Skip to content

Commit f911a33

Browse files
authored
Merge pull request #597 from rlepigre/br/derive-synterp
Add synterp phase support for derive plugins.
2 parents 17a0f00 + a777090 commit f911a33

35 files changed

+556
-132
lines changed

apps/derive/README.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,47 @@ given an inductive type declaration.
77

88
```coq
99
From elpi.apps Require Import derive.std.
10-
11-
derive Inductive peano := Zero | Succ (p : peano).
1210
13-
Print peano.
14-
(* Notation peano := peano.peano *)
11+
#[module] derive Inductive peano := Zero | Succ (p : peano).
12+
1513
Print peano.peano.
16-
(* Inductive peano : Type := Zero : peano | Succ : peano -> peano *)
14+
(* Inductive peano : Set := Zero : peano | Succ : peano -> peano. *)
1715
1816
Eval compute in peano.eqb Zero (Succ Zero).
1917
(* = false : bool *)
2018
2119
About peano.eqb_OK.
2220
(*
23-
peano.eqb_OK : forall x1 x2 : peano, Bool.reflect (x1 = x2) (peano.eqb x1 x2)
21+
peano.eqb_OK : forall x1 x2 : peano, reflect (x1 = x2) (peano.eqb x1 x2)
2422
2523
peano.eqb_OK is not universe polymorphic
2624
Arguments peano.eqb_OK x1 x2
2725
peano.eqb_OK is opaque
26+
Expands to: Constant elpi.apps.derive.examples.readme.peano.eqb_OK
2827
*)
2928
```
3029

31-
See also [examples/usage.v](examples/usage.v)
30+
See also [examples/usage.v](examples/usage.v) and [tests/test_readme.v](tests/test_readme.v).
3231

