Skip to content

Commit 03ce207

Browse files
committed
synterp
1 parent b1d9f61 commit 03ce207

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+4815
-2025
lines changed

.github/workflows/doc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: setup ocaml
2626
uses: avsm/setup-ocaml@v1
2727
with:
28-
ocaml-version: 4.09.1
28+
ocaml-version: 4.10.1
2929

3030
- name: install deps
3131
run: |

.github/workflows/main.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ jobs:
1818
coq_version:
1919
- '8.18'
2020
ocaml_version:
21-
- '4.09-flambda'
22-
- '4.13-flambda'
21+
- '4.14-flambda'
2322
steps:
2423
- uses: actions/checkout@v2
2524
- uses: coq-community/docker-coq-action@v1

Changelog.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
# Changelog
22

3-
## Unreleased - 09/11/2023
3+
## [2.0.0] - Unreleased
4+
5+
Requires Elpi 1.18.1 and Coq 8.18.
6+
7+
This major release accommodates for the separation of parsing from execution
8+
of Coq 8.18 enabling Coq-Elpi programs to be run efficiently (and correctly)
9+
under VSCoq 2.0.
10+
11+
### Documentation
12+
- New section about parsing/execution separation in the [Writing commands in Elpi](https://lpcic.github.io/coq-elpi/tutorial_coq_elpi_command.html) tutorial
13+
14+
### Commands
15+
- New `Elpi *` commands understand the `#[phase]` attribute, see the doc in
16+
the [README](README.md#vernacular-commands) file, and the section
17+
about the [separation of parsing from execution](README.md#separation-of-parsing-from-execution-of-vernacular-commands)
18+
- New `Elpi Export` understands an `As` clause to rename or alias a program when exported
419

520
### API
621
- Change `coq.elpi.add-predicate` now locality can be changed
@@ -13,6 +28,11 @@
1328
- New `coq.ltac.fresh-id` to generate fresh names in the proof context
1429
- New `@no-tc!` attribute supported by `coq.ltac.call-ltac1`
1530
- New `coq.TC.get-inst-prio` returns the `tc-priority` of an instance
31+
- New `synterp-action` datatype
32+
- New `coq.replay-all-missing-synterp-actions`
33+
- New `coq.replay-synterp-action`
34+
- New `coq.next-synterp-action`
35+
- New `coq.synterp-actions` (parsing phase only)
1636

1737
### Apps
1838
- New `tc` app providing an implementation of a type class solver written in elpi.

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,19 @@ doc: $(DOCDEP)
9191

9292
.PHONY: force build all test doc
9393

94-
Makefile.coq Makefile.coq.conf: src/coq_elpi_builtins_HOAS.ml src/coq_elpi_config.ml _CoqProject
94+
Makefile.coq Makefile.coq.conf: src/coq_elpi_builtins_HOAS.ml src/coq_elpi_builtins_arg_HOAS.ml src/coq_elpi_config.ml _CoqProject
9595
@$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq
9696
@$(MAKE) --no-print-directory -f Makefile.coq .merlin
9797
Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test
9898
@$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq
9999
Makefile.examples.coq Makefile.examples.coq.conf: _CoqProject.examples
100100
@$(COQBIN)/coq_makefile -f _CoqProject.examples -o Makefile.examples.coq
101+
src/coq_elpi_builtins_arg_HOAS.ml: elpi/coq-arg-HOAS.elpi Makefile.coq.local
102+
echo "(* Automatically generated from $<, don't edit *)" > $@
103+
echo "(* Regenerate via 'make $@' *)" >> $@
104+
echo "let code = {|" >> $@
105+
cat $< >> $@
106+
echo "|}" >> $@
101107
src/coq_elpi_builtins_HOAS.ml: elpi/coq-HOAS.elpi Makefile.coq.local
102108
echo "(* Automatically generated from $<, don't edit *)" > $@
103109
echo "(* Regenerate via 'make $@' *)" >> $@

Makefile.coq.local

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ install-extra::
1717
df="`$(COQMKFILE) -destination-of theories/elpi.vo $(COQLIBS)`";\
1818
install -m 0644 elpi-builtin.elpi "$(COQLIBINSTALL)/$$df";\
1919
install -m 0644 coq-builtin.elpi "$(COQLIBINSTALL)/$$df";\
20+
install -m 0644 coq-builtin-synterp.elpi "$(COQLIBINSTALL)/$$df";\
21+
install -m 0644 elpi/coq-lib-common.elpi "$(COQLIBINSTALL)/$$df";\
2022
install -m 0644 elpi/coq-lib.elpi "$(COQLIBINSTALL)/$$df";\
2123
install -m 0644 elpi/elpi_elaborator.elpi "$(COQLIBINSTALL)/$$df"
2224

README.md

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ In order to load Coq-Elpi use `From elpi Require Import elpi`.
176176
- `Elpi Db <dbname> <code>` creates a Db (a program that is accumulated into
177177
other programs). `<code>` is the initial contents of the Db, including the
178178
type declaration of its constituting predicates.
179+
It understands the `#[phase]` attribute, see [synterp-vs-interp](README.md#separation-of-parsing-from-execution-of-vernacular-commands).
179180
- `Elpi Program <qname> <code>` lower level primitive letting one crate a
180181
command/tactic with a custom preamble `<code>`.
181182

@@ -186,19 +187,26 @@ In order to load Coq-Elpi use `From elpi Require Import elpi`.
186187
a no op if the Coq version is matched (or not) by the given regular expression.
187188
File names are relative to the directory mapped to `<loadpath>`; if more than
188189
one such directory exists, the `<filename>` must exists only once.
190+
It understands the `#[phase]` attribute, see [synterp-vs-interp](README.md#separation-of-parsing-from-execution-of-vernacular-commands)
189191
- `Elpi Typecheck [<qname>]` typechecks the current program (or `<qname>` if
190192
specified).
193+
It understands the `#[phase]` attribute, see [synterp-vs-interp](README.md#separation-of-parsing-from-execution-of-vernacular-commands)
191194
- `Elpi Debug <string>` sets the variable `<string>`, relevant for conditional
192195
clause compilation (the `:if VARIABLE` clause attribute).
196+
It understands the `#[phase]` attribute, see [synterp-vs-interp](README.md#separation-of-parsing-from-execution-of-vernacular-commands)
193197
- `Elpi Trace [[<start> <stop>] <predicate-filter>*|Off]` enable/disable
194198
tracing, eventually limiting it to a specific range of execution steps or
195199
predicate names.
200+
It understands the `#[phase]` attribute, see [synterp-vs-interp](README.md#separation-of-parsing-from-execution-of-vernacular-commands)
201+
- `Elpi Trace Browser` enable/disable
202+
tracing for Elpi's [trace browser]().
196203
- `Elpi Bound Steps <number>` limits the number of steps an Elpi program can
197204
make.
198205
- `Elpi Print <qname> [<string> <filter>*]` prints the program `<qname>` to an
199206
HTML file named `<qname>.html` and a text file called `<qname>.txt`
200207
(or `<string>` if provided) filtering out clauses whose file or clause-name
201208
matches `<filter>`.
209+
It understands the `#[phase]` attribute, see [synterp-vs-interp](README.md#separation-of-parsing-from-execution-of-vernacular-commands)
202210

203211
where:
204212

@@ -216,6 +224,86 @@ where:
216224

217225
</p></details>
218226

227+
#### Separation of parsing from execution of vernacular commands
228+
229+
<details><summary>(click to expand)</summary>
230+
231+
Since version 8.18 Coq has separate parsing and execution phases,
232+
respectively called synterp and interp.
233+
234+
Since Coq has an extensible grammar the parsing phase is not entirely
235+
performed by the parser: after parsing one sentence Coq evaluates its
236+
synterp action. The synterp actions of a command like `Import A.` are
237+
the subset of its effect which affect parsing, like enabling a notation.
238+
Later, during the execution phase Coq evaluates the its
239+
interp action, which includes effects like putting lemma names in scope or
240+
enables type class instances etc.
241+
242+
Being able to parse an entire document quickly,
243+
without actually executing any sentence, is important for developing reactive
244+
user interfaces, but requires some extra work when defining new commands,
245+
in particular to separate their synterp actions from their interp ones.
246+
Each command defined with Coq-Elpi is split into two programs,
247+
one running during the parsing phase and the other one during the execution
248+
phase.
249+
250+
##### Declaration of synterp actions
251+
252+
Each `Elpi Command` internally declares two programs with the same name.
253+
One to be run while the Coq document is parsed, the synterp-command,
254+
and the other one while it is executed, the interp command.
255+
`Elpi Accumulate`, by default, adds code to the interp-command.
256+
The `#[phase]` attribute can be used to accumulate code to the synterp-command
257+
or to both commands. `Elpi Typecheck` checks both commands.
258+
259+
Each `Elpi Db` internally declares one db, by default for the interp phase.
260+
The `#[phase]` attribute can be used crate a database for the synterp phase,
261+
or for both phases. Note that databases for the two phases are distinct, no
262+
data is shared among them. In particular the `coq.elpi.accumulate*` API exists
263+
in both phases and only acts on data bases for the current phase.
264+
265+
##### The alignment of phases
266+
267+
All synterp actions, i.e. calls to APIs dealing with modules and sections
268+
like begin/end-module or import/export, have to happen at *both* synterp and
269+
interp time and *in the same order*.
270+
271+
In order to do so, the synterp-command may need to communicate data to the
272+
corresponding interp-command. There are two ways for doing so.
273+
274+
The first one is to use, as the main entry points, the following ones:
275+
```
276+
pred main-synterp i:list argument, o:any.
277+
pred main-interp i:list argument, i:any.
278+
```
279+
Unlike `main` the former outputs a datum while the latter receives it in input.
280+
During the synterp phase the API `coq.synterp-actions` lists the actions
281+
performed so far. An excerpt from the [coq-builtin-synterp](coq-builtin-synterp.elpi) file:
282+
```
283+
% Action executed during the parsing phase (aka synterp)
284+
kind synterp-action type.
285+
type begin-module id -> synterp-action.
286+
type end-module modpath -> synterp-action.
287+
```
288+
The synterp-command can output data of that type, but also any other data it
289+
wishes.
290+
291+
The second way to communicate data is implicit, but limited to synterp actions.
292+
During the interp phase commands can use the `coq.next-synterp-action` API to
293+
peek into the list of actions yet to be performed.
294+
Once an action is performed, the API reveals the next one. See also the
295+
related utilities `coq.replay-synterp-action` and
296+
`coq.replay-all-missing-synterp-actions`.
297+
298+
##### Syntax of the `#[phase]` attribute
299+
300+
- `#[phase="ph"]` where `"ph"` can be `"parsing"`,
301+
`"execution"` or `"both"`
302+
- `#[synterp]` is a shorthand for `#[phase="parsing"]`
303+
- `#[interp]` is a shorthand for `#[phase="execution]`
304+
305+
</p></details>
306+
219307
#### Invocation of Elpi code
220308

221309
<details><summary>(click to expand)</summary>
@@ -227,7 +315,8 @@ where:
227315
program passing a possible empty list of arguments and the current goal. This
228316
is how you invoke a tactic.
229317

230-
- `Elpi Export <qname>` makes it possible to invoke command `<qname>` without
318+
- `Elpi Export <qname> [As <other-qname>]` makes it possible to invoke
319+
command `<qname>` (or `<other-qname>` if given) without
231320
the `Elpi` prefix or invoke tactic `<qname>` in the middle of a term just
232321
writing `<qname> args` instead of `ltac:(elpi <qname> args)`. Note that in
233322
the case of tactics, all arguments are considered to be terms.
@@ -327,6 +416,9 @@ Arguments of type `uconstr` are passed raw.
327416

328417
- `Elpi Query [<qname>] <code>` runs `<code>` in the current program (or in
329418
`<qname>` if specified).
419+
- `Elpi Query [<qname>] <synterp-code> <interp-code>` runs
420+
`<synterp-code>` in the current (synterp) program (or in
421+
`<qname>` if specified) and `<interp-code>` in the current program (or `<qname>`).
330422
- `elpi query [<qname>] <string> <argument>*` runs the `<string>` predicate
331423
(that must have the same signature of the default predicate `solve`).
332424

@@ -393,12 +485,13 @@ see [coq-builtin](coq-builtin.elpi).
393485

394486
- [coq-builtin](coq-builtin.elpi) documents the HOAS encoding of Coq terms
395487
and the API to access Coq
488+
- [coq-builtin-synterp](coq-builtin-synterp.elpi) documents APIs to interact with Coq at parsing time
396489
- [elpi-buitin](elpi-builtin.elpi) documents Elpi's standard library, you may
397490
look here for list processing code
398491
- [coq-lib](elpi/coq-lib.elpi) provides some utilities to manipulate Coq terms;
399492
it is an addendum to coq-builtin
400-
- [elpi-command-template](elpi/elpi-command-template.elpi) provides the pre-loaded code for
401-
`Elpi Command`
493+
- [elpi-command-template](elpi/elpi-command-template.elpi) provides the pre-loaded code for `Elpi Command` (execution phase)
494+
- [elpi-command-template-synterp](elpi/elpi-command-template-synterp.elpi) provides the pre-loaded code for `Elpi Command` (parsing phase)
402495
- [elpi-tactic-template](elpi/elpi-tactic-template.elpi) provides the pre-loaded code for `Elpi Tactic`
403496

404497
#### Organization of the repository

_CoqProject

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
# NES
1717
-R apps/NES/theories elpi.apps
18+
-R apps/NES/elpi elpi.apps.NES
1819
-R apps/NES/tests elpi.apps.NES.tests
1920
-R apps/NES/examples elpi.apps.NES.examples
2021

@@ -59,7 +60,10 @@ src/coq_elpi_glob_quotation.mli
5960
src/coq_elpi_arg_HOAS.ml
6061
src/coq_elpi_arg_HOAS.mli
6162
src/coq_elpi_arg_syntax.mlg
63+
src/coq_elpi_builtins_arg_HOAS.ml
6264
src/coq_elpi_builtins_HOAS.ml
65+
src/coq_elpi_builtins_synterp.ml
66+
src/coq_elpi_builtins_synterp.mli
6367
src/coq_elpi_builtins.ml
6468
src/coq_elpi_builtins.mli
6569
src/coq_elpi_config.ml

_CoqProject.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ tests/test_link_order_import2.v
5454
tests/test_link_order_import3.v
5555
tests/test_query_extra_dep.v
5656
tests/test_toposort.v
57+
tests/test_synterp.v

apps/NES/elpi/nes_interp.elpi

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
namespace nes {
2+
3+
% Print a namespace
4+
pred print-path i:list string, i:(gref -> coq.pp -> prop).
5+
print-path Path PP :- std.do! [
6+
std.map {std.findall (ns Path _)} (p\ mp\ p = ns _ mp) MPs,
7+
print.pp-list MPs (print.pp-module Path PP) Out,
8+
coq.say {coq.pp->string Out},
9+
].
10+
11+
namespace print {
12+
13+
pred pp-list i:list A, i:(A -> coq.pp -> prop), o:coq.pp.
14+
pp-list L F Out :- std.do! [
15+
std.map-filter L F PPs,
16+
Out = coq.pp.box (coq.pp.v 0) {std.intersperse (coq.pp.brk 0 0) PPs},
17+
].
18+
19+
kind context type.
20+
type context
21+
list string -> % readable path
22+
int -> % length of full path
23+
(gref -> coq.pp -> prop) ->
24+
context.
25+
26+
% Hides `aux` modules
27+
pred readable-path i:context, i:list string, o:list string.
28+
readable-path (context Prefix N _) FullPath Path :- std.do! [
29+
std.drop N FullPath RelPath,
30+
std.append Prefix RelPath Path,
31+
].
32+
33+
pred module-context i:list string, i:modpath, i:(gref -> coq.pp -> prop), o:context.
34+
module-context Prefix MP PP Ctx :- std.do! [
35+
coq.modpath->path MP FullPath,
36+
Ctx = context Prefix {std.length FullPath} PP,
37+
].
38+
39+
pred submodule-context i:context, i:modpath, o:context.
40+
submodule-context (context _ _ PP as Ctx) MP Ctx' :- std.do! [
41+
coq.modpath->path MP FullPath,
42+
readable-path Ctx FullPath Path,
43+
Ctx' = context Path {std.length FullPath} PP,
44+
].
45+
46+
pred pp-module i:list string, i:(gref -> coq.pp -> prop), i:modpath, o:coq.pp.
47+
pp-module Prefix PP MP Out :- std.do! [
48+
pp-module-items {module-context Prefix MP PP} {coq.env.module MP} Out,
49+
].
50+
51+
pred pp-module-items i:context i:list module-item, o:coq.pp.
52+
pp-module-items Ctx Items Out :-
53+
pp-list Items (pp-module-item Ctx) Out.
54+
55+
pred pp-module-item i:context, i:module-item, o:coq.pp.
56+
pp-module-item (context _ _ PP) (gref GR) Out :- PP GR Out, !.
57+
pp-module-item Ctx (submodule MP Items) Out :- std.do! [
58+
pp-module-items {submodule-context Ctx MP} Items Out,
59+
].
60+
pp-module-item Ctx (module-type MTP) Out :- pp-modtypath Ctx MTP Out.
61+
pp-module-item Ctx (module-type-functor MTP _) Out :- pp-modtypath Ctx MTP Out.
62+
pp-module-item Ctx (module-functor MP _) Out :- pp-modpath Ctx MP Out.
63+
64+
pred pp-path i:context, i:string, i:list string, o:coq.pp.
65+
pp-path Ctx What FullPath Out :- std.do! [
66+
readable-path Ctx FullPath Path,
67+
Out = coq.pp.box coq.pp.h [
68+
coq.pp.str What, coq.pp.spc,
69+
coq.pp.str {std.string.concat "." Path},
70+
],
71+
].
72+
73+
pred pp-modtypath i:context, i:modtypath, o:coq.pp.
74+
pp-modtypath Ctx MTP Out :- std.do! [
75+
pp-path Ctx "Module Type" {coq.modtypath->path MTP} Out,
76+
].
77+
78+
pred pp-modpath i:context, i:modpath, o:coq.pp.
79+
pp-modpath Ctx MP Out :- std.do! [
80+
pp-path Ctx "Module" {coq.modpath->path MP} Out,
81+
].
82+
}
83+
84+
85+
}

0 commit comments

Comments
 (0)