3332
:warning: The line `From elpi.apps Require Import derive.std.` sets globally
3433
`Uniform Inductive Parameters`.
3534
See the [documentation of that option in the Coq reference manual](https://coq.inria.fr/refman/language/core/inductive.html#coq:flag.Uniform-Inductive-Parameters).
3635

36+
## Usage and attributes
37+
38+
Using `derive Inductive ty := ...` produces the inductive `ty`, together with
39+
derivations, all in the current scope. The `#[module=<string>]` attriute can
40+
be used to specify that the inductive and the derivations should be wrapped
41+
in a module of the given name (the name of the inductive is used if no name
42+
is specified).
43+
44+
When a wrapper module is generated, an alias (i.e., a notation) is generated
45+
for the inductive to be accessible with its name, outside of the module scope.
46+
This behaviour can be disabled by using the `#[no_alias]` boolean attribute.
47+
48+
The `#[prefix=<string>]` attribute can be used to specify a prefix for all the
49+
derived definitions/lemmas.
50+
3751
## Documentation
3852

3953
Elpi's `derive` app is a little framework to register derivations.

apps/derive/_CoqProject.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
-R tests elpi.apps.derive.tests
77
-R examples elpi.apps.derive.examples
88

9+
tests/test_readme.v
910
tests/test_derive_stdlib.v
1011
tests/test_bcongr.v
1112
tests/test_derive.v

apps/derive/elpi/derive.elpi

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -89,53 +89,84 @@ pred indt-or-const i:gref.
8989
indt-or-const (indt _).
9090
indt-or-const (const _).
9191

92-
pred main i:gref, i:bool, o:list prop.
93-
main T P CL :- get-option "recursive" tt, !,
94-
coq.env.dependencies T _ AllDeps,
92+
pred main i:gref, o:list prop.
93+
main GR CL :- get-option "module" M, !,
94+
if (M = "") (coq.gref->id GR Mod) (Mod = M),
95+
if-verbose (coq.say "Starting module" Mod),
96+
coq.env.begin-module Mod none,
97+
main-derive GR tt CL,
98+
coq.env.end-module _.
99+
main GR CL :-
100+
main-derive GR ff CL.
101+
102+
pred main-derive i:gref, i:bool, o:list prop.
103+
main-derive GR InModule CL :- get-option "recursive" tt, !,
104+
coq.env.dependencies GR _ AllDeps,
95105
coq.gref.set.elements AllDeps AllDepsL,
96106
std.filter AllDepsL indt-or-const Deps,
97-
main.aux Deps [] CL1,
98-
CL1 => main1 T P CL2,
107+
main.aux InModule Deps [] CL1,
108+
CL1 => main1 GR InModule CL2,
99109
std.append CL1 CL2 CL.
100-
pred main.aux i:list gref, i:list prop, o:list prop.
101-
main.aux [] X X.
102-
main.aux [T|TS] Acc CL :-
103-
(pi X\get-option "only" X :- !, fail) => Acc => main T tt CL1,
104-
main.aux TS {std.append CL1 Acc} CL.
105-
106-
main T P CL :- main1 T P CL.
107-
110+
main-derive GR InModule CL :- main1 GR InModule CL.
111+
112+
pred main.aux i:bool, i:list gref, i:list prop, o:list prop.
113+
main.aux _ [] X X.
114+
main.aux InModule [GR|GRS] Acc CL :-
115+
(pi X\get-option "only" X :- !, fail) => Acc => main-derive GR InModule CL1,
116+
main.aux InModule GRS {std.append CL1 Acc} CL.
117+
118+
pred validate-recursive i:prop, o:derive.
119+
validate-recursive (derivation _ _ tt _) _ :- get-option "recursive" tt,
120+
coq.error "Synterp actions not supported in recursive derive.".
121+
validate-recursive (derivation _ _ _ R) R.
108122
pred main1 i:gref, i:bool, o:list prop.
109-
main1 T P CL :-
110-
if (P = tt) (Prefix is {coq.gref->id T} ^ "_") (Prefix = ""),
111-
std.findall (derivation T Prefix _) L,
123+
main1 GR InModule CL :-
124+
if (get-option "prefix" PFX)
125+
(Prefix = PFX)
126+
(if (InModule is ff) (Prefix is {coq.gref->id GR} ^ "_") (Prefix = "")),
127+
std.findall (derivation GR Prefix _ _) L,
112128
if (L = [])
113129
(coq.error "no derivation found, did you Import derive.std?")
114130
true,
115-
std.map L (x\r\ x = derivation _ _ r) DL,
116-
validate-only T DL,
131+
std.map L validate-recursive DL,
132+
validate-only GR DL,
117133
toposort DL SortedDL,
118-
chain T SortedDL CL.
119-
120-
pred decl+main i:indt-decl.
121-
decl+main DS :- std.do! [
122-
indt-decl-name DS ModName,
123-
if-verbose (coq.say "Starting module" ModName),
124-
coq.env.begin-module ModName none,
134+
chain GR SortedDL CL.
135+
136+
pred decl+main i:string, i:indt-decl.
137+
decl+main TypeName DS :- std.do! [
138+
if (get-option "module" M)
139+
(if (M = "") (ModName = TypeName) (ModName = M), HasModule = tt)
140+
(HasModule = ff),
141+
if (HasModule = tt)
142+
(if-verbose (coq.say "Starting module" ModName),
143+
coq.env.begin-module ModName none)
144+
true,
125145
std.assert-ok! (coq.elaborate-indt-decl-skeleton DS D) "Inductive type declaration illtyped",
126146
if-verbose (coq.say "Declaring inductive" D),
127147
coq.env.add-indt D I,
128148
if-verbose (coq.say "Deriving"),
129-
main (indt I) ff CL,
149+
main-derive (indt I) HasModule CL,
130150
if-verbose (coq.say "Done"),
131-
coq.env.end-module _,
151+
if (HasModule = tt)
152+
(coq.env.end-module _,
153+
decl+main.post TypeName I DS CL)
154+
check-no-no-alias
155+
].
156+
157+
pred check-no-no-alias.
158+
check-no-no-alias :- get-option "no_alias" tt, !,
159+
coq.error "The no_alias attribute only has an effect when a wrapper module is generated.".
160+
check-no-no-alias.
132161

162+
pred decl+main.post i:string, i:inductive, i:indt-decl, o:list prop.
163+
decl+main.post TypeName I DS CL :- std.do! [
133164
coq.env.indt I _ _ _ _ KS _,
134165
std.map KS (k\r\ r = indc k) KGRS,
135166
std.map KGRS coq.gref->id KNS,
136167
std.map KGRS (gr\r\ r = global gr) KTS,
137168

138-
std.forall2 [ModName|KNS] [global (indt I)|KTS] short-alias,
169+
std.forall2 [TypeName|KNS] [global (indt I)|KTS] short-alias,
139170

140171
coq.indt-decl->implicits DS IndImpls KsImpls,
141172
if (coq.any-implicit? IndImpls)
@@ -151,12 +182,7 @@ decl+main DS :- std.do! [
151182
].
152183

153184
pred short-alias i:id, i:term.
185+
short-alias _ _ :- get-option "no_alias" tt, !, true.
154186
short-alias ID T :- @global! => coq.notation.add-abbreviation ID 0 T ff _.
155187

156-
pred indt-decl-name i:indt-decl, o:string.
157-
indt-decl-name (parameter _ _ _ Decl) Name :-
158-
pi x\ indt-decl-name (Decl x) Name.
159-
indt-decl-name (inductive Name _ _ _) Name.
160-
indt-decl-name (record Name _ _ _) Name.
161-
162188
}

apps/derive/elpi/derive_hook.elpi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* license: GNU Lesser General Public License Version 2.1 or later */
33
/* ------------------------------------------------------------------------- */
44

5-
pred derivation i:gref, i:string, o:derive.
5+
pred derivation i:gref, i:string, o:bool, o:derive.
66
pred export i:modpath.
77
pred dep1 o:string, o:string.
88
kind derive type.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Entry point for all derivations */
2+
/* license: GNU Lesser General Public License Version 2.1 or later */
3+
/* ------------------------------------------------------------------------- */
4+
5+
namespace derive {
6+
7+
pred dep o:string, o:string.
8+
dep X Y :- dep1 X Y.
9+
dep X Y :- dep1 X Z, dep Z Y.
10+
11+
pred selected i:string.
12+
selected Name :- get-option "only" Map, !,
13+
Map => (get-option Name _; (get-option X _, dep X Name)).
14+
selected _.
15+
16+
pred chain i:string, i:list derive.
17+
chain _ [].
18+
chain T [derive Name _ _|FS] :- not(selected Name), !,
19+
chain T FS.
20+
chain T [derive _ _ AlreadyDone|FS] :- (pi x\ stop x :- !, fail) => AlreadyDone, !,
21+
chain T FS.
22+
chain T [derive _ F _|FS] :- get-option "only" _, !, % request this one
23+
F _,
24+
chain T FS.
25+
chain T [derive _ F _|FS] :- % all are selected, we can fail
26+
(pi x\ stop x :- !, fail) => F _, !,
27+
chain T FS.
28+
chain T [derive _ _ _|FS] :-
29+
chain T FS.
30+
31+
pred toposort i:list derive, o:list derive.
32+
toposort L SL :-
33+
std.findall (dep1 _ _) Deps,
34+
topo L Deps SL.
35+
36+
pred std.partition i:list A, i:(A -> prop), o:list A, o:list A.
37+
std.partition [] _ [] [].
38+
std.partition [X|XS] P [X|R] L :- P X, !, std.partition XS P R L.
39+
std.partition [X|XS] P R [X|L] :- std.partition XS P R L.
40+
41+
pred not-a-src i:list prop, i:derive.
42+
not-a-src Deps (derive A _ _) :- not(std.mem! Deps (dep1 A _)).
43+
44+
pred tgt-is-not-in i:list derive, i:prop.
45+
tgt-is-not-in [] _.
46+
tgt-is-not-in [derive Tgt _ _|_] (dep1 _ Tgt) :- !, fail.
47+
tgt-is-not-in [_|L] D :- tgt-is-not-in L D.
48+
49+
pred topo i:list derive, i:list prop, o:list derive.
50+
topo [] _ [] :- !.
51+
topo L Deps SL :-
52+
std.partition L (not-a-src Deps) LNoDeps Other,
53+
if (LNoDeps = []) (coq.error "derive: no topological order:" L Deps) true,
54+
std.filter Deps (tgt-is-not-in LNoDeps) NewDeps,
55+
topo Other NewDeps SOther,
56+
std.append LNoDeps SOther SL.
57+
58+
pred main i:string.
59+
main TypeName :- get-option "module" M, !,
60+
if (M = "") (Mod = TypeName) (Mod = M),
61+
coq.env.begin-module Mod none,
62+
main-derive TypeName tt,
63+
coq.env.end-module _.
64+
main TypeName :-
65+
main-derive TypeName ff.
66+
67+
pred main-derive i:string, i:bool.
68+
main-derive TypeName InModule :- main1 TypeName InModule.
69+
70+
pred main1 i:string, i:bool.
71+
main1 TypeName InModule :-
72+
if (get-option "prefix" PFX)
73+
(Prefix = PFX)
74+
(if (InModule is ff) (Prefix is TypeName ^ "_") (Prefix = "")),
75+
std.findall (derivation TypeName Prefix _) L,
76+
std.map L (x\r\ x = derivation _ _ r) DL,
77+
toposort DL SortedDL,
78+
chain TypeName SortedDL.
79+
80+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* Entry point for derive extensions */
2+
/* license: GNU Lesser General Public License Version 2.1 or later */
3+
/* ------------------------------------------------------------------------- */
4+
5+
pred derivation i:string, i:string, o:derive.
6+
pred export i:modpath.
7+
pred dep1 o:string, o:string.
8+
kind derive type.
9+
type derive string -> (list prop -> prop) -> prop -> derive.

apps/derive/examples/readme.v

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
1-
(* README *)
1+
(* README *)
22
From elpi.apps Require Import derive.std.
3-
4-
derive Inductive peano := Zero | Succ (p : peano).
53

6-
(* Bug 8.16: About peano.peano.*)
7-
(* Notation peano := peano.peano *)
4+
#[module] derive Inductive peano := Zero | Succ (p : peano).
85

96
Print peano.peano.
10-
(* Inductive peano : Type := Zero : peano | Succ : peano -> peano *)
7+
(* Inductive peano : Set := Zero : peano | Succ : peano -> peano. *)
118

129
Eval compute in peano.eqb Zero (Succ Zero).
1310
(* = false : bool *)
1411

1512
About peano.eqb_OK.
1613
(*
17-
peano.eqb_OK : forall x1 x2 : peano, Bool.reflect (x1 = x2) (peano.eqb x1 x2)
14+
peano.eqb_OK : forall x1 x2 : peano, reflect (x1 = x2) (peano.eqb x1 x2)
1815
1916
peano.eqb_OK is not universe polymorphic
2017
Arguments peano.eqb_OK x1 x2
2118
peano.eqb_OK is opaque
19+
Expands to: Constant elpi.apps.derive.examples.readme.peano.eqb_OK
2220
*)
2321

2422
#[verbose] derive Nat.add.
2523
Check is_add. (*
2624
: forall n : nat, is_nat n ->
2725
forall m : nat, is_nat m ->
2826
is_nat (n + m)
29-
*)
27+
*)

apps/derive/examples/usage.v

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ From elpi.apps Require Import derive.std.
77
Set Uniform Inductive Parameters.
88

99
(** The best way to call derive is to prefix an Inductive declaration. *)
10-
derive
10+
#[module] derive
1111
Inductive tickle A := stop | more : A -> tickle -> tickle.
1212

1313
(** The command is elaborated to something like:
@@ -40,7 +40,7 @@ Check tickle.tickle_R : (* relator (binary parametricity translation) *)
4040
(** This is a tricky case, since you need a good induction principle for the
4141
nested occurrence of tickle. #[verbose] prints all the derivations being
4242
run *)
43-
#[verbose] derive
43+
#[verbose,module] derive
4444
Inductive rtree A := Leaf (a : A) | Node (l : tickle rtree).
4545

4646
Check rtree.induction : (* this is the key *)
@@ -50,7 +50,7 @@ Check rtree.induction : (* this is the key *)
5050
forall x, rtree.is_rtree A PA x -> P x.
5151

5252
(** You can also select which derivations you like *)
53-
#[verbose, only(lens_laws, eqb)] derive
53+
#[verbose, only(lens_laws, eqb), module] derive
5454
Record Box A := { contents : A; tag : nat }.
5555

5656
Check Box.eqb :

apps/derive/tests/test_derive.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Check XXX.rtree_constructP : forall (A:Type) (l:rtree A), XXX.rtree_construct A
133133
Check XXX.rtree_eqb : forall (A:Type), (A -> A -> bool) -> rtree A -> rtree A -> bool.
134134
(* bug #270 *)
135135

136-
derive
136+
#[module] derive
137137
Inductive triv : Coverage.unit -> Prop :=
138138
| one t : triv t | more x : triv x.
139139

@@ -150,7 +150,7 @@ Inductive RoseTree : Type :=
150150

151151
Elpi derive.param1 is_list.
152152

153-
derive
153+
#[module] derive
154154
Inductive Pred : RoseTree -> Type :=
155155
| Pred_ctr branches :
156156
is_list _ Pred branches ->

0 commit comments

Comments
 (0)