diff --git a/.gitignore b/.gitignore index c5c7a53ba..1f6f027cf 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ apps/coercion/src/coq_elpi_coercion_hook.ml .filestoinstall apps/tc/src/coq_elpi_tc_hook.ml apps/cs/src/coq_elpi_cs_hook.ml +_build diff --git a/.nix/coq-overlays/coq-elpi/default.nix b/.nix/coq-overlays/coq-elpi/default.nix index 90f8e03ea..9262e1f82 100644 --- a/.nix/coq-overlays/coq-elpi/default.nix +++ b/.nix/coq-overlays/coq-elpi/default.nix @@ -64,7 +64,7 @@ in mkCoqDerivation { buildFlags = [ "OCAMLWARN=" ]; mlPlugin = true; - propagatedBuildInputs = [ coq.ocamlPackages.findlib elpi ]; + propagatedBuildInputs = [ coq.ocamlPackages.dune_3 elpi ]; meta = { description = "Coq plugin embedding ELPI."; diff --git a/Makefile b/Makefile index 75b3679f8..fccf33f64 100644 --- a/Makefile +++ b/Makefile @@ -1,156 +1,58 @@ - -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -# detection of elpi -ifeq "$(ELPIDIR)" "" -ELPIDIR=$(shell ocamlfind query elpi 2>/dev/null) -endif -ifeq "$(ELPIDIR)" "" -$(error Elpi not found, make sure it is installed in your PATH or set ELPIDIR) -endif -export ELPIDIR - -DEPS=$(ELPIDIR)/elpi.cmxa $(ELPIDIR)/elpi.cma - -APPS=$(addprefix apps/, derive eltac NES locker coercion cs tc) - -ifeq "$(COQ_ELPI_ALREADY_INSTALLED)" "" -DOCDEP=build -else -DOCDEP= -endif - -ifndef DOCDIR -DOCDIR=$(shell $(COQBIN)/coqc -where)/../../share/doc/coq-elpi -endif - -ifndef COQDOCINSTALL -COQDOCINSTALL=$(DESTDIR)$(DOCDIR) -endif - - all: - $(MAKE) build-core - $(MAKE) test-core - $(MAKE) examples - $(MAKE) build-apps - $(MAKE) test-apps + @dune build +.PHONY: all -build-core: Makefile.coq $(DEPS) - @echo "########################## building plugin ##########################" - @if [ -x $(COQBIN)/coqtop.byte ]; then \ - $(MAKE) --no-print-directory -f Makefile.coq bytefiles; \ - fi - @$(MAKE) --no-print-directory -f Makefile.coq opt +build-core: + @dune build theories +.PHONY: build-core -build-apps: build-core - @echo "########################## building APPS ############################" - @$(foreach app,$(APPS),$(MAKE) -C $(app) build &&) true +build-apps: + @dune build $$(find apps -type d -name theories) +.PHONY: build-apps -build: build-core build-apps +build: + @dune build @install +.PHONY: build -test-core: Makefile.test.coq $(DEPS) build-core - @echo "########################## testing plugin ##########################" - @$(MAKE) --no-print-directory -f Makefile.test.coq +test-core: + @dune runtest tests +.PHONY: test-core -test-apps: build-apps - @echo "########################## testing APPS ############################" - @$(foreach app,$(APPS),$(MAKE) -C $(app) test &&) true +test-apps: + @dune build $$(find apps -type d -name tests) +.PHONY: test-apps -test: test-core test-apps +test: + @dune runtest + @dune build $$(find apps -type d -name tests) +.PHONY: test -examples: Makefile.examples.coq $(DEPS) build-core - @echo "############################ examples ############################" - @$(MAKE) --no-print-directory -f Makefile.examples.coq +examples: + @dune build examples +.PHONY: examples -doc: $(DOCDEP) +doc: build @echo "########################## generating doc ##########################" @mkdir -p doc @$(foreach tut,$(wildcard examples/tutorial*$(ONLY)*.v),\ - echo ALECTRYON $(tut) && ./etc/alectryon_elpi.py \ + echo ALECTRYON $(tut) && OCAMLPATH=$(shell pwd)/_build/install/default/lib ./etc/alectryon_elpi.py \ --frontend coq+rst \ --output-directory doc \ --pygments-style vs \ - -R theories elpi -Q src elpi \ + -R $(shell pwd)/_build/install/default/lib/coq/user-contrib/elpi elpi \ $(tut) &&) true @cp stlc.html doc/ @cp etc/tracer.png doc/ -.merlin: force - @rm -f .merlin - @$(MAKE) --no-print-directory -f Makefile.coq $@ - -.PHONY: force build all test doc - -Makefile.coq Makefile.coq.conf: src/coq_elpi_builtins_HOAS.ml src/coq_elpi_builtins_arg_HOAS.ml src/coq_elpi_config.ml _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq -Makefile.examples.coq Makefile.examples.coq.conf: _CoqProject.examples - @$(COQBIN)/coq_makefile -f _CoqProject.examples -o Makefile.examples.coq -src/coq_elpi_builtins_arg_HOAS.ml: elpi/coq-arg-HOAS.elpi Makefile.coq.local - echo "(* Automatically generated from $<, don't edit *)" > $@ - echo "(* Regenerate via 'make $@' *)" >> $@ - echo "let code = {|" >> $@ - cat $< >> $@ - echo "|}" >> $@ -src/coq_elpi_builtins_HOAS.ml: elpi/coq-HOAS.elpi Makefile.coq.local - echo "(* Automatically generated from $<, don't edit *)" > $@ - echo "(* Regenerate via 'make $@' *)" >> $@ - echo "let code = {|" >> $@ - cat $< >> $@ - echo "|}" >> $@ - -src/coq_elpi_config.ml: - echo "let elpi_dir = \"$(abspath $(ELPIDIR))\";;" > $@ - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - @$(foreach app,$(APPS),$(MAKE) -C $(app) $@ &&) true - -include Makefile.coq.conf -V_FILES_TO_INSTALL := \ - $(filter-out theories/wip/%.v,\ - $(COQMF_VFILES)) +clean: + @dune clean +.PHONY: clean install: - @echo "########################## installing plugin ############################" - @$(MAKE) -f Makefile.coq $@ VFILES="$(V_FILES_TO_INSTALL)" - @if [ -x $(COQBIN)/coqtop.byte ]; then \ - $(MAKE) -f Makefile.coq $@-byte VFILES="$(V_FILES_TO_INSTALL)"; \ - fi - -cp etc/coq-elpi.lang $(COQMF_COQLIB)/ide/ - @echo "########################## installing APPS ############################" - @$(foreach app,$(APPS),$(MAKE) -C $(app) $@ &&) true - @echo "########################## installing doc ############################" - -mkdir -p $(COQDOCINSTALL) - -cp doc/* $(COQDOCINSTALL) - @echo "########################## installed ############################" - - -# compile just one file -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build-core Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build-core Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -SPACE=$(XXX) $(YYY) -apps/%.vo: force - @$(MAKE) -C apps/$(word 1,$(subst /, ,$*)) \ - $(subst $(SPACE),/,$(wordlist 2,99,$(subst /, ,$*))).vo + @dune build -p coq-elpi + @dune install coq-elpi +.PHONY: install nix: - nix-shell --arg do-nothing true --run "updateNixToolBox & genNixActions" \ No newline at end of file + nix-shell --arg do-nothing true --run "updateNixToolBox & genNixActions" +.PHONY: nix diff --git a/Makefile.coq.local b/Makefile.coq.local deleted file mode 100644 index 3d9bd6da4..000000000 --- a/Makefile.coq.local +++ /dev/null @@ -1,24 +0,0 @@ -CAMLPKGS+= -package elpi,stdlib-shims -CAMLFLAGS+= -bin-annot -g -OCAMLWARN+=-warn-error -32 -COQEXTRAFLAGS=-bt - -theories/elpi.vo: $(wildcard elpi/*.elpi) - - -merlin-hook:: - echo "S $(abspath $(ELPIDIR))" >> .merlin - echo "B $(abspath $(ELPIDIR))" >> .merlin - if [ "$(ELPIDIR)" != "elpi/findlib/elpi" ]; then\ - echo "PKG elpi" >> .merlin;\ - fi - -install-extra:: - df="`$(COQMKFILE) -destination-of theories/elpi.vo $(COQLIBS)`";\ - install -m 0644 elpi-builtin.elpi "$(COQLIBINSTALL)/$$df";\ - install -m 0644 coq-builtin.elpi "$(COQLIBINSTALL)/$$df";\ - install -m 0644 coq-builtin-synterp.elpi "$(COQLIBINSTALL)/$$df";\ - install -m 0644 elpi/coq-lib-common.elpi "$(COQLIBINSTALL)/$$df";\ - install -m 0644 elpi/coq-lib.elpi "$(COQLIBINSTALL)/$$df";\ - install -m 0644 elpi/elpi_elaborator.elpi "$(COQLIBINSTALL)/$$df" - diff --git a/Makefile.release b/Makefile.release deleted file mode 100644 index 9e6789ee5..000000000 --- a/Makefile.release +++ /dev/null @@ -1,14 +0,0 @@ -OPAM_SUITE=released -TAG=$(shell git tag --sort=-v:refname|head -1) - -release: - echo "Publishing tag $(TAG) in suite $(OPAM_SUITE)" - echo "Hit ^C to stop, or type options (eg -n fro dry run) and return to continue:";\ - read OPTS;\ - TAG=$(TAG);\ - opam-publish --tag=$(TAG) --packages-directory=$(OPAM_SUITE)/packages \ - --repo=coq/opam --no-browser -v $${TAG##v} $$OPTS \ - https://github.com/LPCIC/coq-elpi/releases/download/$$TAG/coq-elpi-$${TAG##v}.tar.gz - -release-rc: OPAM_SUITE=extra-dev -release-rc: release diff --git a/Makefile.test.coq.local b/Makefile.test.coq.local deleted file mode 100644 index f3c63da85..000000000 --- a/Makefile.test.coq.local +++ /dev/null @@ -1,32 +0,0 @@ -tests/test_cache_async.vo: COQEXTRAFLAGS=-async-proofs on - -tests/test_COQ_ELPI_ATTRIBUTES.vo: export COQ_ELPI_ATTRIBUTES=test=yes,str="some-string" - -define test_link - @F="$(1)";\ - L1=`grep -n '^p 7\.' $$F | cut -d : -f 1`;\ - L2=`grep -n '^p 2\.' $$F | cut -d : -f 1`;\ - [ "$$L1" -gt "$$L2" ] || (echo "wrong link order in file $$F"; exit 1);\ - for i in `seq 1 10`; do\ - N=`grep "^p $$i\\\\." $$F | wc -l`;\ - [ "$$N" = "1" ] || (echo "wrong linking: rule p $$i occurs $$N in file $$F"; exit 1);\ - done;\ - true -endef - -post-all:: tests/test_glob.glob - @echo "test coqdoc hyperlinks" - @mkdir -p tests/test_glob/ - @N=`coqdoc -d tests/test_glob -R tests elpi.tests tests/test_glob.v 2>&1 | grep -i warning | wc -l`;\ - test $$N = 0 - @echo "test link order" - @diff -u tests/test_link_order1.txt tests/test_link_order2.txt - @diff -u tests/test_link_order1.txt tests/test_link_order3.txt - @diff -u tests/test_link_order1.txt tests/test_link_order4.txt - @diff -u tests/test_link_order1.txt tests/test_link_order5.txt - @diff -u tests/test_link_order1.txt tests/test_link_order6.txt - @diff -u tests/test_link_order1.txt tests/test_link_order7.txt - @diff -u tests/test_link_order1.txt tests/test_link_order8.txt - @diff -u tests/test_link_order1.txt tests/test_link_order9.txt - $(call test_link, tests/test_link_order1.txt) - @diff -u tests/test_link_order_import3.ref tests/test_link_order_import3.txt \ No newline at end of file diff --git a/_CoqProject b/_CoqProject index 29a5f0cb1..25bd9f59d 100644 --- a/_CoqProject +++ b/_CoqProject @@ -1,77 +1,126 @@ -arg -w -arg +elpi.deprecated --R theories elpi --Q examples elpi.examples --Q tests elpi.tests --Q src elpi --Q apps/derive/tests elpi.apps.derive.tests --Q tests elpi.tests --Q elpi elpi - -# Derive --R apps/derive/theories elpi.apps --R apps/derive/tests elpi.apps.derive.tests --R apps/derive/examples elpi.apps.derive.examples - -# NES --R apps/NES/theories elpi.apps --R apps/NES/elpi elpi.apps.NES --R apps/NES/tests elpi.apps.NES.tests --R apps/NES/examples elpi.apps.NES.examples - -# Eltac --R apps/eltac/theories elpi.apps.eltac --R apps/eltac/tests elpi.apps.eltac.tests --R apps/eltac/examples elpi.apps.eltac.examples +# Plugins. -# Coercion --R apps/coercion/theories elpi.apps.coercion --R apps/coercion/tests elpi.apps.tc.coercion --I apps/coercion/src +-I _build/install/default/lib -# CS --R apps/cs/theories elpi.apps.cs --R apps/cs/tests elpi.apps.tc.cs --I apps/cs/src +# Theories -# Type classes --R apps/tc/theories elpi.apps.tc --R apps/tc/tests elpi.apps.tc.tests --R apps/tc/elpi elpi.apps.tc --I apps/tc/src - -# Coq-elpi -theories/elpi.v -theories/wip/memoization.v - --I src - -src/META.coq-elpi +-Q theories elpi +-Q _build/default/theories elpi +-Q elpi elpi_elpi +-Q _build/default/elpi elpi_elpi +-Q examples elpi.examples +-Q _build/default/examples elpi.examples -src/coq_elpi_graph.mli -src/coq_elpi_graph.ml -src/coq_elpi_vernacular_syntax.mlg -src/coq_elpi_vernacular.ml -src/coq_elpi_vernacular.mli -src/coq_elpi_programs.ml -src/coq_elpi_programs.mli -src/coq_elpi_utils.mli -src/coq_elpi_utils.ml -src/coq_elpi_HOAS.ml -src/coq_elpi_HOAS.mli -src/coq_elpi_name_quotation.ml -src/coq_elpi_glob_quotation.ml -src/coq_elpi_glob_quotation.mli -src/coq_elpi_arg_HOAS.ml -src/coq_elpi_arg_HOAS.mli -src/coq_elpi_arg_syntax.mlg -src/coq_elpi_builtins_arg_HOAS.ml -src/coq_elpi_builtins_HOAS.ml -src/coq_elpi_builtins_synterp.ml -src/coq_elpi_builtins_synterp.mli -src/coq_elpi_builtins.ml -src/coq_elpi_builtins.mli -src/coq_elpi_config.ml +-Q apps/coercion/tests elpi.apps.coercion.tests +-Q _build/default/apps/coercion/tests elpi.apps.coercion.tests +-Q apps/coercion/theories elpi.apps.coercion +-Q _build/default/apps/coercion/theories elpi.apps.coercion +-Q apps/cs/tests elpi.apps.cs.tests +-Q _build/default/apps/cs/tests elpi.apps.cs.tests +-Q apps/cs/theories elpi.apps.cs +-Q _build/default/apps/cs/theories elpi.apps.cs +-Q apps/derive/elpi elpi.apps.derive.elpi +-Q _build/default/apps/derive/elpi elpi.apps.derive.elpi +-Q apps/derive/examples elpi.apps.derive.examples +-Q _build/default/apps/derive/examples elpi.apps.derive.examples +-Q apps/derive/tests elpi.apps.derive.tests +-Q _build/default/apps/derive/tests elpi.apps.derive.tests +-Q apps/derive/theories elpi.apps.derive +-Q _build/default/apps/derive/theories elpi.apps.derive +-Q apps/derive/theories/derive elpi.apps.derive.derive +-Q _build/default/apps/derive/theories/derive elpi.apps.derive.derive +-Q apps/eltac/examples elpi.apps.eltac.examples +-Q _build/default/apps/eltac/examples elpi.apps.eltac.examples +-Q apps/eltac/tests elpi.apps.eltac.tests +-Q _build/default/apps/eltac/tests elpi.apps.eltac.tests +-Q apps/eltac/theories elpi.apps.eltac +-Q _build/default/apps/eltac/theories elpi.apps.eltac +-Q apps/locker/elpi elpi.apps.locker.elpi +-Q _build/default/apps/locker/elpi elpi.apps.locker.elpi +-Q apps/locker/tests elpi.apps.locker.tests +-Q _build/default/apps/locker/tests elpi.apps.locker.tests +-Q apps/locker/theories elpi.apps.locker +-Q _build/default/apps/locker/theories elpi.apps.locker +-Q apps/NES/elpi elpi.apps.NES.elpi +-Q _build/default/apps/NES/elpi elpi.apps.NES.elpi +-Q apps/NES/examples elpi.apps.NES.examples +-Q _build/default/apps/NES/examples elpi.apps.NES.examples +-Q apps/NES/tests elpi.apps.NES.tests +-Q _build/default/apps/NES/tests elpi.apps.NES.tests +-Q apps/NES/theories elpi.apps.NES +-Q _build/default/apps/NES/theories elpi.apps.NES +-Q apps/tc/elpi elpi.apps.tc.elpi +-Q _build/default/apps/tc/elpi elpi.apps.tc.elpi +-Q apps/tc/examples elpi.apps.tc.examples +-Q _build/default/apps/tc/examples elpi.apps.tc.examples +-Q apps/tc/tests elpi.apps.tc.tests +-Q _build/default/apps/tc/tests elpi.apps.tc.tests +-Q apps/tc/theories elpi.apps.tc +-Q _build/default/apps/tc/theories elpi.apps.tc -src/elpi_plugin.mlpack +# Cram tests. +-Q tests/link_order5.t elpi.test +-Q tests/checker.t elpi.test +-Q tests/query_extra_dep.t elpi.test +-Q tests/libobject_C.t elpi.test +-Q tests/link_order3.t elpi.test +-Q tests/ltac3.t elpi.test +-Q tests/synterp.t elpi.test +-Q tests/link_order6.t elpi.test +-Q tests/API2.t elpi.test +-Q tests/glob.t elpi.test +-Q tests/require_bad_order.t elpi.test +-Q tests/API_arguments.t elpi.test +-Q tests/link_order9.t elpi.test +-Q tests/API_typecheck.t elpi.test +-Q tests/link_order7.t elpi.test +-Q tests/libobject_A.t elpi.test +-Q tests/libobject_B.t elpi.test +-Q tests/vernacular1.t elpi.test +-Q tests/API_section.t elpi.test +-Q tests/tactic.t elpi.test +-Q tests/link_perf.t elpi.test +-Q tests/API_elaborate.t elpi.test +-Q tests/link_order_import3.t elpi.test +-Q tests/COQ_ELPI_ATTRIBUTES.t elpi.test +-Q tests/elaborator.t elpi.test +-Q tests/HOAS.t elpi.test +-Q tests/API_notations.t elpi.test +-Q tests/arg_HOAS.t elpi.test +-Q tests/link_order_import2.t elpi.test +-Q tests/link_order2.t elpi.test +-Q tests/link_order8.t elpi.test +-Q tests/cache_async.t elpi.test +-Q tests/API_new_pred.t elpi.test +-Q tests/quotation.t elpi.test +-Q tests/ltac2.t elpi.test +-Q tests/perf_calls.t elpi.test +-Q tests/link_order1.t elpi.test +-Q tests/link_order_import0.t elpi.test +-Q tests/ltac.t elpi.test +-Q tests/link_order4.t elpi.test +-Q tests/API_env.t elpi.test +-Q tests/toposort.t elpi.test +-Q tests/link_order_import1.t elpi.test +-Q tests/API_module.t elpi.test +-Q tests/vernacular2.t elpi.test +-Q tests/API.t elpi.test +-Q tests/ctx_cache.t elpi.test +-Q tests/API_TC_CS.t elpi.test +-Q tests/example_abs_evars.t elpi.test +-Q tests/example_curry_howard_tactics.t elpi.test +-Q tests/example_data_base.t elpi.test +-Q tests/example_fuzzer.t elpi.test +-Q tests/example_generalize.t elpi.test +-Q tests/example_import_projections.t elpi.test +-Q tests/example_record_expansion.t elpi.test +-Q tests/example_record_to_sigma.t elpi.test +-Q tests/example_reduction_surgery.t elpi.test +-Q tests/example_reflexive_tactic.t elpi.test +-Q tests/tutorial_coq_elpi_command.t elpi.test +-Q tests/tutorial_coq_elpi_HOAS.t elpi.test +-Q tests/tutorial_coq_elpi_tactic.t elpi.test +-Q tests/tutorial_elpi_lang.t elpi.test diff --git a/_CoqProject.examples b/_CoqProject.examples deleted file mode 100644 index 9a8173fb8..000000000 --- a/_CoqProject.examples +++ /dev/null @@ -1,24 +0,0 @@ --arg -w -arg +elpi.deprecated --arg -bt - --Q theories elpi --Q examples elpi.examples --Q tests elpi.tests --I src/ --Q elpi unreleased --docroot elpi - -examples/tutorial_elpi_lang.v -examples/tutorial_coq_elpi_HOAS.v -examples/tutorial_coq_elpi_command.v -examples/tutorial_coq_elpi_tactic.v -examples/example_reflexive_tactic.v -examples/example_curry_howard_tactics.v -examples/example_data_base.v -examples/example_record_expansion.v -examples/example_record_to_sigma.v -examples/example_fuzzer.v -examples/example_generalize.v -examples/example_import_projections.v -examples/example_reduction_surgery.v -examples/example_abs_evars.v diff --git a/_CoqProject.test b/_CoqProject.test deleted file mode 100644 index 709510e49..000000000 --- a/_CoqProject.test +++ /dev/null @@ -1,59 +0,0 @@ --arg -w -arg +elpi.deprecated --arg -bt - --Q theories elpi --Q examples elpi.examples --Q tests elpi.tests --I src/ --Q elpi unreleased --docroot elpi - -tests/test_API.v -tests/test_API_elaborate.v -tests/test_API_typecheck.v -tests/test_API_env.v -tests/test_API_module.v -tests/test_API_section.v -tests/test_API_TC_CS.v -tests/test_API_arguments.v -tests/test_API_notations.v -tests/test_API2.v -tests/test_HOAS.v -tests/test_arg_HOAS.v -tests/test_quotation.v -tests/test_vernacular1.v -tests/test_vernacular2.v -tests/test_tactic.v -tests/test_elaborator.v -tests/test_ltac.v -tests/test_ltac2.v -tests/test_ltac3.v -tests/test_cache_async.v -tests/test_COQ_ELPI_ATTRIBUTES.v -tests/perf_calls.v -tests/test_require_bad_order.v -tests/test_ctx_cache.v -tests/test_libobject_A.v -tests/test_libobject_B.v -tests/test_libobject_C.v -tests/test_glob.v -tests/test_link_perf.v -tests/test_link_order1.v -tests/test_link_order2.v -tests/test_link_order3.v -tests/test_link_order4.v -tests/test_link_order5.v -tests/test_link_order6.v -tests/test_link_order7.v -tests/test_link_order8.v -tests/test_link_order9.v -tests/test_API_new_pred.v -tests/test_link_order_import0.v -tests/test_link_order_import1.v -tests/test_link_order_import2.v -tests/test_link_order_import3.v -tests/test_query_extra_dep.v -tests/test_toposort.v -tests/test_synterp.v -tests/test_checker.v -tests/test_replay.v diff --git a/apps/NES/Makefile b/apps/NES/Makefile deleted file mode 100644 index 9b84ee407..000000000 --- a/apps/NES/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/NES/Makefile.coq.local b/apps/NES/Makefile.coq.local deleted file mode 100644 index 709787b66..000000000 --- a/apps/NES/Makefile.coq.local +++ /dev/null @@ -1,3 +0,0 @@ -install-extra:: - df="`$(COQMKFILE) -destination-of theories/NES.vo $(COQLIBS)`";\ - install -m 0644 $(wildcard elpi/*.elpi) "$(COQLIBINSTALL)/$$df" diff --git a/apps/NES/_CoqProject b/apps/NES/_CoqProject deleted file mode 100644 index 116cb4bb4..000000000 --- a/apps/NES/_CoqProject +++ /dev/null @@ -1,10 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps --Q elpi elpi.apps.NES - -theories/NES.v - diff --git a/apps/NES/_CoqProject.test b/apps/NES/_CoqProject.test deleted file mode 100644 index f6ef410e3..000000000 --- a/apps/NES/_CoqProject.test +++ /dev/null @@ -1,18 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --Q elpi elpi.apps.NES --R theories elpi.apps --R tests elpi.apps.NES.tests --R examples elpi.apps.NES.examples - -tests/test_NES.v -tests/test_NES_resolve.v -tests/test_NES_perf.v -tests/test_NES_perf_optimal.v -tests/test_module_namespace.v -tests/test_NES_lib.v - -examples/usage_NES.v \ No newline at end of file diff --git a/apps/NES/elpi/dune b/apps/NES/elpi/dune new file mode 100644 index 000000000..ff3aa20ed --- /dev/null +++ b/apps/NES/elpi/dune @@ -0,0 +1,21 @@ +(coq.theory + (name elpi.apps.NES.elpi) + (package coq-elpi) + (theories elpi)) + +(rule + (target dummy.v) + (deps + (glob_files *.elpi)) + (action + (with-stdout-to %{target} + (progn + (echo "Require Import String.\nOpen Scope string_scope.\nLocal Definition _hash := \"\n") + (run coq_elpi_shafile %{deps}) + (echo "\".\n"))))) + +(install + (files + (glob_files (*.elpi with_prefix coq/user-contrib/elpi/apps/NES/elpi/))) + (section lib_root) + (package coq-elpi)) diff --git a/apps/NES/examples/dune b/apps/NES/examples/dune new file mode 100644 index 000000000..a71cea916 --- /dev/null +++ b/apps/NES/examples/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.NES.examples) + (theories elpi elpi.apps.NES)) + +(include_subdirs qualified) diff --git a/apps/NES/tests/dune b/apps/NES/tests/dune new file mode 100644 index 000000000..efc60c5ee --- /dev/null +++ b/apps/NES/tests/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.NES.tests) + (theories elpi elpi.apps.NES)) + +(include_subdirs qualified) diff --git a/apps/NES/tests/test_NES_lib.v b/apps/NES/tests/test_NES_lib.v index 66e45c7c2..e96bb5842 100644 --- a/apps/NES/tests/test_NES_lib.v +++ b/apps/NES/tests/test_NES_lib.v @@ -1,5 +1,5 @@ -From elpi.apps.NES Extra Dependency "nes_synterp.elpi" as nes_synterp. -From elpi.apps.NES Extra Dependency "nes_interp.elpi" as nes_interp. +From elpi.apps.NES.elpi Extra Dependency "nes_synterp.elpi" as nes_synterp. +From elpi.apps.NES.elpi Extra Dependency "nes_interp.elpi" as nes_interp. From elpi.apps Require Import NES. Elpi Command Make. diff --git a/apps/NES/theories/NES.v b/apps/NES/theories/NES.v index 1a4902c61..8470263bc 100644 --- a/apps/NES/theories/NES.v +++ b/apps/NES/theories/NES.v @@ -1,5 +1,5 @@ -From elpi.apps.NES Extra Dependency "nes_synterp.elpi" as nes_synterp. -From elpi.apps.NES Extra Dependency "nes_interp.elpi" as nes_interp. +From elpi.apps.NES.elpi Extra Dependency "nes_synterp.elpi" as nes_synterp. +From elpi.apps.NES.elpi Extra Dependency "nes_interp.elpi" as nes_interp. From elpi Require Import elpi. diff --git a/apps/NES/theories/dune b/apps/NES/theories/dune new file mode 100644 index 000000000..87e94c86a --- /dev/null +++ b/apps/NES/theories/dune @@ -0,0 +1,6 @@ +(coq.theory + (name elpi.apps.NES) + (package coq-elpi) + (theories elpi elpi.apps.NES.elpi)) + +(include_subdirs qualified) diff --git a/apps/coercion/Makefile b/apps/coercion/Makefile deleted file mode 100644 index 9b84ee407..000000000 --- a/apps/coercion/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/coercion/Makefile.coq.local b/apps/coercion/Makefile.coq.local deleted file mode 100644 index 6ba02602b..000000000 --- a/apps/coercion/Makefile.coq.local +++ /dev/null @@ -1,10 +0,0 @@ -CAMLPKGS+= -package coq-elpi.elpi - -ifeq "$(shell which cygpath >/dev/null 2>&1)" "" -OCAMLFINDSEP=: -else -OCAMLFINDSEP=; -endif - -OCAMLPATH:=../../src/$(OCAMLFINDSEP)$(OCAMLPATH) -export OCAMLPATH \ No newline at end of file diff --git a/apps/coercion/_CoqProject b/apps/coercion/_CoqProject deleted file mode 100644 index b5b8d84f0..000000000 --- a/apps/coercion/_CoqProject +++ /dev/null @@ -1,14 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps - -src/coq_elpi_coercion_hook.mlg -src/elpi_coercion_plugin.mlpack - --I src/ -src/META.coq-elpi-coercion - -theories/coercion.v diff --git a/apps/coercion/_CoqProject.test b/apps/coercion/_CoqProject.test deleted file mode 100644 index e6e1f59ad..000000000 --- a/apps/coercion/_CoqProject.test +++ /dev/null @@ -1,13 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps --R tests elpi.apps.coercion.tests - -tests/test_coercion.v -tests/test_coercion_open.v -tests/test_coercion_load.v - --I src diff --git a/apps/coercion/src/coq_elpi_coercion_hook.mlg b/apps/coercion/src/coq_elpi_coercion_hook.mlg index db082bdb4..b006679ff 100644 --- a/apps/coercion/src/coq_elpi_coercion_hook.mlg +++ b/apps/coercion/src/coq_elpi_coercion_hook.mlg @@ -1,4 +1,4 @@ -DECLARE PLUGIN "coq-elpi-coercion.plugin" +DECLARE PLUGIN "coq-elpi.coercion" { diff --git a/apps/coercion/src/dune b/apps/coercion/src/dune new file mode 100644 index 000000000..66bb42925 --- /dev/null +++ b/apps/coercion/src/dune @@ -0,0 +1,8 @@ +(library + (name elpi_coercion_plugin) + (public_name coq-elpi.coercion) + (flags :standard -w -27) + (libraries coq-core.plugins.ltac coq-core.vernac coq-elpi.elpi)) + +(coq.pp + (modules coq_elpi_coercion_hook)) diff --git a/apps/coercion/tests/dune b/apps/coercion/tests/dune new file mode 100644 index 000000000..2e0c195f5 --- /dev/null +++ b/apps/coercion/tests/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.coercion.tests) + (theories elpi elpi.apps.coercion)) + +(include_subdirs qualified) diff --git a/apps/coercion/theories/coercion.v b/apps/coercion/theories/coercion.v index c4b50c273..6afd7d0f4 100644 --- a/apps/coercion/theories/coercion.v +++ b/apps/coercion/theories/coercion.v @@ -1,4 +1,4 @@ -Declare ML Module "coq-elpi-coercion.plugin". +Declare ML Module "coq-elpi.coercion". From elpi Require Import elpi. Elpi Db coercion.db lp:{{ diff --git a/apps/coercion/theories/dune b/apps/coercion/theories/dune new file mode 100644 index 000000000..90f81f0f0 --- /dev/null +++ b/apps/coercion/theories/dune @@ -0,0 +1,7 @@ +(coq.theory + (name elpi.apps.coercion) + (package coq-elpi) + (theories elpi) + (plugins coq-elpi.coercion)) + +(include_subdirs qualified) diff --git a/apps/cs/Makefile b/apps/cs/Makefile deleted file mode 100644 index 9b84ee407..000000000 --- a/apps/cs/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/cs/Makefile.coq.local b/apps/cs/Makefile.coq.local deleted file mode 100644 index 6ba02602b..000000000 --- a/apps/cs/Makefile.coq.local +++ /dev/null @@ -1,10 +0,0 @@ -CAMLPKGS+= -package coq-elpi.elpi - -ifeq "$(shell which cygpath >/dev/null 2>&1)" "" -OCAMLFINDSEP=: -else -OCAMLFINDSEP=; -endif - -OCAMLPATH:=../../src/$(OCAMLFINDSEP)$(OCAMLPATH) -export OCAMLPATH \ No newline at end of file diff --git a/apps/cs/_CoqProject b/apps/cs/_CoqProject deleted file mode 100644 index 39ac91fab..000000000 --- a/apps/cs/_CoqProject +++ /dev/null @@ -1,15 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps - -src/evarconv_hacked.ml -src/coq_elpi_cs_hook.mlg -src/elpi_cs_plugin.mlpack - --I src/ -src/META.coq-elpi-cs - -theories/cs.v diff --git a/apps/cs/_CoqProject.test b/apps/cs/_CoqProject.test deleted file mode 100644 index 891f699f9..000000000 --- a/apps/cs/_CoqProject.test +++ /dev/null @@ -1,11 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps --R tests elpi.apps.cs.tests - -tests/test_cs.v - --I src diff --git a/apps/cs/src/coq_elpi_cs_hook.mlg b/apps/cs/src/coq_elpi_cs_hook.mlg index e0badf337..b50479170 100644 --- a/apps/cs/src/coq_elpi_cs_hook.mlg +++ b/apps/cs/src/coq_elpi_cs_hook.mlg @@ -1,4 +1,4 @@ -DECLARE PLUGIN "coq-elpi-cs.plugin" +DECLARE PLUGIN "coq-elpi.cs" { diff --git a/apps/cs/src/dune b/apps/cs/src/dune new file mode 100644 index 000000000..7c02c7ad2 --- /dev/null +++ b/apps/cs/src/dune @@ -0,0 +1,8 @@ +(library + (name elpi_cs_plugin) + (public_name coq-elpi.cs) + (flags :standard -w -27) + (libraries coq-core.plugins.ltac coq-core.vernac coq-elpi.elpi)) + +(coq.pp + (modules coq_elpi_cs_hook)) diff --git a/apps/cs/tests/dune b/apps/cs/tests/dune new file mode 100644 index 000000000..a5bc01765 --- /dev/null +++ b/apps/cs/tests/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.cs.tests) + (theories elpi elpi.apps.cs)) + +(include_subdirs qualified) diff --git a/apps/cs/theories/cs.v b/apps/cs/theories/cs.v index f7f04660a..2f6df289a 100644 --- a/apps/cs/theories/cs.v +++ b/apps/cs/theories/cs.v @@ -1,4 +1,4 @@ -Declare ML Module "coq-elpi-cs.plugin". +Declare ML Module "coq-elpi.cs". From elpi Require Import elpi. Elpi Db cs.db lp:{{ diff --git a/apps/cs/theories/dune b/apps/cs/theories/dune new file mode 100644 index 000000000..ebc2a3419 --- /dev/null +++ b/apps/cs/theories/dune @@ -0,0 +1,7 @@ +(coq.theory + (name elpi.apps.cs) + (package coq-elpi) + (theories elpi) + (plugins coq-elpi.cs)) + +(include_subdirs qualified) diff --git a/apps/derive/Makefile b/apps/derive/Makefile deleted file mode 100644 index 39bf36d54..000000000 --- a/apps/derive/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -coverage: - @$(MAKE) --no-print-directory -f Makefile.coq coverage - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/derive/Makefile.coq.local b/apps/derive/Makefile.coq.local deleted file mode 100644 index 562fd6a6a..000000000 --- a/apps/derive/Makefile.coq.local +++ /dev/null @@ -1,25 +0,0 @@ - -coverage: - @printf "====== %-10s\n" "test suite" - @printf "inductives: %d\n" \ - `grep -E "^ *(Inductive|Variant)" tests/test_derive_stdlib.v 2>/dev/null| wc -l` - @printf "records: %d\n" \ - `grep -E "^ *(Record|Structure)" tests/test_derive_stdlib.v 2>/dev/null| wc -l` - @printf "definitions: %d\n" \ - `grep -E "^ *(Fixpoint|Definition)" tests/test_derive_stdlib.v 2>/dev/null| wc -l` - @for F in $(wildcard theories/derive/*.v); do\ - D=`basename $$F .v`;\ - D_=`echo $$D | sed 's/_/./'`;\ - F=`mktemp`;\ - if [ -e tests/test_$${D}.v ]; then\ - (cat tests/test_$${D}.v | awk ' /Module Coverage/ { p = 1 } /End Coverage/ { p = 0 } { if(p == 1) { print }} ' ) > $$F ;\ - N=`grep -E "^(Fail )?Elpi derive.$$D_" $$F 2>/dev/null| wc -l`;\ - OK=`grep -E "^Elpi derive.$$D_" $$F 2>/dev/null| wc -l`;\ - printf "====== %-10s (%2d/%-2d)\n" tests/test_$${D}.v $$OK $$N;\ - grep -E "^Fail Elpi derive.$$D_" $$F | grep -vi expected 2>/dev/null;\ - fi;\ - done || true - -install-extra:: - df="`$(COQMKFILE) -destination-of theories/derive/std.vo $(COQLIBS)`";\ - install -m 0644 $(wildcard elpi/*.elpi) "$(COQLIBINSTALL)/$$df" diff --git a/apps/derive/_CoqProject b/apps/derive/_CoqProject deleted file mode 100644 index de3a997ba..000000000 --- a/apps/derive/_CoqProject +++ /dev/null @@ -1,41 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps --Q elpi elpi.apps.derive --R tests elpi.apps.derive.tests --R examples elpi.apps.derive.examples - -theories/derive.v -theories/derive/std.v -theories/derive/legacy.v -theories/derive/experimental.v - -theories/derive/bcongr.v -theories/derive/cast.v -theories/derive/eq.v -theories/derive/eqcorrect.v -theories/derive/eqK.v -theories/derive/eqOK.v -theories/derive/map.v -theories/derive/isK.v -theories/derive/idx2inv.v -theories/derive/invert.v -theories/derive/projK.v -theories/derive/param1.v -theories/derive/param1_functor.v -theories/derive/param1_congr.v -theories/derive/param1_trivial.v -theories/derive/param2.v -theories/derive/induction.v -theories/derive/lens.v -theories/derive/lens_laws.v -theories/derive/eqb_core_defs.v -theories/derive/tag.v -theories/derive/fields.v -theories/derive/eqb.v -theories/derive/eqbcorrect.v -theories/derive/eqbOK.v -theories/derive/eqType_ast.v diff --git a/apps/derive/_CoqProject.test b/apps/derive/_CoqProject.test deleted file mode 100644 index 34794415f..000000000 --- a/apps/derive/_CoqProject.test +++ /dev/null @@ -1,38 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src - --R theories elpi.apps --R tests elpi.apps.derive.tests --R examples elpi.apps.derive.examples - -tests/test_readme.v -tests/test_derive_stdlib.v -tests/test_bcongr.v -tests/test_derive.v -tests/test_eq.v -tests/test_eqK.v -tests/test_eqOK.v -tests/test_map.v -tests/test_isK.v -tests/test_projK.v -tests/test_param1.v -tests/test_param1_functor.v -tests/test_param1_congr.v -tests/test_param1_trivial.v -tests/test_param2.v -tests/test_induction.v -tests/test_invert.v -tests/test_idx2inv.v -tests/test_eqcorrect.v -tests/test_lens.v -tests/test_lens_laws.v -tests/test_tag.v -tests/test_fields.v -tests/test_eqb.v -tests/test_eqbcorrect.v -tests/test_eqbOK.v -tests/test_eqType_ast.v - -examples/usage.v -examples/readme.v \ No newline at end of file diff --git a/apps/derive/elpi/dune b/apps/derive/elpi/dune new file mode 100644 index 000000000..1483b7fbc --- /dev/null +++ b/apps/derive/elpi/dune @@ -0,0 +1,21 @@ +(coq.theory + (name elpi.apps.derive.elpi) + (package coq-elpi) + (theories elpi)) + +(rule + (target dummy.v) + (deps + (glob_files *.elpi)) + (action + (with-stdout-to %{target} + (progn + (echo "Require Import String.\nOpen Scope string_scope.\nLocal Definition _hash := \"\n") + (run coq_elpi_shafile %{deps}) + (echo "\".\n"))))) + +(install + (files + (glob_files (*.elpi with_prefix coq/user-contrib/elpi/apps/derive/elpi/))) + (section lib_root) + (package coq-elpi)) diff --git a/apps/derive/examples/dune b/apps/derive/examples/dune new file mode 100644 index 000000000..89e7e401a --- /dev/null +++ b/apps/derive/examples/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.derive.examples) + (theories elpi elpi.apps.derive)) + +(include_subdirs qualified) diff --git a/apps/derive/tests/dune b/apps/derive/tests/dune new file mode 100644 index 000000000..44ae90129 --- /dev/null +++ b/apps/derive/tests/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.derive.tests) + (theories elpi elpi.apps.derive)) + +(include_subdirs qualified) diff --git a/apps/derive/tests/test_derive_vector.v b/apps/derive/tests/test_derive_vector.v.skip similarity index 98% rename from apps/derive/tests/test_derive_vector.v rename to apps/derive/tests/test_derive_vector.v.skip index a7002b490..2236dce60 100644 --- a/apps/derive/tests/test_derive_vector.v +++ b/apps/derive/tests/test_derive_vector.v.skip @@ -1,4 +1,4 @@ -From elpi.apps Require Import derive. +From elpi.apps Require Import derive derive.projK. From elpi.apps Require Import test_derive_stdlib. diff --git a/apps/derive/theories/derive.v b/apps/derive/theories/derive.v index 248e22df0..3c9839346 100644 --- a/apps/derive/theories/derive.v +++ b/apps/derive/theories/derive.v @@ -52,10 +52,10 @@ *) -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. -From elpi.apps.derive Extra Dependency "derive.elpi" as derive. -From elpi.apps.derive Extra Dependency "derive_synterp.elpi" as derive_synterp. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "derive.elpi" as derive. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp.elpi" as derive_synterp. From elpi Require Import elpi. diff --git a/apps/derive/theories/derive/bcongr.v b/apps/derive/theories/derive/bcongr.v index 9ea7a484e..36d9564fa 100644 --- a/apps/derive/theories/derive/bcongr.v +++ b/apps/derive/theories/derive/bcongr.v @@ -3,10 +3,10 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "injection.elpi" as injection. -From elpi.apps.derive Extra Dependency "bcongr.elpi" as bcongr. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "injection.elpi" as injection. +From elpi.apps.derive.elpi Extra Dependency "bcongr.elpi" as bcongr. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From Coq Require Export Bool. From elpi Require Export elpi. @@ -58,7 +58,7 @@ Elpi Accumulate derive Db derive.bcongr.db. Elpi Accumulate derive File injection. Elpi Accumulate derive File bcongr. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "bcongr" "projK". }}. diff --git a/apps/derive/theories/derive/cast.v b/apps/derive/theories/derive/cast.v index 8fd1602ed..8c084093a 100644 --- a/apps/derive/theories/derive/cast.v +++ b/apps/derive/theories/derive/cast.v @@ -3,7 +3,7 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "cast.elpi" as cast. +From elpi.apps.derive.elpi Extra Dependency "cast.elpi" as cast. From elpi Require Export elpi. diff --git a/apps/derive/theories/derive/eq.v b/apps/derive/theories/derive/eq.v index f813a7859..1e5e91f55 100644 --- a/apps/derive/theories/derive/eq.v +++ b/apps/derive/theories/derive/eq.v @@ -2,9 +2,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "eq.elpi" as eq. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "eq.elpi" as eq. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From Coq Require Import Bool. From elpi Require Import elpi. diff --git a/apps/derive/theories/derive/eqK.v b/apps/derive/theories/derive/eqK.v index 07ba4a7f4..e4fb4f73a 100644 --- a/apps/derive/theories/derive/eqK.v +++ b/apps/derive/theories/derive/eqK.v @@ -3,10 +3,10 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "discriminate.elpi" as discriminate. -From elpi.apps.derive Extra Dependency "eqK.elpi" as eqK. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "discriminate.elpi" as discriminate. +From elpi.apps.derive.elpi Extra Dependency "eqK.elpi" as eqK. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. @@ -67,7 +67,7 @@ Elpi Accumulate derive Db derive.eqK.db. Elpi Accumulate derive File discriminate. Elpi Accumulate derive File eqK. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "eqK" "bcongr". dep1 "eqK" "isK". }}. diff --git a/apps/derive/theories/derive/eqOK.v b/apps/derive/theories/derive/eqOK.v index b89d8f5fe..428cb6551 100644 --- a/apps/derive/theories/derive/eqOK.v +++ b/apps/derive/theories/derive/eqOK.v @@ -3,15 +3,15 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1.elpi" as param1. -From elpi.apps.derive Extra Dependency "eqOK.elpi" as eqOK. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1.elpi" as param1. +From elpi.apps.derive.elpi Extra Dependency "eqOK.elpi" as eqOK. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. -From elpi.apps Require Import derive.param1 derive.param1_trivial derive.eqK derive.eqcorrect. +From elpi.apps Require Import derive.param1 derive.param1_congr derive.param1_trivial derive.eqK derive.eqcorrect. Elpi Db derive.eqOK.db lp:{{ pred eqOK-done i:inductive. @@ -46,7 +46,7 @@ Elpi Typecheck. Elpi Accumulate derive File eqOK. Elpi Accumulate derive Db derive.eqOK.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "eqOK" "eqcorrect". dep1 "eqOK" "param1_trivial". }}. diff --git a/apps/derive/theories/derive/eqOK_trivial.v b/apps/derive/theories/derive/eqOK_trivial.v.skip similarity index 100% rename from apps/derive/theories/derive/eqOK_trivial.v rename to apps/derive/theories/derive/eqOK_trivial.v.skip diff --git a/apps/derive/theories/derive/eqType_ast.v b/apps/derive/theories/derive/eqType_ast.v index e1be4bc3e..2dc72ca9d 100644 --- a/apps/derive/theories/derive/eqType_ast.v +++ b/apps/derive/theories/derive/eqType_ast.v @@ -2,9 +2,9 @@ From elpi Require Import elpi. From Coq Require Import PrimInt63 PrimFloat. From elpi.apps Require Import derive. -From elpi.apps.derive Extra Dependency "eqType.elpi" as eqType. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "eqType.elpi" as eqType. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. Elpi Db derive.eqType.db lp:{{ diff --git a/apps/derive/theories/derive/eqb.v b/apps/derive/theories/derive/eqb.v index 4c6a3868c..7ddd34e43 100644 --- a/apps/derive/theories/derive/eqb.v +++ b/apps/derive/theories/derive/eqb.v @@ -3,11 +3,11 @@ From elpi.apps Require Import derive derive.param1. From Coq Require Import ssrbool ssreflect Uint63. From Coq Require Import PArith. -From elpi.apps.derive Extra Dependency "fields.elpi" as fields. -From elpi.apps.derive Extra Dependency "eqb.elpi" as eqb. -From elpi.apps.derive Extra Dependency "eqType.elpi" as eqType. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "fields.elpi" as fields. +From elpi.apps.derive.elpi Extra Dependency "eqb.elpi" as eqb. +From elpi.apps.derive.elpi Extra Dependency "eqType.elpi" as eqType. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. Require Import eqb_core_defs. Require Import eqType_ast tag fields. @@ -67,7 +67,7 @@ Elpi Typecheck. Elpi Accumulate derive Db derive.eqb.db. Elpi Accumulate derive File eqb. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "eqb" "fields". }}. diff --git a/apps/derive/theories/derive/eqbOK.v b/apps/derive/theories/derive/eqbOK.v index ef31c547d..8a11eb2cb 100644 --- a/apps/derive/theories/derive/eqbOK.v +++ b/apps/derive/theories/derive/eqbOK.v @@ -6,10 +6,10 @@ Require Import eqb_core_defs. Require Import tag eqType_ast fields eqb eqbcorrect derive. -From elpi.apps.derive Extra Dependency "eqbOK.elpi" as eqbOK. -From elpi.apps.derive Extra Dependency "eqType.elpi" as eqType. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "eqbOK.elpi" as eqbOK. +From elpi.apps.derive.elpi Extra Dependency "eqType.elpi" as eqType. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. Elpi Db derive.eqbOK.db lp:{{ @@ -44,7 +44,7 @@ Elpi Typecheck. Elpi Accumulate derive File eqbOK. Elpi Accumulate derive Db derive.eqbOK.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "eqbOK" "eqbcorrect". dep1 "eqbOK-alias" "eqbcorrect-alias". }}. diff --git a/apps/derive/theories/derive/eqbcorrect.v b/apps/derive/theories/derive/eqbcorrect.v index 95f1dffaf..d5ac45e7e 100644 --- a/apps/derive/theories/derive/eqbcorrect.v +++ b/apps/derive/theories/derive/eqbcorrect.v @@ -3,12 +3,12 @@ From elpi Require Import elpi. From elpi.apps Require Import derive. From elpi.apps.derive Require Import induction param1_functor param1_trivial eqb_core_defs tag fields eqb. -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1.elpi" as param1. -From elpi.apps.derive Extra Dependency "eqType.elpi" as eqType. -From elpi.apps.derive Extra Dependency "eqbcorrect.elpi" as eqbcorrect. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1.elpi" as param1. +From elpi.apps.derive.elpi Extra Dependency "eqType.elpi" as eqType. +From elpi.apps.derive.elpi Extra Dependency "eqbcorrect.elpi" as eqbcorrect. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. Module Export exports. Export ssreflect ssrbool eqb_core_defs. (* go ask the ltac gurus... *) @@ -98,7 +98,7 @@ Elpi Typecheck. Elpi Accumulate derive File eqbcorrect. Elpi Accumulate derive Db derive.eqbcorrect.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "eqbcorrect" "eqb". dep1 "eqbcorrect" "induction". dep1 "eqbcorrect" "param1_inhab". diff --git a/apps/derive/theories/derive/eqcorrect.v b/apps/derive/theories/derive/eqcorrect.v index 312fb583c..dbf7dbeb6 100644 --- a/apps/derive/theories/derive/eqcorrect.v +++ b/apps/derive/theories/derive/eqcorrect.v @@ -3,9 +3,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "eqcorrect.elpi" as eqcorrect. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "eqcorrect.elpi" as eqcorrect. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. @@ -56,7 +56,7 @@ Elpi Accumulate derive File derive_hook. Elpi Accumulate derive File eqcorrect. Elpi Accumulate derive Db derive.eqcorrect.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "eqcorrect" "induction". dep1 "eqcorrect" "eq". dep1 "eqcorrect" "eqK". diff --git a/apps/derive/theories/derive/fields.v b/apps/derive/theories/derive/fields.v index 1227f172d..94e944281 100644 --- a/apps/derive/theories/derive/fields.v +++ b/apps/derive/theories/derive/fields.v @@ -2,10 +2,10 @@ From elpi Require Import elpi. From elpi.apps Require Import derive. From Coq Require Import PArith. From elpi.apps Require Export derive.eqType_ast derive.tag. -From elpi.apps.derive Extra Dependency "fields.elpi" as fields. -From elpi.apps.derive Extra Dependency "eqType.elpi" as eqType. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "fields.elpi" as fields. +From elpi.apps.derive.elpi Extra Dependency "eqType.elpi" as eqType. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. Register unit as elpi.derive.unit. @@ -53,7 +53,7 @@ Elpi Typecheck. Elpi Accumulate derive File fields. Elpi Accumulate derive Db derive.fields.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "fields" "tag". dep1 "fields" "eqType_ast". }}. diff --git a/apps/derive/theories/derive/idx2inv.v b/apps/derive/theories/derive/idx2inv.v index 448b91131..23dcbe218 100644 --- a/apps/derive/theories/derive/idx2inv.v +++ b/apps/derive/theories/derive/idx2inv.v @@ -3,11 +3,11 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1_functor.elpi" as param1_functor. -From elpi.apps.derive Extra Dependency "idx2inv.elpi" as idx2inv. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1_functor.elpi" as param1_functor. +From elpi.apps.derive.elpi Extra Dependency "idx2inv.elpi" as idx2inv. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Export elpi. From elpi.apps Require Export derive. @@ -41,7 +41,7 @@ Elpi Accumulate derive Db derive.idx2inv.db. Elpi Accumulate derive File idx2inv. Elpi Accumulate File paramX. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "idx2inv" "invert". }}. diff --git a/apps/derive/theories/derive/induction.v b/apps/derive/theories/derive/induction.v index 8946a339b..e20c6c2ea 100644 --- a/apps/derive/theories/derive/induction.v +++ b/apps/derive/theories/derive/induction.v @@ -2,11 +2,11 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1.elpi" as param1. -From elpi.apps.derive Extra Dependency "induction.elpi" as induction. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1.elpi" as param1. +From elpi.apps.derive.elpi Extra Dependency "induction.elpi" as induction. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive derive.param1 derive.param1_functor. @@ -46,7 +46,7 @@ Elpi Typecheck. Elpi Accumulate derive File induction. Elpi Accumulate derive Db derive.induction.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "induction" "param1_functor". }}. diff --git a/apps/derive/theories/derive/invert.v b/apps/derive/theories/derive/invert.v index f66638f18..62f559440 100644 --- a/apps/derive/theories/derive/invert.v +++ b/apps/derive/theories/derive/invert.v @@ -3,9 +3,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "invert.elpi" as invert. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "invert.elpi" as invert. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Export elpi. From elpi.apps Require Export derive. diff --git a/apps/derive/theories/derive/isK.v b/apps/derive/theories/derive/isK.v index a1d66e91f..aec45ed22 100644 --- a/apps/derive/theories/derive/isK.v +++ b/apps/derive/theories/derive/isK.v @@ -3,9 +3,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "isK.elpi" as isK. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "isK.elpi" as isK. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. diff --git a/apps/derive/theories/derive/lens.v b/apps/derive/theories/derive/lens.v index 15a277146..ec947f46b 100644 --- a/apps/derive/theories/derive/lens.v +++ b/apps/derive/theories/derive/lens.v @@ -2,9 +2,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "lens.elpi" as lens. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "lens.elpi" as lens. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. diff --git a/apps/derive/theories/derive/lens_laws.v b/apps/derive/theories/derive/lens_laws.v index 89bf9b5ee..6b65699e6 100644 --- a/apps/derive/theories/derive/lens_laws.v +++ b/apps/derive/theories/derive/lens_laws.v @@ -2,9 +2,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "lens_laws.elpi" as lens_laws. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "lens_laws.elpi" as lens_laws. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive.lens. @@ -57,7 +57,7 @@ Elpi Typecheck. Elpi Accumulate derive File lens_laws. Elpi Accumulate derive Db derive.lens_laws.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "lens_laws" "lens". }}. diff --git a/apps/derive/theories/derive/map.v b/apps/derive/theories/derive/map.v index c1edbffb5..378315fb5 100644 --- a/apps/derive/theories/derive/map.v +++ b/apps/derive/theories/derive/map.v @@ -2,9 +2,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "map.elpi" as map. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "map.elpi" as map. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. diff --git a/apps/derive/theories/derive/param1.v b/apps/derive/theories/derive/param1.v index 3e5bb8303..6af7b482d 100644 --- a/apps/derive/theories/derive/param1.v +++ b/apps/derive/theories/derive/param1.v @@ -2,10 +2,10 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1.elpi" as param1. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1.elpi" as param1. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. diff --git a/apps/derive/theories/derive/param1_congr.v b/apps/derive/theories/derive/param1_congr.v index 6631f9951..28da44210 100644 --- a/apps/derive/theories/derive/param1_congr.v +++ b/apps/derive/theories/derive/param1_congr.v @@ -6,10 +6,10 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1_congr.elpi" as param1_congr. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1_congr.elpi" as param1_congr. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Export elpi. From elpi.apps Require Export derive.param1. @@ -36,7 +36,7 @@ Elpi Typecheck. Elpi Accumulate derive File param1_congr. Elpi Accumulate derive Db derive.param1.congr.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "param1_congr" "param1". }}. diff --git a/apps/derive/theories/derive/param1_functor.v b/apps/derive/theories/derive/param1_functor.v index d43c18c0e..b3dcb47f1 100644 --- a/apps/derive/theories/derive/param1_functor.v +++ b/apps/derive/theories/derive/param1_functor.v @@ -6,9 +6,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "param1_functor.elpi" as param1_functor. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "param1_functor.elpi" as param1_functor. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. @@ -35,7 +35,7 @@ Elpi Typecheck. Elpi Accumulate derive File param1_functor. Elpi Accumulate derive Db derive.param1.functor.db. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "param1_functor" "param1". }}. diff --git a/apps/derive/theories/derive/param1_trivial.v b/apps/derive/theories/derive/param1_trivial.v index 0e754fa20..0aef2045f 100644 --- a/apps/derive/theories/derive/param1_trivial.v +++ b/apps/derive/theories/derive/param1_trivial.v @@ -6,12 +6,12 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param1.elpi" as param1. -From elpi.apps.derive Extra Dependency "param1_inhab.elpi" as param1_inhab. -From elpi.apps.derive Extra Dependency "param1_trivial.elpi" as param1_trivial. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param1.elpi" as param1. +From elpi.apps.derive.elpi Extra Dependency "param1_inhab.elpi" as param1_inhab. +From elpi.apps.derive.elpi Extra Dependency "param1_trivial.elpi" as param1_trivial. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive.param1 derive.param1_congr. @@ -184,7 +184,7 @@ Elpi Accumulate derive Db derive.param1.trivial.db. Elpi Accumulate derive File param1_inhab. Elpi Accumulate derive File param1_trivial. -#[phases=both] Elpi Accumulate derive lp:{{ +#[phases="both"] Elpi Accumulate derive lp:{{ dep1 "param1_trivial" "param1_inhab". dep1 "param1_trivial" "param1_congr". dep1 "param1_inhab" "param1". @@ -192,6 +192,7 @@ dep1 "param1_inhab" "param1". #[synterp] Elpi Accumulate derive lp:{{ derivation _ _ (derive "param1_inhab" (cl\ cl = []) true). + derivation _ _ (derive "param1_trivial" (cl\ cl = []) true). }}. Elpi Accumulate derive lp:{{ diff --git a/apps/derive/theories/derive/param2.v b/apps/derive/theories/derive/param2.v index 4be93df83..712343f8f 100644 --- a/apps/derive/theories/derive/param2.v +++ b/apps/derive/theories/derive/param2.v @@ -2,10 +2,10 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "paramX_lib.elpi" as paramX. -From elpi.apps.derive Extra Dependency "param2.elpi" as param2. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "paramX_lib.elpi" as paramX. +From elpi.apps.derive.elpi Extra Dependency "param2.elpi" as param2. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. diff --git a/apps/derive/theories/derive/projK.v b/apps/derive/theories/derive/projK.v index 101739063..44eac02e1 100644 --- a/apps/derive/theories/derive/projK.v +++ b/apps/derive/theories/derive/projK.v @@ -5,9 +5,9 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.derive Extra Dependency "projK.elpi" as projK. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "projK.elpi" as projK. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. From elpi Require Import elpi. From elpi.apps Require Import derive. diff --git a/apps/derive/theories/derive/tag.v b/apps/derive/theories/derive/tag.v index f7927f667..2f2c029be 100644 --- a/apps/derive/theories/derive/tag.v +++ b/apps/derive/theories/derive/tag.v @@ -1,9 +1,9 @@ From elpi Require Import elpi. From elpi.apps Require Import derive. From Coq Require Import PArith. -From elpi.apps.derive Extra Dependency "tag.elpi" as tag. -From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook. -From elpi.apps.derive Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. +From elpi.apps.derive.elpi Extra Dependency "tag.elpi" as tag. +From elpi.apps.derive.elpi Extra Dependency "derive_hook.elpi" as derive_hook. +From elpi.apps.derive.elpi Extra Dependency "derive_synterp_hook.elpi" as derive_synterp_hook. Register positive as elpi.derive.positive. diff --git a/apps/derive/theories/dune b/apps/derive/theories/dune new file mode 100644 index 000000000..2f66ea4ab --- /dev/null +++ b/apps/derive/theories/dune @@ -0,0 +1,6 @@ +(coq.theory + (name elpi.apps.derive) + (package coq-elpi) + (theories elpi elpi.apps.derive.elpi)) + +(include_subdirs qualified) diff --git a/apps/eltac/Makefile b/apps/eltac/Makefile deleted file mode 100644 index 9b84ee407..000000000 --- a/apps/eltac/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/eltac/_CoqProject b/apps/eltac/_CoqProject deleted file mode 100644 index 85f861b7a..000000000 --- a/apps/eltac/_CoqProject +++ /dev/null @@ -1,22 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - -# Hack to see derive even if it is not installed yet --Q ../derive/theories elpi.apps --Q ../derive/elpi elpi.apps.derive - --R theories elpi.apps.eltac - -theories/assumption.v -theories/constructor.v -theories/intro.v -theories/clear.v -theories/fail.v -theories/discriminate.v -theories/injection.v -theories/case.v -theories/generalize.v -theories/cycle.v -theories/tactics.v diff --git a/apps/eltac/_CoqProject.test b/apps/eltac/_CoqProject.test deleted file mode 100644 index 38d0959d1..000000000 --- a/apps/eltac/_CoqProject.test +++ /dev/null @@ -1,24 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - -# Hack to see derive even if it is not installed yet --Q ../derive/theories elpi.apps - --R theories elpi.apps.eltac --R tests elpi.apps.eltac.tests --R examples elpi.apps.eltac.examples - -tests/test_assumption.v -tests/test_constructor.v -tests/test_intro.v -tests/test_clear.v -tests/test_fail.v -tests/test_discriminate.v -tests/test_injection.v -tests/test_case.v -tests/test_generalize.v -tests/test_cycle.v - -examples/usage_eltac.v diff --git a/apps/eltac/examples/dune b/apps/eltac/examples/dune new file mode 100644 index 000000000..99eac545f --- /dev/null +++ b/apps/eltac/examples/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.eltac.examples) + (theories elpi elpi.apps.eltac)) + +(include_subdirs qualified) diff --git a/apps/eltac/tests/dune b/apps/eltac/tests/dune new file mode 100644 index 000000000..6e44bff72 --- /dev/null +++ b/apps/eltac/tests/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.eltac.tests) + (theories elpi elpi.apps.eltac)) + +(include_subdirs qualified) diff --git a/apps/eltac/theories/discriminate.v b/apps/eltac/theories/discriminate.v index a0647b83d..87a403b5f 100644 --- a/apps/eltac/theories/discriminate.v +++ b/apps/eltac/theories/discriminate.v @@ -1,4 +1,4 @@ -From elpi.apps.derive Extra Dependency "discriminate.elpi" as discriminate. +From elpi.apps.derive.elpi Extra Dependency "discriminate.elpi" as discriminate. From elpi.apps Require Export derive.isK derive.bcongr derive.eqK. diff --git a/apps/eltac/theories/dune b/apps/eltac/theories/dune new file mode 100644 index 000000000..11d5b4899 --- /dev/null +++ b/apps/eltac/theories/dune @@ -0,0 +1,6 @@ +(coq.theory + (name elpi.apps.eltac) + (package coq-elpi) + (theories elpi elpi.apps.derive)) + +(include_subdirs qualified) diff --git a/apps/eltac/theories/injection.v b/apps/eltac/theories/injection.v index 2f744a5bc..76de111ad 100644 --- a/apps/eltac/theories/injection.v +++ b/apps/eltac/theories/injection.v @@ -1,4 +1,4 @@ -From elpi.apps.derive Extra Dependency "injection.elpi" as injection. +From elpi.apps.derive.elpi Extra Dependency "injection.elpi" as injection. From elpi.apps Require Export derive.projK derive.bcongr. @@ -19,4 +19,4 @@ Elpi Accumulate lp:{{ }}. Elpi Typecheck. -Tactic Notation "eltac.injection" constr(T) := elpi injection ltac_term:(T). \ No newline at end of file +Tactic Notation "eltac.injection" constr(T) := elpi injection ltac_term:(T). diff --git a/apps/locker/Makefile b/apps/locker/Makefile deleted file mode 100644 index 9b84ee407..000000000 --- a/apps/locker/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/locker/_CoqProject b/apps/locker/_CoqProject deleted file mode 100644 index 2adcf48f6..000000000 --- a/apps/locker/_CoqProject +++ /dev/null @@ -1,9 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps --Q elpi elpi.apps.locker - -theories/locker.v diff --git a/apps/locker/_CoqProject.test b/apps/locker/_CoqProject.test deleted file mode 100644 index 737a13576..000000000 --- a/apps/locker/_CoqProject.test +++ /dev/null @@ -1,9 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps --R tests elpi.apps.locker.tests - -tests/test_locker.v diff --git a/apps/locker/elpi/dune b/apps/locker/elpi/dune new file mode 100644 index 000000000..5f258ae21 --- /dev/null +++ b/apps/locker/elpi/dune @@ -0,0 +1,21 @@ +(coq.theory + (name elpi.apps.locker.elpi) + (package coq-elpi) + (theories elpi)) + +(rule + (target dummy.v) + (deps + (glob_files *.elpi)) + (action + (with-stdout-to %{target} + (progn + (echo "Require Import String.\nOpen Scope string_scope.\nLocal Definition _hash := \"\n") + (run coq_elpi_shafile %{deps}) + (echo "\".\n"))))) + +(install + (files + (glob_files (*.elpi with_prefix coq/user-contrib/elpi/apps/locker/elpi/))) + (section lib_root) + (package coq-elpi)) diff --git a/apps/locker/tests/dune b/apps/locker/tests/dune new file mode 100644 index 000000000..7a4322327 --- /dev/null +++ b/apps/locker/tests/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.locker.tests) + (theories elpi elpi.apps.locker)) + +(include_subdirs qualified) diff --git a/apps/locker/theories/dune b/apps/locker/theories/dune new file mode 100644 index 000000000..71c54f4e0 --- /dev/null +++ b/apps/locker/theories/dune @@ -0,0 +1,6 @@ +(coq.theory + (name elpi.apps.locker) + (package coq-elpi) + (theories elpi elpi.apps.locker.elpi)) + +(include_subdirs qualified) diff --git a/apps/locker/theories/locker.v b/apps/locker/theories/locker.v index f0112ee04..331eea6b8 100644 --- a/apps/locker/theories/locker.v +++ b/apps/locker/theories/locker.v @@ -2,7 +2,7 @@ license: GNU Lesser General Public License Version 2.1 or later ------------------------------------------------------------------------- *) -From elpi.apps.locker Extra Dependency "locker.elpi" as locker. +From elpi.apps.locker.elpi Extra Dependency "locker.elpi" as locker. From Coq Require Import ssreflect. From elpi Require Import elpi. diff --git a/apps/tc/Makefile b/apps/tc/Makefile deleted file mode 100644 index 9b84ee407..000000000 --- a/apps/tc/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# detection of coq -ifeq "$(COQBIN)" "" -COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`) -endif -ifeq "$(COQBIN)" "" -$(error Coq not found, make sure it is installed in your PATH or set COQBIN) -else -$(info Using coq found in $(COQBIN), from COQBIN or PATH) -endif -export COQBIN := $(COQBIN)/ - -all: build test - -build: Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq - -test: Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq - -theories/%.vo: force - @$(MAKE) --no-print-directory -f Makefile.coq $@ -tests/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ -examples/%.vo: force build Makefile.test.coq - @$(MAKE) --no-print-directory -f Makefile.test.coq $@ - -Makefile.coq Makefile.coq.conf: _CoqProject - @$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq - @$(MAKE) --no-print-directory -f Makefile.coq .merlin -Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test - @$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq - -clean: Makefile.coq Makefile.test.coq - @$(MAKE) -f Makefile.coq $@ - @$(MAKE) -f Makefile.test.coq $@ - -.PHONY: force all build test - -install: - @$(MAKE) -f Makefile.coq $@ diff --git a/apps/tc/Makefile.coq.local b/apps/tc/Makefile.coq.local deleted file mode 100644 index e9d25651e..000000000 --- a/apps/tc/Makefile.coq.local +++ /dev/null @@ -1,14 +0,0 @@ -CAMLPKGS+= -package coq-elpi.elpi - -ifeq "$(shell which cygpath >/dev/null 2>&1)" "" -OCAMLFINDSEP=: -else -OCAMLFINDSEP=; -endif - -OCAMLPATH:=../../src/$(OCAMLFINDSEP)$(OCAMLPATH) -export OCAMLPATH - -install-extra:: - df="`$(COQMKFILE) -destination-of theories/tc.vo $(COQLIBS)`";\ - install -m 0644 $(wildcard elpi/*.elpi) "$(COQLIBINSTALL)/$$df" diff --git a/apps/tc/_CoqProject b/apps/tc/_CoqProject deleted file mode 100644 index 7898332a8..000000000 --- a/apps/tc/_CoqProject +++ /dev/null @@ -1,22 +0,0 @@ -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src --docroot elpi.apps - --R theories elpi.apps.tc --R elpi elpi.apps.tc --R tests elpi.apps.tc.tests - -src/coq_elpi_tc_register.ml -src/coq_elpi_tc_hook.mlg -src/coq_elpi_class_tactics_takeover.ml -src/coq_elpi_class_tactics_hacked.ml -src/elpi_tc_plugin.mlpack - --I src/ -src/META.coq-elpi-tc - -theories/db.v -theories/add_commands.v -theories/tc.v -theories/wip.v diff --git a/apps/tc/_CoqProject.test b/apps/tc/_CoqProject.test deleted file mode 100644 index 293e86d66..000000000 --- a/apps/tc/_CoqProject.test +++ /dev/null @@ -1,54 +0,0 @@ --arg -w -arg -Not-added --arg -w -arg -TC.hints - -# Hack to see Coq-Elpi even if it is not installed yet --Q ../../theories elpi --I ../../src - --Q elpi elpi.apps.tc --R theories elpi.apps.tc --R tests elpi.apps.tc.tests --I src - -tests/classes_declare.v - -# Register (de-)activation -tests/register/f1.v -tests/register/f2.v -tests/register/f3.v - -tests/hook_test.v - -tests/auto_compile.v - -# Import order of instances -tests/importOrder/sameOrderCommand.v -tests/importOrder/f1.v -tests/importOrder/f2a.v -tests/importOrder/f2b.v -tests/importOrder/f3a.v -tests/importOrder/f3b.v -tests/importOrder/f3c.v -tests/importOrder/f3d.v -tests/importOrder/f3e.v -tests/importOrder/f3f.v -tests/importOrder/f3g.v - -tests/nobacktrack.v -tests/patternFragment.v -tests/contextDeepHierarchy.v -# tests/test_commands_API.v -tests/section_in_out.v -tests/eqSimplDef.v - -tests/injTest.v -# Test with light version of base.v of stdpp -tests/stdppInj.v -tests/stdppInjClassic.v -tests/test.v - -tests/indt_to_inst.v - -tests/bigTest.v - -examples/tutorial.v diff --git a/apps/tc/elpi/dune b/apps/tc/elpi/dune new file mode 100644 index 000000000..5e9205d56 --- /dev/null +++ b/apps/tc/elpi/dune @@ -0,0 +1,21 @@ +(coq.theory + (name elpi.apps.tc.elpi) + (package coq-elpi) + (theories elpi)) + +(rule + (target dummy.v) + (deps + (glob_files *.elpi)) + (action + (with-stdout-to %{target} + (progn + (echo "Require Import String.\nOpen Scope string_scope.\nLocal Definition _hash := \"\n") + (run coq_elpi_shafile %{deps}) + (echo "\".\n"))))) + +(install + (files + (glob_files (*.elpi with_prefix coq/user-contrib/elpi/apps/tc/elpi/))) + (section lib_root) + (package coq-elpi)) diff --git a/apps/tc/examples/dune b/apps/tc/examples/dune new file mode 100644 index 000000000..70efd6993 --- /dev/null +++ b/apps/tc/examples/dune @@ -0,0 +1,5 @@ +(coq.theory + (name elpi.apps.tc.examples) + (theories elpi elpi.apps.tc)) + +(include_subdirs qualified) diff --git a/apps/tc/src/coq_elpi_tc_hook.mlg b/apps/tc/src/coq_elpi_tc_hook.mlg index 7003bdf38..ae86862bd 100644 --- a/apps/tc/src/coq_elpi_tc_hook.mlg +++ b/apps/tc/src/coq_elpi_tc_hook.mlg @@ -1,7 +1,7 @@ (* license: GNU Lesser General Public License Version 2.1 or later *) (* ------------------------------------------------------------------------- *) -DECLARE PLUGIN "coq-elpi-tc.plugin" +DECLARE PLUGIN "coq-elpi.tc" { open Stdarg diff --git a/apps/tc/src/dune b/apps/tc/src/dune new file mode 100644 index 000000000..729c39467 --- /dev/null +++ b/apps/tc/src/dune @@ -0,0 +1,8 @@ +(library + (name elpi_tc_plugin) + (public_name coq-elpi.tc) + (flags :standard -w -27) + (libraries coq-core.plugins.ltac coq-core.vernac coq-elpi.elpi)) + +(coq.pp + (modules coq_elpi_tc_hook)) diff --git a/apps/tc/tests/compile_add_pred.v b/apps/tc/tests/compile_add_pred.v.skip similarity index 100% rename from apps/tc/tests/compile_add_pred.v rename to apps/tc/tests/compile_add_pred.v.skip diff --git a/apps/tc/tests/dune b/apps/tc/tests/dune new file mode 100644 index 000000000..48784a530 --- /dev/null +++ b/apps/tc/tests/dune @@ -0,0 +1,7 @@ +(coq.theory + (name elpi.apps.tc.tests) + (flags -async-proofs-cache force) + (theories elpi elpi.apps.tc)) + +(include_subdirs qualified) +(dirs :standard \ WIP) diff --git a/apps/tc/tests/importOrder/dune b/apps/tc/tests/importOrder/dune new file mode 100644 index 000000000..b324dbc60 --- /dev/null +++ b/apps/tc/tests/importOrder/dune @@ -0,0 +1 @@ +(copy_files ../../tests_fixties/*.elpi) \ No newline at end of file diff --git a/apps/tc/tests/importOrder/sameOrderCommand.v b/apps/tc/tests/importOrder/sameOrderCommand.v index 04aa228d1..8f458a98d 100644 --- a/apps/tc/tests/importOrder/sameOrderCommand.v +++ b/apps/tc/tests/importOrder/sameOrderCommand.v @@ -1,6 +1,6 @@ From elpi.apps Require Export tc. -From elpi.apps.tc Extra Dependency "base.elpi" as base. +From elpi.apps.tc.elpi Extra Dependency "base.elpi" as base. From elpi.apps.tc.tests.importOrder Extra Dependency "tc_same_order.elpi" as tc_same_order. Elpi Command SameOrderImport. diff --git a/apps/tc/tests/section_in_out.v b/apps/tc/tests/section_in_out.v index 5b6fae08e..569abfcfa 100644 --- a/apps/tc/tests/section_in_out.v +++ b/apps/tc/tests/section_in_out.v @@ -1,5 +1,5 @@ From elpi.apps Require Import tc. -From elpi.apps.tc Extra Dependency "base.elpi" as base. +From elpi.apps.tc.elpi Extra Dependency "base.elpi" as base. Elpi Accumulate tc.db lp:{{ pred origial_tc o:int. diff --git a/apps/tc/tests/test_commands_API.v b/apps/tc/tests/test_commands_API.v index f45d8d289..3eb9cdc3f 100644 --- a/apps/tc/tests/test_commands_API.v +++ b/apps/tc/tests/test_commands_API.v @@ -18,10 +18,10 @@ Elpi Accumulate lp:{{ }}. Elpi Typecheck. -Elpi AddClasses Eqb. +TC.AddClasses Eqb. Module test1. - Elpi AddInstances Eqb ignoreInstances eqP. + TC.AddInstances Eqb ignoreInstances eqP. Elpi len_test Eqb 2. End test1. Reset test1. @@ -32,7 +32,7 @@ End test2. Reset test2. Module test3. - Elpi AddInstances Eqb. + TC.AddInstances Eqb. Elpi len_test Eqb 3. End test3. Reset test3. @@ -48,8 +48,8 @@ Elpi Query TC.Solver lp:{{ }}. *) Module test4. - Elpi AddAllClasses. - Elpi AddAllInstances eqU. + TC.AddAllClasses. + TC.AddAllInstances eqU. Elpi Query TC.Solver lp:{{ EqP = {{:gref eqU}}, diff --git a/apps/tc/tests/test_tc.v b/apps/tc/tests/test_tc.v index 8b4970ee3..22329d30a 100644 --- a/apps/tc/tests/test_tc.v +++ b/apps/tc/tests/test_tc.v @@ -6,7 +6,7 @@ Class a (N: nat). Instance b : a 3. Qed. Instance c : a 4. Qed. -Elpi AddAllClasses. -Elpi AddAllInstances. +TC.AddAllClasses. +TC.AddAllInstances. Goal a 4. apply _. Qed. diff --git a/apps/tc/tests/importOrder/tc_same_order.elpi b/apps/tc/tests_fixties/tc_same_order.elpi similarity index 100% rename from apps/tc/tests/importOrder/tc_same_order.elpi rename to apps/tc/tests_fixties/tc_same_order.elpi diff --git a/apps/tc/theories/add_commands.v b/apps/tc/theories/add_commands.v index fa7a01e3f..2f159ad51 100644 --- a/apps/tc/theories/add_commands.v +++ b/apps/tc/theories/add_commands.v @@ -1,13 +1,13 @@ (* license: GNU Lesser General Public License Version 2.1 or later *) (* ------------------------------------------------------------------------- *) -From elpi.apps Require Import db. +From elpi.apps.tc Require Import db. -From elpi.apps.tc Extra Dependency "tc_aux.elpi" as tc_aux. -From elpi.apps.tc Extra Dependency "compiler.elpi" as compiler. -From elpi.apps.tc Extra Dependency "parser_addInstances.elpi" as parser_addInstances. -From elpi.apps.tc Extra Dependency "solver.elpi" as solver. -From elpi.apps.tc Extra Dependency "create_tc_predicate.elpi" as create_tc_predicate. +From elpi.apps.tc.elpi Extra Dependency "tc_aux.elpi" as tc_aux. +From elpi.apps.tc.elpi Extra Dependency "compiler.elpi" as compiler. +From elpi.apps.tc.elpi Extra Dependency "parser_addInstances.elpi" as parser_addInstances. +From elpi.apps.tc.elpi Extra Dependency "solver.elpi" as solver. +From elpi.apps.tc.elpi Extra Dependency "create_tc_predicate.elpi" as create_tc_predicate. Elpi Command TC.AddAllInstances. Elpi Accumulate Db tc.db. diff --git a/apps/tc/theories/db.v b/apps/tc/theories/db.v index 7eb299707..a9d8b5b3e 100644 --- a/apps/tc/theories/db.v +++ b/apps/tc/theories/db.v @@ -3,8 +3,8 @@ From elpi Require Import elpi. -From elpi.apps.tc Extra Dependency "base.elpi". -From elpi.apps.tc Extra Dependency "tc_aux.elpi". +From elpi.apps.tc.elpi Extra Dependency "base.elpi". +From elpi.apps.tc.elpi Extra Dependency "tc_aux.elpi". (* tc_option.db contains the set of options used by the solver of tc. diff --git a/apps/tc/theories/dune b/apps/tc/theories/dune new file mode 100644 index 000000000..40a2f29e0 --- /dev/null +++ b/apps/tc/theories/dune @@ -0,0 +1,7 @@ +(coq.theory + (name elpi.apps.tc) + (package coq-elpi) + (theories elpi elpi.apps.tc.elpi) + (plugins coq-elpi.tc)) + +(include_subdirs qualified) diff --git a/apps/tc/theories/tc.v b/apps/tc/theories/tc.v index 0ba466e48..77e02078d 100644 --- a/apps/tc/theories/tc.v +++ b/apps/tc/theories/tc.v @@ -1,12 +1,12 @@ (* license: GNU Lesser General Public License Version 2.1 or later *) (* ------------------------------------------------------------------------- *) -Declare ML Module "coq-elpi-tc.plugin". +Declare ML Module "coq-elpi.tc". -From elpi.apps.tc Extra Dependency "tc_aux.elpi" as tc_aux. -From elpi.apps.tc Extra Dependency "compiler.elpi" as compiler. -From elpi.apps.tc Extra Dependency "solver.elpi" as solver. -From elpi.apps.tc Extra Dependency "create_tc_predicate.elpi" as create_tc_predicate. +From elpi.apps.tc.elpi Extra Dependency "tc_aux.elpi" as tc_aux. +From elpi.apps.tc.elpi Extra Dependency "compiler.elpi" as compiler. +From elpi.apps.tc.elpi Extra Dependency "solver.elpi" as solver. +From elpi.apps.tc.elpi Extra Dependency "create_tc_predicate.elpi" as create_tc_predicate. From elpi.apps Require Import db. From elpi.apps Require Export add_commands. diff --git a/apps/tc/theories/wip.v b/apps/tc/theories/wip.v index 6a77906b9..932589f95 100644 --- a/apps/tc/theories/wip.v +++ b/apps/tc/theories/wip.v @@ -1,17 +1,17 @@ (* license: GNU Lesser General Public License Version 2.1 or later *) (* --------------------------------------------------------------------------*) -Declare ML Module "coq-elpi-tc.plugin". +Declare ML Module "coq-elpi.tc". From elpi Require Import elpi. -From elpi.apps.tc Extra Dependency "base.elpi" as base. -From elpi.apps.tc Extra Dependency "compiler.elpi" as compiler. -From elpi.apps.tc Extra Dependency "parser_addInstances.elpi" as parser_addInstances. -From elpi.apps.tc Extra Dependency "alias.elpi" as alias. -From elpi.apps.tc Extra Dependency "solver.elpi" as solver. -From elpi.apps.tc Extra Dependency "rewrite_forward.elpi" as rforward. -From elpi.apps.tc Extra Dependency "tc_aux.elpi" as tc_aux. -From elpi.apps.tc Extra Dependency "create_tc_predicate.elpi" as create_tc_predicate. +From elpi.apps.tc.elpi Extra Dependency "base.elpi" as base. +From elpi.apps.tc.elpi Extra Dependency "compiler.elpi" as compiler. +From elpi.apps.tc.elpi Extra Dependency "parser_addInstances.elpi" as parser_addInstances. +From elpi.apps.tc.elpi Extra Dependency "alias.elpi" as alias. +From elpi.apps.tc.elpi Extra Dependency "solver.elpi" as solver. +From elpi.apps.tc.elpi Extra Dependency "rewrite_forward.elpi" as rforward. +From elpi.apps.tc.elpi Extra Dependency "tc_aux.elpi" as tc_aux. +From elpi.apps.tc.elpi Extra Dependency "create_tc_predicate.elpi" as create_tc_predicate. From elpi.apps Require Import tc. diff --git a/builtin-doc/coq-builtin-synterp.elpi b/builtin-doc/coq-builtin-synterp.elpi new file mode 100644 index 000000000..5f1002d3f --- /dev/null +++ b/builtin-doc/coq-builtin-synterp.elpi @@ -0,0 +1,386 @@ + + +% -- Misc --------------------------------------------------------- + +% [coq.info ...] Prints an info message +external type coq.info variadic any prop. + +% [coq.notice ...] Prints a notice message +external type coq.notice variadic any prop. + +% [coq.say ...] Prints a notice message +external type coq.say variadic any prop. + +% [coq.warn ...] Prints a generic warning message +external type coq.warn variadic any prop. + +% [coq.warning Category Name ...] +% Prints a warning message with a Name and Category which can be used +% to silence this warning or turn it into an error. See coqc -w command +% line option +external type coq.warning string -> string -> variadic any prop. + +% [coq.error ...] Prints and *aborts* the program. It is a fatal error for +% Elpi and Ltac +external type coq.error variadic any prop. + +% [coq.version VersionString Major Minor Patch] Fetches the version of Coq, +% as a string and as 3 numbers +external pred coq.version o:string, o:int, o:int, o:int. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-arg-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% This section contains the low level data types linking Coq and elpi. +% In particular the entry points for commands + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Entry points +% +% Command and tactic invocation +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Entry point for commands. Eg. "#[att=true] Elpi mycommand foo 3 (f x)." becomes +% main [str "foo", int 3, trm (app[f,x])] +% in a context where +% attributes [attribute "att" (leaf "true")] +% holds. The encoding of terms is described below. +% See also the coq.parse-attributes utility. +pred main i:list argument. +pred main-interp i:list argument, i:any. +pred main-synterp i:list argument, o:any. +pred usage. +pred attributes o:list attribute. + +% see coq-lib.elpi for coq.parse-attributes generating the options below +type get-option string -> A -> prop. + +% The data type of arguments (for commands or tactics) +kind argument type. +type int int -> argument. % Eg. 1 -2. +type str string -> argument. % Eg. x "y" z.w. or any Coq keyword/symbol +type trm term -> argument. % Eg. (t). + +% Extra arguments for commands. [Definition], [Axiom], [Record] and [Context] +% take precedence over the [str] argument above (when not "quoted"). +% +% Eg. Record or Inductive +type indt-decl indt-decl -> argument. +% Eg. #[universes(polymorphic,...)] Record or Inductive +type upoly-indt-decl indt-decl -> upoly-decl -> argument. +type upoly-indt-decl indt-decl -> upoly-decl-cumul -> argument. +% Eg. Definition or Axiom (when the body is none) +type const-decl id -> option term -> arity -> argument. +% Eg. #[universes(polymorphic,...)] Definition or Axiom +type upoly-const-decl id -> option term -> arity -> upoly-decl -> argument. +% Eg. Context A (b : A). +type ctx-decl context-decl -> argument. + +% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +kind indt-decl type. +kind indc-decl type. +kind record-decl type. + +% An arity is written, in Coq syntax, as: +% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U +% This syntax is used, for example, in the type of an inductive type or +% in the type of constructors. We call the abstractions on the left of ":" +% "parameters" while we call the type following the ":" (proper) arity. + +% Note: in some contexts, like the type of an inductive type constructor, +% Coq makes no distinction between these two writings +% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ... +% while Elpi is a bit more restrictive, since it understands user directives +% such as the implicit status of an arguments (eg, using {} instead of () around +% the binder), only on parameters. +% Moreover parameters carry the name given by the user as an "id", while binders +% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see +% also the HOAS of terms). A user command can hence only use the names of +% parameters, and not the names of "forall" quantified variables in the arity. +% +% See also the arity->term predicate in coq-lib.elpi + +type parameter id -> implicit_kind -> term -> (term -> arity) -> arity. +type arity term -> arity. + +type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl. +type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive +type record id -> term -> id -> record-decl -> indt-decl. + +type constructor id -> arity -> indc-decl. + +type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl. +type end-record record-decl. + +% Example. +% Remark that A is a regular parameter; y is a non-uniform parameter and t +% also features an index of type bool. +% +% Inductive t (A : Type) | (y : nat) : bool -> Type := +% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true +% | K2 : t A y false +% +% is written +% +% (parameter "A" explicit {{ Type }} a\ +% inductive "t" tt (parameter "y" explicit {{ nat }} _\ +% arity {{ bool -> Type }}) +% t\ +% [ constructor "K1" +% (parameter "y" explicit {{ nat }} y\ +% (parameter "x" explicit a x\ +% (parameter "n" maximal {{ nat }} n\ +% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }}))) +% , constructor "K2" +% (parameter "y" explicit {{ nat }} y\ +% arity {{ lp:t lp:y false }}) ]) +% +% Remark that the uniform parameters are not passed to occurrences of t, since +% they never change, while non-uniform parameters are both abstracted +% in each constructor type and passed as arguments to t. +% +% The coq.typecheck-indt-decl API can be used to fill in implicit arguments +% an infer universe constraints in the declaration above (e.g. the hidden +% argument of "=" in the arity of K1). +% +% Note: when and inductive type declaration is passed as an argument to an +% Elpi command non uniform parameters must be separated from the uniform ones +% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since +% version 1.4, in Coq this separator is optional, but not in Elpi). + +% Context declaration (used as an argument to Elpi commands) +kind context-decl type. +% Eg. (x : T) or (x := B), body is optional, type may be a variable +type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl. +type context-end context-decl. + +typeabbrev field-attributes (list field-attribute). + +macro @global! :- get-option "coq:locality" "global". +macro @local! :- get-option "coq:locality" "local". + + +% Coq terms are not visible at synterp time, they are always holes + +kind term type. + +% -- Parsing time APIs +% ---------------------------------------------------- + +% [id] is a name that matters, we piggy back on Elpi's strings. +% Note: [name] is a name that does not matter. +typeabbrev id string. + + +% Name of a module /*E*/ +typeabbrev modpath (ctype "modpath"). + + +% Name of a module type /*E*/ +typeabbrev modtypath (ctype "modtypath"). + + +% [coq.locate-module ModName ModPath] locates a module. It's a fatal error +% if ModName cannot be located. *E* +external pred coq.locate-module i:id, o:modpath. + +% [coq.locate-module-type ModName ModPath] locates a module. It's a fatal +% error if ModName cannot be located. *E* +external pred coq.locate-module-type i:id, o:modtypath. + + +kind located type. +type loc-modpath modpath -> located. +type loc-modtypath modtypath -> located. + + +% [coq.locate-all Name Located] finds all possible meanings of a string. +% Does not fail. +external pred coq.locate-all i:id, o:list located. + +% Coq Module inline directive +kind coq.inline type. +type coq.inline.no coq.inline. % Coq's [no inline] (aka !) +type coq.inline.default coq.inline. % The default, can be omitted +type coq.inline.at int -> coq.inline. % Coq's [inline at ] + +external pred coq.env.begin-module-functor % Starts a functor *E* + i:id, % The name of the functor + i:option modtypath, % Its module type + i:list (pair id modtypath). % Parameters of the functor + + +pred coq.env.begin-module i:id, i:option modtypath. +coq.env.begin-module Name MP :- + coq.env.begin-module-functor Name MP []. + + +% [coq.env.end-module ModPath] end the current module that becomes known as +% ModPath *E* +external pred coq.env.end-module o:modpath. + +external pred coq.env.begin-module-type-functor % Starts a module type functor *E* + i:id, % The name of the functor + i:list (pair id modtypath). % The parameters of the functor + + +pred coq.env.begin-module-type i:id. +coq.env.begin-module-type Name :- + coq.env.begin-module-type-functor Name []. + + +% [coq.env.end-module-type ModTyPath] end the current module type that +% becomes known as ModPath *E* +external pred coq.env.end-module-type o:modtypath. + +external pred coq.env.apply-module-functor % Applies a functor *E* + i:id, % The name of the new module + i:option modtypath, % Its module type + i:modpath, % The functor being applied + i:list modpath, % Its arguments + i:coq.inline, % Arguments inlining + o:modpath. % The modpath of the new module + +external pred coq.env.apply-module-type-functor % Applies a type functor *E* + i:id, % The name of the new module type + i:modtypath, % The functor + i:list modpath, % Its arguments + i:coq.inline, % Arguments inlining + o:modtypath. % The modtypath of the new module type + +% [coq.env.include-module ModPath Inline] is like the vernacular Include, +% Inline can be omitted *E* +external pred coq.env.include-module i:modpath, i:coq.inline. + +% [coq.env.include-module-type ModTyPath Inline] is like the vernacular +% Include Type, Inline can be omitted *E* +external pred coq.env.include-module-type i:modtypath, i:coq.inline. + +% [coq.env.import-module ModPath] is like the vernacular Import *E* +external pred coq.env.import-module i:modpath. + +% [coq.env.export-module ModPath] is like the vernacular Export *E* +external pred coq.env.export-module i:modpath. + +% [coq.env.begin-section Name] starts a section named Name *E* +external pred coq.env.begin-section i:id. + +% [coq.env.end-section] end the current section *E* +external pred coq.env.end-section . + +% [coq.modpath->path MP FullPath] extract the full kernel name, each +% component is a separate list item +external pred coq.modpath->path i:modpath, o:list string. + +% [coq.modtypath->path MTP FullPath] extract the full kernel name, each +% component is a separate list item +external pred coq.modtypath->path i:modtypath, o:list string. + +% [coq.modpath->library MP LibraryPath] extract the enclosing module which +% can be Required +external pred coq.modpath->library i:modpath, o:modpath. + +% [coq.modtypath->library MTP LibraryPath] extract the enclosing module +% which can be Required +external pred coq.modtypath->library i:modtypath, o:modpath. + +% [coq.env.current-path Path] lists the current module path +external pred coq.env.current-path o:list string. + +% [coq.env.current-section-path Path] lists the current section path +external pred coq.env.current-section-path o:list string. + +% clauses +% +% A clause like +% :name "foo" :before "bar" foo X Y :- bar X Z, baz Z Y +% is represented as +% clause "foo" (before "bar") (pi x y z\ foo x y :- bar x z, baz z y) +% that is exactly what one would load in the context using =>. +% +% The name and the grafting specification can be left unspecified. +kind clause type. +type clause id -> grafting -> prop -> clause. + +% Specify if the clause has to be grafted before, grafted after or replace +% a named clause +kind grafting type. +type before id -> grafting. +type after id -> grafting. +type replace id -> grafting. + +% Specify to which module the clause should be attached to +kind scope type. +type execution-site scope. % The module inside which the Elpi program is run +type current scope. % The module being defined (see begin/end-module) +type library scope. % The outermost module (carrying the file name) + + +% see coq.elpi.accumulate-clauses +pred coq.elpi.accumulate i:scope, i:id, i:clause. +coq.elpi.accumulate S N C :- coq.elpi.accumulate-clauses S N [C]. + + +% [coq.elpi.accumulate-clauses Scope DbName Clauses] +% Declare that, once the program is over, the given clauses has to be +% added to the given db (see Elpi Db). +% Clauses usually belong to Coq modules: the Scope argument lets one +% select which module: +% - execution site (default) is the module in which the pogram is +% invoked +% - current is the module currently being constructed (see +% begin/end-module) +% - library is the current file (the module that is named after the file) +% The clauses are visible as soon as the enclosing module is +% Imported. +% Clauses cannot be accumulated inside functors. +% Supported attributes: +% - @local! (default: false, discard at the end of section or module) +% - @global! (default: false, always active, only if Scope is +% execution-site, discouraged) +external pred coq.elpi.accumulate-clauses i:scope, i:id, i:list clause. + +% Action executed during the parsing phase (aka synterp) +kind synterp-action type. +type begin-module id -> synterp-action. +type begin-module-type id -> synterp-action. +type begin-section id -> synterp-action. +type end-module modpath -> synterp-action. +type end-module-type modtypath -> synterp-action. +type end-section synterp-action. +type apply-module-functor id -> synterp-action. +type apply-module-type-functor id -> synterp-action. +type include-module modpath -> synterp-action. +type include-module-type modtypath -> synterp-action. +type import-module modpath -> synterp-action. +type export-module modpath -> synterp-action. + +% [coq.synterp-actions A] Get the list of actions performed during the +% parsing phase (aka synterp) up to now. +external pred coq.synterp-actions o:list synterp-action. + +% [coq.begin-synterp-group ID Group] Create and open a new synterp action +% group with the given name. +external pred coq.begin-synterp-group i:id, o:group. + +% [coq.end-synterp-group Group] End the synterp action group Group. Group +% must refer to the most recently openned group. +external pred coq.end-synterp-group i:group. + +% Generic attribute value +kind attribute-value type. +type leaf-str string -> attribute-value. +type leaf-loc loc -> attribute-value. +type node list attribute -> attribute-value. + +% Generic attribute +kind attribute type. +type attribute string -> attribute-value -> attribute. + + + + diff --git a/builtin-doc/coq-builtin.elpi b/builtin-doc/coq-builtin.elpi new file mode 100644 index 000000000..29cfde6e7 --- /dev/null +++ b/builtin-doc/coq-builtin.elpi @@ -0,0 +1,2135 @@ + + +% Coq terms as the object language of elpi and basic API to access Coq +% license: GNU Lesser General Public License Version 2.1 or later +% ------------------------------------------------------------------------- + +% This file is automatically generated from +% - coq-HOAS.elpi +% - coq_elpi_builtin.ml +% and contains the description of the data type of Coq terms and the +% API to access Coq. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-arg-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% This section contains the low level data types linking Coq and elpi. +% In particular the entry points for commands + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Entry points +% +% Command and tactic invocation +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Entry point for commands. Eg. "#[att=true] Elpi mycommand foo 3 (f x)." becomes +% main [str "foo", int 3, trm (app[f,x])] +% in a context where +% attributes [attribute "att" (leaf "true")] +% holds. The encoding of terms is described below. +% See also the coq.parse-attributes utility. +pred main i:list argument. +pred main-interp i:list argument, i:any. +pred main-synterp i:list argument, o:any. +pred usage. +pred attributes o:list attribute. + +% see coq-lib.elpi for coq.parse-attributes generating the options below +type get-option string -> A -> prop. + +% The data type of arguments (for commands or tactics) +kind argument type. +type int int -> argument. % Eg. 1 -2. +type str string -> argument. % Eg. x "y" z.w. or any Coq keyword/symbol +type trm term -> argument. % Eg. (t). + +% Extra arguments for commands. [Definition], [Axiom], [Record] and [Context] +% take precedence over the [str] argument above (when not "quoted"). +% +% Eg. Record or Inductive +type indt-decl indt-decl -> argument. +% Eg. #[universes(polymorphic,...)] Record or Inductive +type upoly-indt-decl indt-decl -> upoly-decl -> argument. +type upoly-indt-decl indt-decl -> upoly-decl-cumul -> argument. +% Eg. Definition or Axiom (when the body is none) +type const-decl id -> option term -> arity -> argument. +% Eg. #[universes(polymorphic,...)] Definition or Axiom +type upoly-const-decl id -> option term -> arity -> upoly-decl -> argument. +% Eg. Context A (b : A). +type ctx-decl context-decl -> argument. + +% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +kind indt-decl type. +kind indc-decl type. +kind record-decl type. + +% An arity is written, in Coq syntax, as: +% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U +% This syntax is used, for example, in the type of an inductive type or +% in the type of constructors. We call the abstractions on the left of ":" +% "parameters" while we call the type following the ":" (proper) arity. + +% Note: in some contexts, like the type of an inductive type constructor, +% Coq makes no distinction between these two writings +% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ... +% while Elpi is a bit more restrictive, since it understands user directives +% such as the implicit status of an arguments (eg, using {} instead of () around +% the binder), only on parameters. +% Moreover parameters carry the name given by the user as an "id", while binders +% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see +% also the HOAS of terms). A user command can hence only use the names of +% parameters, and not the names of "forall" quantified variables in the arity. +% +% See also the arity->term predicate in coq-lib.elpi + +type parameter id -> implicit_kind -> term -> (term -> arity) -> arity. +type arity term -> arity. + +type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl. +type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive +type record id -> term -> id -> record-decl -> indt-decl. + +type constructor id -> arity -> indc-decl. + +type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl. +type end-record record-decl. + +% Example. +% Remark that A is a regular parameter; y is a non-uniform parameter and t +% also features an index of type bool. +% +% Inductive t (A : Type) | (y : nat) : bool -> Type := +% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true +% | K2 : t A y false +% +% is written +% +% (parameter "A" explicit {{ Type }} a\ +% inductive "t" tt (parameter "y" explicit {{ nat }} _\ +% arity {{ bool -> Type }}) +% t\ +% [ constructor "K1" +% (parameter "y" explicit {{ nat }} y\ +% (parameter "x" explicit a x\ +% (parameter "n" maximal {{ nat }} n\ +% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }}))) +% , constructor "K2" +% (parameter "y" explicit {{ nat }} y\ +% arity {{ lp:t lp:y false }}) ]) +% +% Remark that the uniform parameters are not passed to occurrences of t, since +% they never change, while non-uniform parameters are both abstracted +% in each constructor type and passed as arguments to t. +% +% The coq.typecheck-indt-decl API can be used to fill in implicit arguments +% an infer universe constraints in the declaration above (e.g. the hidden +% argument of "=" in the arity of K1). +% +% Note: when and inductive type declaration is passed as an argument to an +% Elpi command non uniform parameters must be separated from the uniform ones +% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since +% version 1.4, in Coq this separator is optional, but not in Elpi). + +% Context declaration (used as an argument to Elpi commands) +kind context-decl type. +% Eg. (x : T) or (x := B), body is optional, type may be a variable +type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl. +type context-end context-decl. + +typeabbrev field-attributes (list field-attribute). + +macro @global! :- get-option "coq:locality" "global". +macro @local! :- get-option "coq:locality" "local". + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% This section contains the low level data types linking Coq and elpi. +% In particular the data type for terms and the evar_map entries (a sequent) +% and the entry points for tactics + +% Entry point for tactics. Eg. "elpi mytactic foo 3 (f x)." becomes +% solve +% Where [str "foo", int 3, trm (app[f,x])] is part of . +% The encoding of goals is described below. +% msolve is for tactics that operate on multiple goals (called via all: ). +pred solve i:goal, o:list sealed-goal. +pred msolve i:list sealed-goal, o:list sealed-goal. + +% Extra arguments for tactics +type tac ltac1-tactic -> argument. + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Coq's terms +% +% Types of term formers +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% -- terms -------------------------------------------------------------------- +kind term type. + +type sort sort -> term. % Prop, Type@{i} + +% constants: inductive types, inductive constructors, definitions +type global gref -> term. +type pglobal gref -> univ-instance -> term. + +% binders: to form functions, arities and local definitions +type fun name -> term -> (term -> term) -> term. % fun x : t => +type prod name -> term -> (term -> term) -> term. % forall x : t, +type let name -> term -> term -> (term -> term) -> term. % let x : T := v in + +% other term formers: function application, pattern matching and recursion +type app list term -> term. % app [hd|args] +type match term -> term -> list term -> term. % match t p [branch]) +type fix name -> int -> term -> (term -> term) -> term. % fix name rno ty bo + +type primitive primitive-value -> term. + +% NYI +%type cofix name -> term -> (term -> term) -> term. % cofix name ty bo + +% Notes about (match Scrutinee TypingFunction Branches) when +% Inductive i A : A -> nat -> Type := K : forall a : A, i A a 0 +% and +% Scrutinee be a term of type (i bool true 7) +% +% - TypingFunction has a very rigid shape that depends on i. Namely +% as many lambdas as indexes plus one lambda for the inductive itself +% where the value of the parameters are taken from the type of the scrutinee: +% fun `a` (indt "bool") a\ +% fun `n` (indt "nat) n\ +% fun `i` (app[indt "i", indt "bool", a n) i\ .. +% Such spine of fun cannot be omitted; else elpi cannot read the term back. +% See also coq.bind-ind-arity-no-let in coq-lib.elpi, that builds such spine for you, +% or the higher level api coq.build-match (same file) that also takes +% care of breanches. +% - Branches is a list of terms, the order is the canonical one (the order +% of the constructors as they were declared). If the constructor has arguments +% (excluding the parameters) then the corresponding term shall be a Coq +% function. In this case +% fun `x` (indt "bool") x\ .. + +% -- helpers ------------------------------------------------------------------ +macro @cast T TY :- (let `cast` TY T x\x). + +% -- misc --------------------------------------------------------------------- + +% When one writes Constraint Handling Rules unification variables are "frozen", +% i.e. represented by a fresh constant (the evar key) and a list of terms +% (typically the variables in scope). +kind evarkey type. +type uvar evarkey -> list term -> term. + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Coq's evar_map +% +% Context and evar declaration +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% An evar_info (displayed as a Coq goal) is essentially a sequent: +% +% x : t +% y := v : x +% ---------- +% p x y +% +% is coded as an Elpi query +% +% pi x1\ decl x1 `x` => +% pi x2\ def x2 `y` x1 => +% declare-evar +% [def x2 `y` x1 , decl x1 `x` ] +% (RawEvar x1 x2) (

x1 x2) (Ev x1 x2) +% +% where, by default, declare-evar creates a syntactic constraint as +% +% {x1 x2} : +% decl x1 `x` , def x2 `y` x1 ?- +% evar (RawEvar x1 x2) (

x1 x2) (Ev x1 x2) /* suspended on RawEvar, Ev */ +% +% When the program is over, a remaining syntactic constraint like the one above +% is read back and transformed into the corresponding evar_info. + +pred decl i:term, o:name, o:term. % Var Name Ty +pred def i:term, o:name, o:term, o:term. % Var Name Ty Bo +pred declare-evar i:list prop, i:term, i:term, i:term. % Ctx RawEvar Ty Evar + +:name "default-declare-evar" +declare-evar Ctx RawEv Ty Ev :- + declare_constraint (declare-evar Ctx RawEv Ty Ev) [RawEv]. + +% When a goal (evar _ _ _) is turned into a constraint the context is filtered +% to only contain decl, def, pp. For now no handling rules for this set of +% constraints other than one to remove a constraint + +pred rm-evar i:term, i:term. +rm-evar (uvar as X) (uvar as Y):- !, declare_constraint (rm-evar X Y) [X,Y]. +rm-evar _ _. + +constraint declare-evar evar def decl cache rm-evar { + + % Override the actual context + rule \ (declare-evar Ctx RawEv Ty Ev) <=> (Ctx => evar RawEv Ty Ev). + + rule \ (rm-evar (uvar X _) (uvar Y _)) (evar (uvar X _) _ (uvar Y _)). + rule \ (rm-evar (uvar X _) (uvar Y _)). + +} + +% The (evar R Ty E) predicate suspends when R and E are flexible, +% and is solved otherwise. +% The client may want to provide an alternative implementation of +% the clause "default-assign-evar", for example to typechecks that the +% term assigned to E has type Ty, or that the term assigned to R +% elaborates to a term of type Ty that gets assigned to E. +% In tactic mode, elpi/coq-elaborator.elpi wires things up that way. + +pred evar i:term, i:term, o:term. % Evar Ty RefinedSolution +evar (uvar as X) T S :- var S _ VL, !, + prune T VL, prune X VL, declare_constraint (evar X T S) [X, S]. + +:name "default-assign-evar" +evar _ _ _. % volatile, only unresolved evars are considered as evars + +% To ease the creation of a context with decl and def +% Eg. @pi-decl `x` x1\ @pi-def `y` y\ ... +macro @pi-decl N T F :- pi x\ decl x N T => F x. +macro @pi-def N T B F :- pi x\ def x N T B => cache x B_ => F x. +macro @pi-parameter ID T F :- + sigma N\ (coq.id->name ID N, pi x\ decl x N T => F x). +macro @pi-inductive ID A F :- + sigma N\ (coq.id->name ID N, coq.arity->term A T, pi x\ decl x N T => F x). + +% Sometimes it can be useful to pass to Coq a term with unification variables +% representing "untyped holes" like an implicit argument _. In particular +% a unification variable may exit the so called pattern fragment (applied +% to distinct variables) and hence cannot be reliably mapped to Coq as an evar, +% but can still be considered as an implicit argument. +% By loading in the context get-option "HOAS:holes" tt one forces that +% behavior. Here a convenience macro to be put on the LHS of => +macro @holes! :- get-option "HOAS:holes" tt. + +% Similarly, some APIs take a term skeleton in input. In that case unification +% variables are totally disregarded (not even mapped to Coq evars). They are +% interpreted as the {{ lib:elpi.hole }} constant, which represents an implicit +% argument. As a consenque these APIs don't modify the input term at all, but +% rather return a copy. Note that if {{ lib:elpi.hole }} is used directly, then +% it has to be applied to all variables in scope, since Coq erases variables +% that are not used. For example using {{ forall x : nat, lib:elpi.hole }} as +% a term skeleton is equivalent to {{ nat -> lib:elpi.hole }}, while +% {{ forall x : nat, lib:elpi.hole x lib:elpi.hole more args }} puts x in +% the scope of the hole (and passes to is more args). + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Coq's goals and tactic invocation +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% A Coq goal is essentially a sequent, like the evar_info above, but since it +% has to be manipulated as first class Elpi data, it is represented in a slightly +% different way. For example +% +% x : t +% y := v : x +% ---------- +% g x y +% +% is represented by the following term of type sealed-goal +% +% nabla x1\ +% nabla x2\ +% seal +% (goal +% [def x2 `y` x1 , decl x1 `x` ] +% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2) +% (Arguments x1 x2)) + +kind goal type. +kind sealed-goal type. +type nabla (term -> sealed-goal) -> sealed-goal. +type seal goal -> sealed-goal. + +typeabbrev goal-ctx (list prop). +type goal goal-ctx -> term -> term -> term -> list argument -> goal. + +% A sealed-goal closes with nabla the bound names of a +% +% (goal Ctx RawSolution Ty Solution Arguments) +% +% where Ctx is a list of decl or def and Solution is a unification variable +% to be assigned to a term of type Ty in order to make progress. +% RawSolution is used as a trigger: when a term is assigned to it, it is +% elaborated against Ty and the resulting term is assigned to Solution. +% +% Arguments contains data attached to the goal, which lives in its context +% and can be used by tactics to solve the goals. + +% A tactic (an elpi predicate which makes progress on a Coq goal) is +% a predicate of type +% sealed-goal -> list sealed-goal -> prop +% +% while the main entry point for a tactic written in Elpi is solve +% which has type +% goal -> list sealed-goal -> prop +% +% The utility (coq.ltac.open T G GL) postulates all the variables bounds +% by nabla and loads the goal context before calling T on the unsealed +% goal. The invocation of a tactic with arguments +% 3 x "y" (h x) +% on the previous goal results in the following Elpi query: +% +% (pi x1\ decl x1 `x` => +% pi x2\ def x2 `y` x1 => +% declare-evar +% [def x2 `y` x1 , decl x1 `x` ] +% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)), +% (coq.ltac.open solve +% (nabla x1\ nabla x2\ seal +% (goal +% [def x2 `y` x1 , decl x1 `x` ] +% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2) +% [int 3, str `x`, str`y`, trm (app[const `h`,x1])])) +% NewGoals) +% +% If the goal sequent contains other evars, then a tactic invocation is +% an Elpi query made of the conjunction of all the declare-evar queries +% corresponding to these evars and the query corresponding to the goal +% sequent. NewGoals can be assigned to a list of goals that should be +% declared as open. Omitted goals are shelved. If NewGoals is not +% assigned, then all unresolved evars become new goals, but the order +% of such goals is not specified. + +% The file elpi-ltac.elpi provides a few combinators (other than coq.ltac.open) +% in the tradition of LCF tacticals. The main difference is that the arguments +% of custom written tactics must not be passed as predicate arguments but rather +% put in the goal they receive. Indeed these arguments can contain terms, and +% their bound variables cannot escape the seal. coq.ltac.set-goal-arguments +% can be used to put an argument from the current goal context into another +% goal. The coq.ltac.call utility can call Ltac1 code (written in Coq) and +% pass arguments via this mechanism. + +% Last, since Elpi is alerady a logic programming language with primitive +% support for unification variables, most of the work of a tactic can be +% performed without using tacticals (which work on sealed goals) but rather +% in the context of the original goal. The last step is typically to call +% the refine utility with a term synthesized by the tactic or invoke some +% Ltac1 code on that term (e.g. to call vm_compute, see also the example +% on the reflexive tactic). + +% ----- Multi goals tactics. ---- +% Coq provides goal selectors, such as all:, to pass to a tactic more than one +% goal. In order to write such a tactic, Coq-Elpi provides another entry point +% called msolve. To be precise, if there are two goals under focus, say and +% , then all: elpi tac runs the following query +% +% msolve [,] NewGoals ; % note the disjunction +% coq.ltac.all (coq.ltac.open solve) [,] NewGoals +% +% So, if msolve has no clause, Coq-Elpi will use solve on all the goals +% independently. If msolve has a cluse, then it can manipulate the entire list +% of sealed goals. Note that the argument is in both and but +% it is interpreted in both contexts independently. If both goals have a proof +% variable named "x" then passing (@eq_refl _ x) as equips both goals with +% a (raw) proof that "x = x", no matter what their type is. + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Declarations for Coq's API (environment read/write access, etc). +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% tt = Yes, ff = No, unspecified = No (unspecified means "_" or a variable). +typeabbrev opaque? bool. macro @opaque! :- tt. macro @transparent! :- ff. + +%%%%%%% Attributes to be passed to APIs as in @local! => coq.something %%%%%%%% + +macro @primitive! :- get-option "coq:primitive" tt. % primitive records +macro @reversible! :- get-option "coq:reversible" tt. % coercions +macro @no-tc! :- get-option "coq:no_tc" tt. % skip typeclass inference + +macro @uinstance! I :- get-option "coq:uinstance" I. % universe instance + +% declaration of universe polymorphic constants +% The first list is the one of the unvierse variables being bound +% The first boolean is tt if this list can be extended by Coq (or it has to +% mention all universes actually used) +% The second list if the one with the constaints amond where universes +% The second boolean is tt if this list can be extended by Coq or it has to +% mention all universe constraints actually required to type check the +% declaration) +macro @udecl! Vs LV Cs LC :- get-option "coq:udecl" (upoly-decl Vs LV Cs LC). +macro @udecl-cumul! Vs LV Cs LC :- get-option "coq:udecl-cumul" (upoly-decl-cumul Vs LV Cs LC). +macro @univpoly! :- @udecl! [] tt [] tt. +macro @univpoly-cumul! :- @udecl-cumul! [] tt [] tt. + +macro @ppwidth! N :- get-option "coq:ppwidth" N. % printing width +macro @ppall! :- get-option "coq:pp" "all". % printing all +macro @ppmost! :- get-option "coq:pp" "most". % printing most of contents +macro @pplevel! N :- get-option "coq:pplevel" N. % printing precedence (for parentheses) + +macro @keepunivs! :- get-option "coq:keepunivs" tt. % skeletons elaboration +macro @dropunivs! :- get-option "coq:keepunivs" ff. % add-indt/add-const + +macro @using! S :- get-option "coq:using" S. % like the #[using=S] attribute + +macro @inline-at! N :- get-option "coq:inline" (coq.inline.at N). % like Inline(N) +macro @inline! N :- get-option "coq:inline" coq.inline.default. % like + +macro @redflags! F :- get-option "coq:redflags" F. % for whd & co + +% both arguments are strings eg "8.12.0" "use foo instead" +macro @deprecated! Since Msg :- + get-option "coq:deprecated" (pr Since Msg). + +macro @ltacfail! N :- get-option "ltac:fail" N. + +% retrocompatibility macro for Coq v8.10 +macro @coercion! :- [coercion reversible]. + + +% Attributes for a record field. Can be left unspecified, see defaults +% below. +kind field-attribute type. +type coercion coercion-status -> field-attribute. % default off +type canonical bool -> field-attribute. % default true, if field is named + +% Status of a record field w.r.t. coercions +kind coercion-status type. +type regular coercion-status. +type reversible coercion-status. +type off coercion-status. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% builtins %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% This section contains the API to access Coq +% The marker *E* means *experimental*, i.e. use at your own risk, it may change +% substantially or even disappear in future versions. + + +% -- Misc --------------------------------------------------------- + +% [coq.info ...] Prints an info message +external type coq.info variadic any prop. + +% [coq.notice ...] Prints a notice message +external type coq.notice variadic any prop. + +% [coq.say ...] Prints a notice message +external type coq.say variadic any prop. + +% [coq.warn ...] Prints a generic warning message +external type coq.warn variadic any prop. + +% [coq.warning Category Name ...] +% Prints a warning message with a Name and Category which can be used +% to silence this warning or turn it into an error. See coqc -w command +% line option +external type coq.warning string -> string -> variadic any prop. + +% [coq.error ...] Prints and *aborts* the program. It is a fatal error for +% Elpi and Ltac +external type coq.error variadic any prop. + +% [coq.version VersionString Major Minor Patch] Fetches the version of Coq, +% as a string and as 3 numbers +external pred coq.version o:string, o:int, o:int, o:int. + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% API for objects belonging to the logic +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% -- Environment: names ----------------------------------------------- + +% To make the API more precise we use different data types for the names +% of global objects. +% Note: [ctype \"bla\"] is an opaque data type and by convention it is +% written [@bla]. + +% Global constant name +typeabbrev constant (ctype "constant"). + + +% Inductive type name +typeabbrev inductive (ctype "inductive"). + + +% Inductive constructor name +typeabbrev constructor (ctype "constructor"). + + +% Global objects: inductive types, inductive constructors, definitions +kind gref type. +type const constant -> gref. % Nat.add, List.append, ... +type indt inductive -> gref. % nat, list, ... +type indc constructor -> gref. % O, S, nil, cons, ... + +% [id] is a name that matters, we piggy back on Elpi's strings. +% Note: [name] is a name that does not matter. +typeabbrev id string. + + +% Name of a module /*E*/ +typeabbrev modpath (ctype "modpath"). + + +% Name of a module type /*E*/ +typeabbrev modtypath (ctype "modtypath"). + + +% Result of coq.locate-all +kind located type. +type loc-gref gref -> located. +type loc-modpath modpath -> located. +type loc-modtypath modtypath -> located. +type loc-abbreviation abbreviation -> located. + +% [coq.locate-all Name Located] finds all possible meanings of a string. +% Does not fail. +external pred coq.locate-all i:id, o:list located. + +% [coq.locate Name GlobalReference] locates a global definition, inductive +% type or constructor via its name. +% It unfolds syntactic notations, e.g. "Notation old_name := new_name." +% It undestands qualified names, e.g. "Nat.t". +% It understands Coqlib Registered names using the "lib:" prefix, +% eg "lib:core.bool.true". +% It's a fatal error if Name cannot be located. +external pred coq.locate i:id, o:gref. + +% -- Environment: read ------------------------------------------------ + +% Note: The type [term] is defined in coq-HOAS.elpi + +% [coq.env.typeof GR Ty] reads the type Ty of a global reference. +% Supported attributes: +% - @uinstance! I (default: fresh instance I) +external pred coq.env.typeof i:gref, o:term. + +% [coq.env.global GR T] turns a global reference GR into a term, or +% viceversa. +% T = (global GR) or, if GR points to a universe polymorphic term, +% T = (pglobal GR I). +% Supported attributes: +% - @uinstance! I (default: fresh instance I) +external pred coq.env.global o:gref, o:term. + +external pred coq.env.indt % reads the inductive type declaration for the environment. +% Supported attributes: +% - @uinstance! I (default: fresh instance I) + i:inductive, % reference to the inductive type + o:bool, % tt if the type is inductive (ff for co-inductive) + o:int, % number of parameters + o:int, % number of parameters that are uniform (<= parameters) + o:term, % type of the inductive type constructor including parameters + o:list constructor, % list of constructor names + o:list term. % list of the types of the constructors (type of KNames) including parameters + +external pred coq.env.indt-decl % reads the inductive type declaration for the environment. +% Supported attributes: +% - @uinstance! I (default: fresh instance I) + i:inductive, % reference to the inductive type + o:indt-decl. % HOAS description of the inductive type + +% [coq.env.indc->indt K I N] finds the inductive I to which constructor K +% belongs and its position N among the other constructors +external pred coq.env.indc->indt i:constructor, o:inductive, o:int. + +% [coq.env.indc GR ParamNo UnifParamNo Kno Ty] reads the type Ty of an +% inductive constructor GR, as well as +% the number of parameters ParamNo and uniform parameters +% UnifParamNo and the number of the constructor Kno (0 based). +% Supported attributes: +% - @uinstance! I (default: fresh instance I) +external pred coq.env.indc i:constructor, o:int, o:int, o:int, o:term. + +% [coq.env.informative? Ind] Checks if Ind is informative, that is, if +% it can be eliminated to build a Type. Inductive types in Type +% are +% informative, as well a singleton types in Prop (which are +% regarded as not non-informative). +external pred coq.env.informative? i:inductive. + +% [coq.env.record? Ind PrimProjs] checks if Ind is a record (PrimProjs = tt +% if Ind has primitive projections) +external pred coq.env.record? i:inductive, o:bool. + +% [coq.env.recursive? Ind] checks if Ind is recursive +external pred coq.env.recursive? i:inductive. + +% [coq.env.opaque? GR] checks if GR is an opaque constant +external pred coq.env.opaque? i:constant. + +% [coq.env.univpoly? GR PolyArity] checks if GR is universe polymorphic and +% if so returns the number of universe variables +external pred coq.env.univpoly? i:gref, o:int. + +% [coq.env.const GR Bo Ty] reads the type Ty and the body Bo of constant +% GR. +% Opaque constants have Bo = none. +% Supported attributes: +% - @uinstance! I (default: fresh instance I) +external pred coq.env.const i:constant, o:option term, o:term. + +% [coq.env.const-body GR Bo] reads the body of a constant, even if it is +% opaque. +% If such body is none, then the constant is a true axiom. +% Supported attributes: +% - @uinstance! I (default: fresh instance I) +external pred coq.env.const-body i:constant, o:option term. + +% [coq.env.primitive? GR] tests if GR is a primitive constant (like uin63 +% addition) or a primitive type (like uint63) +external pred coq.env.primitive? i:constant. + +% [coq.locate-module ModName ModPath] locates a module. It's a fatal error +% if ModName cannot be located. *E* +external pred coq.locate-module i:id, o:modpath. + +% [coq.locate-module-type ModName ModPath] locates a module. It's a fatal +% error if ModName cannot be located. *E* +external pred coq.locate-module-type i:id, o:modtypath. + +% Contents of a module +kind module-item type. +type submodule modpath -> list module-item -> module-item. +type module-type modtypath -> module-item. +type gref gref -> module-item. +type module-functor modpath -> list modtypath -> module-item. +type module-type-functor modtypath -> list modtypath -> module-item. + +% [coq.env.module MP Contents] lists the contents of a module (recurses on +% submodules) *E* +external pred coq.env.module i:modpath, o:list module-item. + +% [coq.env.module-type MTP Entries] lists the items made visible by module +% type (does not recurse on submodules) *E* +external pred coq.env.module-type i:modtypath, o:list id. + +% [coq.env.section GlobalObjects] lists the global objects that are marked +% as to be abstracted at the end of the enclosing sections +external pred coq.env.section o:list constant. + +% [coq.env.dependencies GR MP Deps] Computes the direct dependencies of GR. +% If MP is given, Deps only contains grefs from that module +external pred coq.env.dependencies i:gref, i:modpath, o:coq.gref.set. + +% [coq.env.transitive-dependencies GR MP Deps] Computes the transitive +% dependencies of GR. If MP is given, Deps only contains grefs from that +% module +external pred coq.env.transitive-dependencies i:gref, i:modpath, + o:coq.gref.set. + +% [coq.env.term-dependencies T S] Computes all the grefs S occurring in the +% term T +external pred coq.env.term-dependencies i:term, o:coq.gref.set. + +% [coq.env.current-path Path] lists the current module path +external pred coq.env.current-path o:list string. + +% [coq.env.current-section-path Path] lists the current section path +external pred coq.env.current-section-path o:list string. + +% Deprecated, use coq.env.opaque? + pred coq.env.const-opaque? i:constant. + coq.env.const-opaque? C :- + coq.warning "elpi.deprecated" "elpi.const-opaque" "use coq.env.opaque? in place of coq.env.const-opaque?", + coq.env.opaque? C. + + +% Deprecated, use coq.env.primitive? + pred coq.env.const-primitive? i:constant. + coq.env.const-primitive? C :- + coq.warning "elpi.deprecated" "elpi.const-primitive" "use coq.env.primitive? in place of coq.env.const-primitive?", + coq.env.primitive? C. + + +% -- Environment: write ----------------------------------------------- + +% Note: (monomorphic) universe constraints are taken from ELPI's +% constraints store. Use coq.univ-* in order to add constraints (or any +% higher level facility as coq.typecheck). Load in the context attributes +% such as @univpoly!, @univpoly-cumul!, @udecl! or @udecl-cumul! in order to +% declare universe polymorphic constants or inductives. + +% [coq.env.add-const Name Bo Ty Opaque C] Declare a new constant: C gets a +% constant derived from Name +% and the current module; Ty can be left unspecified and in that case +% the +% inferred one is taken (as in writing Definition x := t); Bo can be +% left +% unspecified and in that case an axiom is added (or a section variable, +% if a section is open and @local! is used). Omitting the body and the type +% is +% an error. Note: using this API for declaring an axiom or a section +% variable is +% deprecated, use coq.env.add-axiom or coq.env.add-section-variable +% instead. +% Supported attributes: +% - @local! (default: false) +% - @using! (default: section variables actually used) +% - @univpoly! (default unset) +% - @udecl! (default unset) +% - @dropunivs! (default: false, drops all universe constraints from the +% store after the definition) +% +external pred coq.env.add-const i:id, i:term, i:term, i:opaque?, + o:constant. + +% [coq.env.add-axiom Name Ty C] Declare a new axiom: C gets a constant +% derived from Name +% and the current module. +% Supported attributes: +% - @local! (default: false) +% - @univpoly! (default unset) +% - @using! (default: section variables actually used) +% - @inline! (default: no inlining) +% - @inline-at! N (default: no inlining) +external pred coq.env.add-axiom i:id, i:term, o:constant. + +% [coq.env.add-section-variable Name Ty C] Declare a new section variable: C +% gets a constant derived from Name +% and the current module +external pred coq.env.add-section-variable i:id, i:term, o:constant. + +% [coq.env.add-indt Decl I] Declares an inductive type. +% Supported attributes: +% - @dropunivs! (default: false, drops all universe constraints from the +% store after the definition) +% - @primitive! (default: false, makes records primitive) +external pred coq.env.add-indt i:indt-decl, o:inductive. + +% Interactive module construction + +% Coq Module inline directive +kind coq.inline type. +type coq.inline.no coq.inline. % Coq's [no inline] (aka !) +type coq.inline.default coq.inline. % The default, can be omitted +type coq.inline.at int -> coq.inline. % Coq's [inline at ] + +% [coq.env.fresh-global-id ID FID] Generates an id FID which is fresh in +% the current module and looks similar to ID, i.e. it is ID concatenated +% with a number, starting from 1. +% [coq.env.fresh-global-id X X] can be used to check if X is taken +external pred coq.env.fresh-global-id i:id, o:id. + +external pred coq.env.begin-module-functor % Starts a functor. bla bla + i:id, % The name of the functor + i:option modtypath, % Its module type (optional) + i:list (pair id modtypath). % Parameters of the functor (optional) + + +pred coq.env.begin-module i:id, i:option modtypath. +coq.env.begin-module Name MP :- coq.env.begin-module-functor Name MP []. + + +% [coq.env.end-module ModPath] end the current module that becomes known as +% ModPath *E*. bla bla +external pred coq.env.end-module o:modpath. + +external pred coq.env.begin-module-type-functor % Starts a module type functor *E*. bla bla + i:id, % The name of the functor + i:list (pair id modtypath). % The parameters of the functor (optional) + + +pred coq.env.begin-module-type i:id. +coq.env.begin-module-type Name :- + coq.env.begin-module-type-functor Name []. + + +% [coq.env.end-module-type ModTyPath] end the current module type that +% becomes known as ModPath *E*. bla bla +external pred coq.env.end-module-type o:modtypath. + +external pred coq.env.apply-module-functor % Applies a functor *E*. bla bla + i:id, % The name of the new module + i:option modtypath, % Its module type (optional) + i:modpath, % The functor being applied (optional) + i:list modpath, % Its arguments (optional) + i:coq.inline, % Arguments inlining (optional) + o:modpath. % The modpath of the new module + +external pred coq.env.apply-module-type-functor % Applies a type functor *E*. bla bla + i:id, % The name of the new module type + i:modtypath, % The functor (optional) + i:list modpath, % Its arguments (optional) + i:coq.inline, % Arguments inlining (optional) + o:modtypath. % The modtypath of the new module type + +% [coq.env.include-module ModPath Inline (optional)] is like the vernacular +% Include, Inline can be omitted *E*. bla bla +external pred coq.env.include-module i:modpath, i:coq.inline. + +% [coq.env.include-module-type ModTyPath Inline (optional)] is like the +% vernacular Include Type, Inline can be omitted *E*. bla bla +external pred coq.env.include-module-type i:modtypath, i:coq.inline. + +% [coq.env.import-module ModPath] is like the vernacular Import *E* +external pred coq.env.import-module i:modpath. + +% [coq.env.export-module ModPath] is like the vernacular Export *E* +external pred coq.env.export-module i:modpath. + +% Support for sections is limited, in particular sections and +% Coq quotations may interact in surprising ways. For example +% Section Test. +% Variable x : nat. +% Elpi Query lp:{{ coq.say {{ x }} }}. +% works since x is a global Coq term while +% Elpi Query lp:{{ +% coq.env.begin-section "Test", +% coq.env.add-const "x" _ {{ nat }} _ @local! GRX, +% coq.say {{ x }} +% }}. +% may work in a surprising way or may not work at all since +% x is resolved before the section is started hence it cannot +% denote the same x as before. + +% [coq.env.begin-section Name] starts a section named Name *E* +external pred coq.env.begin-section i:id. + +% [coq.env.end-section] end the current section *E* +external pred coq.env.end-section . + +% [coq.env.projections StructureName Projections] given a record +% StructureName lists all projections +external pred coq.env.projections i:inductive, o:list (option constant). + +% [coq.env.primitive-projections StructureName Projections] given a record +% StructureName lists all primitive projections +external pred coq.env.primitive-projections i:inductive, + o:list (option (pair projection int)). + +% -- Sorts (and their universe level, if applicable) ---------------- + +% Warning: universe polymorphism has to be considered experimental *E* as +% a feature, not just as a set of APIs. Unfortunately some of the +% current complexity is exposed to the programmer, bare with us. +% +% The big bang is that in Coq one has terms, types and sorts (which are +% the types of types). Some sorts (as of today only Type) some with +% a universe level, on paper Type_i for some i. At the sort level +% Coq features some form of subtyping: a function expecting a function +% to Type, e.g. nat -> Type, can receive a function to Prop, since +% Prop <= Type. So far, so good. But what are these levels i +% exactly? +% +% Universe levels are said to be "algebraic", they are made of +% variables (see the next section) and the two operators +1 and max. +% This is a sort of internal optimization that leaks to the +% user/programmer. Indeed these universe levels cannot be (directly) used +% in all APIs morally expecting a universe level "i", in particular +% the current constraint engine cannot handle constraint with an +% algebraic level on the right, e.g. i <= j+1. Since some APIs only +% accept universe variables, we provide the coq.univ.variable API +% which is able to craft a universe variable which is roughly +% equivalent to an algebraic universe, e.g. k such that j+1 = k. +% +% Coq-Elpi systematically purges algebraic universes from terms (and +% types and sorts) when one reads them from the environment. This +% makes the embedding of terms less precise than what it could be. +% The different data types stay, since Coq will eventually become +% able to handle algebraic universes consistently, making this purging +% phase unnecessary. + +% universe level (algebraic: max, +1, univ.variable) +typeabbrev univ (ctype "univ"). + + +% Sorts (kinds of types) +kind sort type. +type prop sort. % impredicative sort of propositions +type sprop sort. % impredicative sort of propositions with definitional proof irrelevance +type typ univ -> + sort. % predicative sort of data (carries a universe level) + +% [coq.sort.leq S1 S2] constrains S1 <= S2 +external pred coq.sort.leq o:sort, o:sort. + +% [coq.sort.eq S1 S2] constrains S1 = S2 +external pred coq.sort.eq o:sort, o:sort. + +% [coq.sort.sup S1 S2] constrains S2 = S1 + 1 +external pred coq.sort.sup o:sort, o:sort. + +% [coq.sort.pts-triple S1 S2 S3] constrains S3 = sort of product with domain +% in S1 and codomain in S2 +external pred coq.sort.pts-triple o:sort, o:sort, o:sort. + +% [coq.univ.print] prints the set of universe constraints +external pred coq.univ.print . + +% [coq.univ.new U] A fresh universe. +external pred coq.univ.new o:univ. + +% [coq.univ Name U] Finds a named unvierse. Can fail. +external pred coq.univ o:id, o:univ. + +% [coq.univ.global? U] succeeds if U is a global universe +external pred coq.univ.global? i:univ. + +% [coq.univ.constraints CL] gives the list of constraints, see also +% coq.univ.variable.constraints +external pred coq.univ.constraints o:list univ-constraint. + +% -- Universe variables ------ + +% universe level variable +typeabbrev univ.variable (ctype "univ.variable"). + + +% [coq.univ.variable U L] relates a univ.variable L to a univ U +external pred coq.univ.variable o:univ, o:univ.variable. + +% [coq.univ.variable.constraints L CL] gives the list of constraints on L. +% Can be used to craft a strict upoly-decl +external pred coq.univ.variable.constraints i:univ.variable, + o:list univ-constraint. + +% [coq.univ.variable.of-term T S] collects all univ.variables occurring in T +external pred coq.univ.variable.of-term i:term, o:coq.univ.variable.set. + +% -- Universe instance (for universe polymorphic global terms) ------ + +% As of today a universe polymorphic constant can only be instantiated +% with universe level variables. That is f@{Prop} is not valid, nor +% is f@{u+1}. One can only write f@{u} for any u. +% +% A univ-instance is morally a list of universe level variables, +% but its list syntax is hidden in the terms. If you really need to +% craft or inspect one of these, the following APIs can help you. +% +% Most of the time the user is expected to use coq.env.global which +% crafts a fresh, appropriate, universe instance and possibly unify that +% term (of the instance it contains) with another one. + +% Universes level instance for a universe-polymorphic constant +typeabbrev univ-instance (ctype "univ-instance"). + + +% [coq.univ-instance UI UL] relates a univ-instance UI and a list of +% universe level variables UL +external pred coq.univ-instance o:univ-instance, o:list univ.variable. + +% [coq.univ-instance.unify-eq GR UI1 UI2 Diagnostic] unifies the two +% universe instances for the same gref +external pred coq.univ-instance.unify-eq i:gref, i:univ-instance, + i:univ-instance, o:diagnostic. + +% [coq.univ-instance.unify-leq GR UI1 UI2 Diagnostic] unifies the two +% universe instances for the same gref. Note: if the GR is not *cumulative* +% (see Cumulative or #[universes(cumulative)]) then this API imposes an +% equality constraint. +external pred coq.univ-instance.unify-leq i:gref, i:univ-instance, + i:univ-instance, o:diagnostic. + +% -- Declaration of universe polymorphic global terms ----------- + +% These are the data types used to declare how constants +% and inductive types should be declared (see also the @udecl! +% and +% @udecl-cumul! macros). Note that only inductive types can be +% declared as cumulative. + +% Constraint between two universes level variables +kind univ-constraint type. +type lt univ.variable -> univ.variable -> univ-constraint. +type le univ.variable -> univ.variable -> univ-constraint. +type eq univ.variable -> univ.variable -> univ-constraint. + +% Variance of a universe level variable +kind univ-variance type. +type auto univ.variable -> univ-variance. +type covariant univ.variable -> univ-variance. +type invariant univ.variable -> univ-variance. +type irrelevant univ.variable -> univ-variance. + +% Constraints for a non-cumulative declaration. Boolean tt means loose +% (e.g. the '+' in f@{u v + | u < v +}) +kind upoly-decl type. +type upoly-decl list univ.variable -> bool -> list univ-constraint -> + bool -> upoly-decl. + +% Constraints for a cumulative declaration. Boolean tt means loose (e.g. +% the '+' in f@{u v + | u < v +}) +kind upoly-decl-cumul type. +type upoly-decl-cumul list univ-variance -> bool -> + list univ-constraint -> bool -> upoly-decl-cumul. + +% -- Primitive -------------------------------------------------------- + +typeabbrev uint63 (ctype "uint63"). + + +typeabbrev float64 (ctype "float64"). + + +typeabbrev projection (ctype "projection"). + + +% Primitive values +kind primitive-value type. +type uint63 uint63 -> primitive-value. % unsigned integers over 63 bits +type float64 float64 -> + primitive-value. % double precision foalting points +type proj projection -> int -> primitive-value. % primitive projection + +% [coq.uint63->int U I] Transforms a primitive unsigned integer U into an +% elpi integer I. Fails if it does not fit. +external pred coq.uint63->int i:uint63, o:int. + +% [coq.int->uint63 I U] Transforms an elpi integer I into a primitive +% unsigned integer U. Fails if I is negative. +external pred coq.int->uint63 i:int, o:uint63. + +% [coq.float64->float F64 F] Transforms a primitive float on 64 bits to an +% elpi one. Currently, it should not fail. +external pred coq.float64->float i:float64, o:float. + +% [coq.float->float64 F F64] Transforms an elpi float F to a primitive float +% on 64 bits. Currently, it should not fail. +external pred coq.float->float64 i:float, o:float64. + +% [coq.primitive.projection-unfolded P PU] Relates a primitive projection P +% to its unfolded version PU. PU is still a primitive projection, but it is +% displayed as a match and some Ltac code can see that. +external pred coq.primitive.projection-unfolded o:projection, + o:projection. + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% API for extra logical objects +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% -- Databases (TC, CS, Coercions) ------------------------------------ + +% Pattern for canonical values +kind cs-pattern type. +type cs-gref gref -> cs-pattern. +type cs-prod cs-pattern. +type cs-default cs-pattern. +type cs-sort sort -> cs-pattern. + +% Canonical Structure instances: (cs-instance Proj ValPat Inst) +kind cs-instance type. +type cs-instance gref -> cs-pattern -> gref -> cs-instance. + +% [coq.CS.declare-instance GR] Declares GR as a canonical structure +% instance. +% Supported attributes: +% - @local! (default: false) +external pred coq.CS.declare-instance i:gref. + +% [coq.CS.db Db] reads all instances +external pred coq.CS.db o:list cs-instance. + +% [coq.CS.db-for Proj Value Db] reads all instances for a given Projection +% or canonical Value, or both +external pred coq.CS.db-for i:gref, i:cs-pattern, o:list cs-instance. + +% [coq.TC.declare-class GR] Declare GR as a type class +external pred coq.TC.declare-class i:gref. + +% [coq.elpi.toposort Graph Nodes in toposort order] takes a graph and +% returns the nodes in topological order +external pred coq.elpi.toposort i:list (pair A (list A)), o:list A. + +% Type class instance priority +kind tc-priority type. +type tc-priority-given int -> tc-priority. % User given priority +type tc-priority-computed int -> tc-priority. % Coq computed priority + +% Type class instance with priority +kind tc-instance type. +type tc-instance gref -> tc-priority -> tc-instance. + +% [coq.TC.declare-instance GR Priority] Declare GR as a Global type class +% instance with Priority. +% Supported attributes: +% - @global! (default: true) +external pred coq.TC.declare-instance i:gref, i:int. + +% [coq.TC.db Instances] reads all type class instances +external pred coq.TC.db o:list tc-instance. + +% [coq.TC.db-tc TypeClasses] reads all type classes +external pred coq.TC.db-tc o:list gref. + +% [coq.TC.db-for GR InstanceList] reads all instances of the given class GR. +% Instances are in their precedence order. +external pred coq.TC.db-for i:gref, o:list tc-instance. + +% [coq.TC.get-inst-prio ClassGR InstGR InstPrio] reads the priority of an +% instance +external pred coq.TC.get-inst-prio i:gref, i:gref, o:tc-priority. + +% [coq.TC.class? GR] checks if GR is a class +external pred coq.TC.class? i:gref. + +% Node of the coercion graph +kind class type. +type funclass class. +type sortclass class. +type grefclass gref -> class. + +% Edge of the coercion graph +kind coercion type. +type coercion gref -> int -> gref -> class -> + coercion. % ref, nparams, src, tgt + +% [coq.coercion.declare C] Declares C = (coercion GR NParams From To) as a +% coercion From >-> To. +% NParams can always be omitted, since it is inferred. +% If From or To is unspecified, then the endpoints are inferred. +% Supported attributes: +% - @global! (default: false) +% - @nonuniform! (default: false) +% - @reversible! (default: false) +external pred coq.coercion.declare i:coercion. + +% [coq.coercion.db L] reads all declared coercions +external pred coq.coercion.db o:list coercion. + +% [coq.coercion.db-for From To L] L is a path From -> To +external pred coq.coercion.db-for i:class, i:class, + o:list (pair gref int). + +% Deprecated, use coq.env.projections +pred coq.CS.canonical-projections i:inductive, o:list (option constant). +coq.CS.canonical-projections I L :- + coq.warning "elpi.deprecated" "elpi.canonical-projections" "use coq.env.projections in place of coq.CS.canonical-projections", + coq.env.projections I L. + + +% -- Coq's Hint DB ------------------------------------- + +% Locality of hints is a delicate matter since the Coq default +% is, in some cases, to make an hint active even if the module it belongs +% to is not imported (just merely required, which can happen +% transitively). +% Coq is aiming at changing the default to #[export], that makes an +% hint active only when its enclosing module is imported. +% See: +% https://coq.discourse.group/t/change-of-default-locality-for-hint-commands-in-coq-8-13/1140 +% +% This old behavior is available via the @global! flag, but is discouraged. +% + +% Hint Mode +kind hint-mode type. +type mode-ground hint-mode. % No Evar +type mode-input hint-mode. % No Head Evar +type mode-output hint-mode. % Anything + +% [coq.hints.add-mode GR DB Mode] Adds a mode declaration to DB about +% GR. +% Supported attributes: +% - @local! (default is export) +% - @global! (discouraged, may become deprecated) +external pred coq.hints.add-mode i:gref, i:string, i:list hint-mode. + +% [coq.hints.modes GR DB Modes] Gets all the mode declarations in DB about +% GR +external pred coq.hints.modes i:gref, i:string, o:list (list hint-mode). + +% [coq.hints.set-opaque C DB Opaque] Like Hint Opaque C : DB (or Hint +% Transparent, if the boolean is ff). +% Supported attributes: +% - @local! (default is export) +% - @global! (discouraged, may become deprecated) +external pred coq.hints.set-opaque i:constant, i:string, i:bool. + +% [coq.hints.opaque C DB Opaque] Reads if constant C is opaque (tt) or +% transparent (ff) in DB +external pred coq.hints.opaque i:constant, i:string, o:bool. + +% [coq.hints.add-resolve GR DB Priority Pattern] Like Hint Resolve GR | +% Priority Pattern : DB. +% Supported attributes: +% - @local! (default is export) +% - @global! (discouraged, may become deprecated) +external pred coq.hints.add-resolve i:gref, i:string, i:int, i:term. + +% -- Coq's notational mechanisms ------------------------------------- + +% Implicit status of an argument +kind implicit_kind type. +type implicit implicit_kind. % regular implicit argument, eg Arguments foo [x] +type maximal implicit_kind. % maximally inserted implicit argument, eg Arguments foo {x} +type explicit implicit_kind. % explicit argument, eg Arguments foo x + +% [coq.arguments.implicit GR Imps] reads the implicit arguments declarations +% associated to a global reference. See also the [] and {} flags for the +% Arguments command. +external pred coq.arguments.implicit i:gref, o:list (list implicit_kind). + +% [coq.arguments.set-implicit GR Imps] sets the implicit arguments +% declarations associated to a global reference. +% Unspecified means explicit. +% See also the [] and {} flags for the Arguments command. +% Supported attributes: +% - @global! (default: false) +external pred coq.arguments.set-implicit i:gref, + i:list (list implicit_kind). + +% [coq.arguments.set-default-implicit GR] sets the default implicit +% arguments declarations associated to a global reference. +% See also the "default implicits" flag to the Arguments command. +% Supported attributes: +% - @global! (default: false) +external pred coq.arguments.set-default-implicit i:gref. + +% [coq.arguments.name GR Names] reads the Names of the arguments of a global +% reference. See also the (f (A := v)) syntax. +external pred coq.arguments.name i:gref, o:list (option id). + +% [coq.arguments.set-name GR Names] sets the Names of the arguments of a +% global reference. +% See also the :rename flag to the Arguments command. +% Supported attributes: +% - @global! (default: false) +external pred coq.arguments.set-name i:gref, i:list (option id). + +% [coq.arguments.scope GR Scopes] reads the notation scope of the arguments +% of a global reference. See also the %scope modifier for the Arguments +% command +external pred coq.arguments.scope i:gref, o:list (list id). + +% [coq.arguments.set-scope GR Scopes] sets the notation scope of the +% arguments of a global reference. +% Scope can be a scope name or its delimiter. +% See also the %scope modifier for the Arguments command. +% Supported attributes: +% - @global! (default: false) +external pred coq.arguments.set-scope i:gref, i:list (list id). + +% Strategy for simplification tactics +kind simplification_strategy type. +type never simplification_strategy. % Arguments foo : simpl never +type when list int -> option int -> + simplification_strategy. % Arguments foo .. / .. ! .. +type when-nomatch list int -> option int -> + simplification_strategy. % Arguments foo .. / .. ! .. : simpl nomatch + +% [coq.arguments.simplification GR Strategy] reads the behavior of the +% simplification tactics. Positions are 0 based. See also the ! and / +% modifiers for the Arguments command +external pred coq.arguments.simplification i:gref, + o:option simplification_strategy. + +% [coq.arguments.set-simplification GR Strategy] sets the behavior of the +% simplification tactics. +% Positions are 0 based. +% See also the ! and / modifiers for the Arguments command. +% Supported attributes: +% - @global! (default: false) +external pred coq.arguments.set-simplification i:gref, + i:simplification_strategy. + +% [coq.locate-abbreviation Name Abbreviation] locates an abbreviation. It's +% a fatal error if Name cannot be located. +external pred coq.locate-abbreviation i:id, o:abbreviation. + +% Name of an abbreviation +typeabbrev abbreviation (ctype "abbreviation"). + + +% [coq.notation.add-abbreviation Name Nargs Body OnlyParsing Abbreviation] +% Declares an abbreviation Name with Nargs arguments. +% The term must begin with at least Nargs "fun" nodes whose domain is +% ignored, eg (fun _ _ x\ fun _ _ y\ app[global "add",x,y]). +% Supported attributes: +% - @deprecated! (default: not deprecated) +% - @global! (default: false) +external pred coq.notation.add-abbreviation i:id, i:int, i:term, i:bool, + o:abbreviation. + +% [coq.notation.abbreviation Abbreviation Args Body] Unfolds an abbreviation +external pred coq.notation.abbreviation i:abbreviation, i:list term, + o:term. + +% [coq.notation.abbreviation-body Abbreviation Nargs Body] Retrieves the +% body of an abbreviation +external pred coq.notation.abbreviation-body i:abbreviation, o:int, + o:term. + +% [coq.notation.add-abbreviation-for-tactic Name TacticName FixedArgs] +% Declares a parsing rule similar to +% Notation Name X1..Xn := ltac:(elpi TacticName FixedArgs (X1)..(Xn)) +% so that Name can be used in the middle of a term to invoke an +% elpi tactic. While FixedArgs can contain str, int, and trm all +% other arguments will necessarily be terms, and their number is +% not fixed (the user can pass as many as he likes). +% The tactic receives as the elpi.loc attribute the precise location +% at which the term is written (unlike if a regular abbreviation was +% declared by hand). +% A call to coq.notation.add-abbreviation-for-tactic TacName TacName [] +% is equivalent to Elpi Export TacName. +external pred coq.notation.add-abbreviation-for-tactic i:string, + i:string, + i:list argument. + +% Generic attribute value +kind attribute-value type. +type leaf-str string -> attribute-value. +type leaf-loc loc -> attribute-value. +type node list attribute -> attribute-value. + +% Generic attribute +kind attribute type. +type attribute string -> attribute-value -> attribute. + +% -- Coq's pretyper --------------------------------------------------- + +% [coq.sigma.print] Prints Coq's Evarmap and the mapping to/from Elpi's +% unification variables +external pred coq.sigma.print . + +% [coq.typecheck T Ty Diagnostic] typchecks a term T returning its type Ty. +% If Ty is provided, then +% the inferred type is unified (see unify-leq) with it. +% Universe constraints are put in the constraint store. +external pred coq.typecheck i:term, o:term, o:diagnostic. + +% [coq.typecheck-ty Ty U Diagnostic] typchecks a type Ty returning its +% universe U. If U is provided, then +% the inferred universe is unified (see unify-leq) with it. +% Universe constraints are put in the constraint store. +external pred coq.typecheck-ty i:term, o:sort, o:diagnostic. + +% [coq.unify-eq A B Diagnostic] unifies the two terms +external pred coq.unify-eq i:term, i:term, o:diagnostic. + +% [coq.unify-leq A B Diagnostic] unifies the two terms (with cumulativity, +% if they are types) +external pred coq.unify-leq i:term, i:term, o:diagnostic. + +% [coq.elaborate-skeleton T ETy E Diagnostic] elabotares T against the +% expected type ETy. +% T is allowed to contain holes (unification variables) but these are +% not assigned even if the elaborated term has a term in place of the +% hole. Similarly universe levels present in T are disregarded. +% Supported attributes: +% - @keepunivs! (default false, do not disregard universe levels) +% - @no-tc! (default false, do not infer typeclasses) +external pred coq.elaborate-skeleton i:term, o:term, o:term, o:diagnostic. + +% [coq.elaborate-ty-skeleton T U E Diagnostic] elabotares T expecting it to +% be a type of sort U. +% T is allowed to contain holes (unification variables) but these are +% not assigned even if the elaborated term has a term in place of the +% hole. Similarly universe levels present in T are disregarded. +% Supported attributes: +% - @keepunivs! (default false, do not disregard universe levels) +% - @no-tc! (default false, do not infer typeclasses) +external pred coq.elaborate-ty-skeleton i:term, o:sort, o:term, + o:diagnostic. + +% -- Coq's reduction flags ------------------------------------ + +% Flags for lazy, cbv, ... reductions +kind coq.redflag type. +type coq.redflags.beta coq.redflag. +type coq.redflags.delta coq.redflag. % if set then coq.redflags.const disables unfolding +type coq.redflags.match coq.redflag. +type coq.redflags.fix coq.redflag. +type coq.redflags.cofix coq.redflag. +type coq.redflags.zeta coq.redflag. +type coq.redflags.const constant -> + coq.redflag. % enable/disable unfolding + +% Set of flags for lazy, cbv, ... reductions +typeabbrev coq.redflags (ctype "coq.redflags"). + +type coq.redflags.all coq.redflags. +type coq.redflags.allnolet coq.redflags. +type coq.redflags.beta coq.redflags. +type coq.redflags.betadeltazeta coq.redflags. +type coq.redflags.betaiota coq.redflags. +type coq.redflags.betaiotazeta coq.redflags. +type coq.redflags.betazeta coq.redflags. +type coq.redflags.delta coq.redflags. +type coq.redflags.zeta coq.redflags. +type coq.redflags.nored coq.redflags. + +% [coq.redflags.add Flags Options NewFlags] Updates reduction Flags by +% adding Options +external pred coq.redflags.add i:coq.redflags, i:list coq.redflag, + o:coq.redflags. + +% [coq.redflags.sub Flags Options NewFlags] Updates reduction Flags by +% removing Options +external pred coq.redflags.sub i:coq.redflags, i:list coq.redflag, + o:coq.redflags. + +% -- Coq's reduction machines ------------------------------------ + +% [coq.reduction.lazy.whd T Tred] Puts T in weak head normal form. +% Supported attributes: +% - @redflags! (default coq.redflags.all) +external pred coq.reduction.lazy.whd i:term, o:term. + +% [coq.reduction.lazy.norm T Tred] Puts T in normal form. +% Supported attributes: +% - @redflags! (default coq.redflags.all) +external pred coq.reduction.lazy.norm i:term, o:term. + +% [coq.reduction.lazy.bi-norm T Tred] Puts T in normal form only reducing +% beta and iota redexes +external pred coq.reduction.lazy.bi-norm i:term, o:term. + +% [coq.reduction.cbv.norm T Tred] Puts T in normal form using the call by +% value strategy. +% Supported attributes: +% - @redflags! (default coq.redflags.all) +external pred coq.reduction.cbv.norm i:term, o:term. + +% [coq.reduction.vm.norm T Ty Tred] Puts T in normal form using +% [vm_compute]'s machinery. Its type Ty can be omitted (but is recomputed) +external pred coq.reduction.vm.norm i:term, i:term, o:term. + +% [coq.reduction.native.norm T Ty Tred] Puts T in normal form using +% [native_compute]'s machinery. Its type Ty can be omitted (but is +% recomputed). Falls back to vm.norm if native compilation is not available. +external pred coq.reduction.native.norm i:term, i:term, o:term. + +% [coq.reduction.native.available?] Is native compilation available on this +% system/configuration? +external pred coq.reduction.native.available? . + +% Deprecated, use coq.reduction.cbv.norm +pred coq.reduction.cbv.whd_all i:term, o:term. +coq.reduction.cbv.whd_all T R :- + coq.warning "elpi.deprecated" "elpi.cbv-whd-all" "use coq.reduction.cbv.norm in place of coq.reduction.cbv.whd_all", + coq.reduction.cbv.norm T R. + + +% Deprecated, use coq.reduction.vm.norm +pred coq.reduction.vm.whd_all i:term, i:term, o:term. +coq.reduction.vm.whd_all T TY R :- + coq.warning "elpi.deprecated" "elpi.vm-whd-all" "use coq.reduction.vm.norm in place of coq.reduction.vm.whd_all", + coq.reduction.vm.norm T TY R. + + + +pred coq.reduction.lazy.whd_all i:term, o:term. +coq.reduction.lazy.whd_all X Y :- + @redflags! coq.redflags.all => coq.reduction.lazy.whd X Y. + + +% [coq.reduction.eta-contract T Tred] Removes all eta expansions from T +external pred coq.reduction.eta-contract i:term, o:term. + +% -- Coq's conversion strategy tweaks -------------------------- + +% Strategy for conversion test +% expand < ... < level -1 < level 0 < level 1 < ... < opaque +kind conversion_strategy type. +type opaque conversion_strategy. +type expand conversion_strategy. +type level int -> conversion_strategy. % default is 0, aka transparent + +% [coq.strategy.set CL Level] Sets the unfolding priority for all the +% constants in the list CL. See the command Strategy. +external pred coq.strategy.set i:list constant, i:conversion_strategy. + +% [coq.strategy.get C Level] Gets the unfolding priority for C +external pred coq.strategy.get i:constant, o:conversion_strategy. + +% -- Coq's tactics -------------------------------------------- + +% LTac1 tactic expression +typeabbrev ltac1-tactic (ctype "ltac1-tactic"). + + +% [coq.ltac.fail Level ...] Interrupts the Elpi program and calls Ltac's +% fail Level Msg, where Msg is the printing of the remaining arguments. +% Level can be left unspecified and defaults to 0 +external type coq.ltac.fail int -> variadic any prop. + +% [coq.ltac.collect-goals T Goals ShelvedGoals] +% Turns the holes in T into Goals. +% Goals are closed with nablas. +% ShelvedGoals are goals which can be solved by side effect (they occur +% in the type of the other goals). +% The order of Goals is given by the traversal order of EConstr.fold +% (a +% fold_left over the terms, letin body comes before the type). +% +external pred coq.ltac.collect-goals i:term, o:list sealed-goal, + o:list sealed-goal. + +% [coq.ltac.call-ltac1 Tac G GL] Calls Ltac1 tactic Tac on goal G (passing +% the arguments of G, see coq.ltac.call for a handy wrapper). +% Tac can either be a string (the tactic name), or a value +% of type ltac1-tactic, see the tac argument constructor +% and the ltac_tactic:(...) syntax to pass arguments to +% an elpi tactic. +% Supported attributes: +% - @no-tc! (default false, do not infer typeclasses) +external pred coq.ltac.call-ltac1 i:any, i:goal, o:list sealed-goal. + +% [coq.ltac.id-free? ID G] +% Fails if ID is already used in G. Note that ids which are taken are +% renamed +% on the fly (since in the HOAS of terms, names are just pretty printing +% hints), but for the ergonomy of a tactic it may help to know if an +% hypothesis name is already taken. +% +external pred coq.ltac.id-free? i:id, i:goal. + +% [coq.ltac.fresh-id Default Ty FreshID] TODO +external pred coq.ltac.fresh-id i:id, i:term, o:id. + +% -- Coq's options system -------------------------------------------- + +% Coq option value +kind coq.option type. +type coq.option.int option int -> coq.option. % none means unset +type coq.option.string option string -> coq.option. % none means unset +type coq.option.bool bool -> coq.option. + +% [coq.option.get Option Value] reads Option. Reading a non existing option +% is a fatal error. +external pred coq.option.get i:list string, o:coq.option. + +% [coq.option.set Option Value] writes Option. Writing a non existing option +% is a fatal error. +external pred coq.option.set i:list string, i:coq.option. + +% [coq.option.available? Option Deprecated] checks if Option exists and +% tells if is deprecated (tt) or not (ff) +external pred coq.option.available? i:list string, o:bool. + +% [coq.option.add Option Value Deprecated] +% adds a new option to Coq setting its current value (and type). +% Deprecated can be left unspecified and defaults to ff. +% This call cannot be undone in a Coq interactive session, use it once +% and for all in a .v file which your clients will load. Eg. +% +% Elpi Query lp:{{ coq.option.add ... }}. +% +% +external pred coq.option.add i:list string, i:coq.option, i:bool. + +% -- Datatypes conversions -------------------------------------------- + +% Name.Name.t: Name hints (in binders), can be input writing a name +% between backticks, e.g. `x` or `_` for anonymous. Important: these are +% just printing hints with no meaning, hence in elpi two name are always +% related: `x` = `y` +typeabbrev name (ctype "name"). + + +% [coq.name-suffix Name Suffix NameSuffix] suffixes a Name with a string or +% an int or another name +external pred coq.name-suffix i:name, i:any, o:name. + +% [coq.string->name Hint Name] creates a name hint +external pred coq.string->name i:string, o:name. + + +pred coq.id->name i:id, o:name. +coq.id->name S N :- coq.string->name S N. + + +% [coq.name->id Name Id] tuns a pretty printing hint into a string. This API +% is for internal use, no guarantee on its behavior. +external pred coq.name->id i:name, o:id. + +% [coq.gref->id GR Id] extracts the label (last component of a full kernel +% name) +external pred coq.gref->id i:gref, o:id. + +% [coq.gref->string GR FullPath] extract the full kernel name +external pred coq.gref->string i:gref, o:string. + +% [coq.gref->path GR FullPath] extract the full path (kernel name without +% final id), each component is a separate list item +external pred coq.gref->path i:gref, o:list string. + +% [coq.modpath->path MP FullPath] extract the full kernel name, each +% component is a separate list item +external pred coq.modpath->path i:modpath, o:list string. + +% [coq.modtypath->path MTP FullPath] extract the full kernel name, each +% component is a separate list item +external pred coq.modtypath->path i:modtypath, o:list string. + +% [coq.modpath->library MP LibraryPath] extract the enclosing module which +% can be Required +external pred coq.modpath->library i:modpath, o:modpath. + +% [coq.modtypath->library MTP LibraryPath] extract the enclosing module +% which can be Required +external pred coq.modtypath->library i:modtypath, o:modpath. + +% [coq.term->string T S] prints a term T to a string S using Coq's pretty +% printer +% Supported attributes: +% - @ppwidth! N (default 80, max line length) +% - @ppall! (default: false, prints all details) +% - @ppmost! (default: false, prints most details) +% - @pplevel! (default: _, prints parentheses to reach that level, 200 = +% off) +% - @holes! (default: false, prints evars as _) +external pred coq.term->string i:term, o:string. + +% [coq.term->pp T B] prints a term T to a pp.t B using Coq's pretty +% printer" +% Supported attributes: +% - @ppall! (default: false, prints all details) +% - @ppmost! (default: false, prints most details) +% - @pplevel! (default: _, prints parentheses to reach that level, 200 = +% off) +% - @holes! (default: false, prints evars as _) +external pred coq.term->pp i:term, o:coq.pp. + +% [coq.goal->pp G B] prints a goal G to a pp.t B using Coq's pretty +% printer" +% Supported attributes: +% - @ppall! (default: false, prints all details) +% - @ppmost! (default: false, prints most details) +% - @pplevel! (default: _, prints parentheses to reach that level, 200 = +% off) +% - @holes! (default: false, prints evars as _) +external pred coq.goal->pp i:goal, o:coq.pp. + +% -- Extra Dependencies ----------------------------------------------- + +% [coq.extra-dep Identifier FileName] Resolve the file name of an extra +% dependency. See also Coq's From xxx Extra Dependency yyy as zzz. +external pred coq.extra-dep i:id, o:option id. + +% -- Access to Elpi's data -------------------------------------------- + +% clauses +% +% A clause like +% :name "foo" :before "bar" foo X Y :- bar X Z, baz Z Y +% is represented as +% clause "foo" (before "bar") (pi x y z\ foo x y :- bar x z, baz z y) +% that is exactly what one would load in the context using =>. +% +% The name and the grafting specification can be left unspecified. +kind clause type. +type clause id -> grafting -> prop -> clause. + +% Specify if the clause has to be grafted before, grafted after or replace +% a named clause +kind grafting type. +type before id -> grafting. +type after id -> grafting. +type replace id -> grafting. + +% Specify to which module the clause should be attached to +kind scope type. +type execution-site scope. % The module inside which the Elpi program is run +type current scope. % The module being defined (see begin/end-module) +type library scope. % The outermost module (carrying the file name) + + +% see coq.elpi.accumulate-clauses +pred coq.elpi.accumulate i:scope, i:id, i:clause. +coq.elpi.accumulate S N C :- coq.elpi.accumulate-clauses S N [C]. + + +% [coq.elpi.accumulate-clauses Scope DbName Clauses] +% Declare that, once the program is over, the given clauses has to be +% added to the given db (see Elpi Db). +% Clauses usually belong to Coq modules: the Scope argument lets one +% select which module: +% - execution site (default) is the module in which the pogram is +% invoked +% - current is the module currently being constructed (see +% begin/end-module) +% - library is the current file (the module that is named after the file) +% The clauses are visible as soon as the enclosing module is Imported. +% A clause that mentions a section variable is automatically discarded +% at the end of the section. +% Clauses cannot be accumulated inside functors. +% Supported attributes: +% - @local! (default: false, discard at the end of section or module) +% - @global! (default: false, always active, only if Scope is +% execution-site, discouraged) +external pred coq.elpi.accumulate-clauses i:scope, i:id, i:list clause. + +% Specify if a predicate argument is in input or output mode +kind argument_mode type. +type in argument_mode. +type out argument_mode. + +% [coq.elpi.add-predicate Db Indexing PredName Spec] Declares a new +% predicate PredName in the data base Db. +% Indexing can be left unspecified. Spec gathers a mode and a +% type for each argument. CAVEAT: types and indexing are strings +% instead of proper data types; beware parsing errors are fatal. +% Supported attributes: +% - @local! (default: false, discard at the end of section or module) +% - @global! (default: false, always active +external pred coq.elpi.add-predicate i:string, i:string, i:string, + i:list (pair argument_mode string). + +% [coq.elpi.predicate PredName Args Pred] Pred is the application of +% PredName to Args +external pred coq.elpi.predicate i:string, i:list any, o:prop. + +% -- Synterp ---------------------------------------------------------- + +% Action executed during the parsing phase (aka synterp) +kind synterp-action type. +type begin-module id -> synterp-action. +type begin-module-type id -> synterp-action. +type begin-section id -> synterp-action. +type end-module modpath -> synterp-action. +type end-module-type modtypath -> synterp-action. +type end-section synterp-action. +type apply-module-functor id -> synterp-action. +type apply-module-type-functor id -> synterp-action. +type include-module modpath -> synterp-action. +type include-module-type modtypath -> synterp-action. +type import-module modpath -> synterp-action. +type export-module modpath -> synterp-action. + +% Synterp action group +typeabbrev group (ctype "group"). + + +% [coq.next-synterp-action A] Get the next action performed during parsing +% (aka synterp), that is also the next action to be performed during +% execution (aka interp). See also coq.replay-synterp-action +external pred coq.next-synterp-action o:synterp-action. + +% [coq.replay-synterp-action-group ID] Execute all actions of synterp action +% group ID. ID must be the name of the next group, it must not be opened +% already, and there must not be any actions before it. +external pred coq.replay-synterp-action-group i:id. + +% [coq.begin-synterp-group ID Group] Match a begin-synterp-group synterp +% operation. ID must be the name of the next synterp action group and there +% must not be any actions before it. +external pred coq.begin-synterp-group i:id, o:group. + +% [coq.end-synterp-group Group] Match a end-synterp-group synterp operation. +% Group must be the currently opened synterp action group and the group must +% not have any more synterp actions or groups left to replay. +external pred coq.end-synterp-group i:group. + +% -- Utils ------------------------------------------------------------ + +kind coq.gref.set type. + +% [coq.gref.set.empty A] The empty set +external pred coq.gref.set.empty o:coq.gref.set. + +% [coq.gref.set.mem Elem A] Checks if Elem is in a +external pred coq.gref.set.mem i:gref, i:coq.gref.set. + +% [coq.gref.set.add Elem A B] B is A union {Elem} +external pred coq.gref.set.add i:gref, i:coq.gref.set, o:coq.gref.set. + +% [coq.gref.set.remove Elem A B] B is A \ {Elem} +external pred coq.gref.set.remove i:gref, i:coq.gref.set, o:coq.gref.set. + +% [coq.gref.set.union A B X] X is A union B +external pred coq.gref.set.union i:coq.gref.set, i:coq.gref.set, + o:coq.gref.set. + +% [coq.gref.set.inter A B X] X is A intersection B +external pred coq.gref.set.inter i:coq.gref.set, i:coq.gref.set, + o:coq.gref.set. + +% [coq.gref.set.diff A B X] X is A \ B +external pred coq.gref.set.diff i:coq.gref.set, i:coq.gref.set, + o:coq.gref.set. + +% [coq.gref.set.equal A B] tests A and B for equality +external pred coq.gref.set.equal i:coq.gref.set, i:coq.gref.set. + +% [coq.gref.set.subset A B] tests if A is a subset of B +external pred coq.gref.set.subset i:coq.gref.set, i:coq.gref.set. + +% [coq.gref.set.elements M L] L is M transformed into list +external pred coq.gref.set.elements i:coq.gref.set, o:list gref. + +% [coq.gref.set.cardinal M N] N is the number of elements of M +external pred coq.gref.set.cardinal i:coq.gref.set, o:int. + +% [coq.gref.set.filter M F M1] Filter M w.r.t. the predicate F +external pred coq.gref.set.filter i:coq.gref.set, i:gref -> prop, + o:coq.gref.set. + +% [coq.gref.set.map M F M1] Map M w.r.t. the predicate F +external pred coq.gref.set.map i:coq.gref.set, i:gref -> gref -> prop, + o:coq.gref.set. + +% CAVEAT: the type parameter of coq.gref.map must be a closed term + +kind coq.gref.map type -> type. + +% [coq.gref.map.empty M] The empty map +external pred coq.gref.map.empty o:coq.gref.map A. + +% [coq.gref.map.mem S M] Checks if S is bound in M +external pred coq.gref.map.mem i:gref, i:coq.gref.map A. + +% [coq.gref.map.add S V M M1] M1 is M where V is bound to S +external pred coq.gref.map.add i:gref, i:A, i:coq.gref.map A, + o:coq.gref.map A. + +% [coq.gref.map.remove S M M1] M1 is M where S is unbound +external pred coq.gref.map.remove i:gref, i:coq.gref.map A, + o:coq.gref.map A. + +% [coq.gref.map.find S M V] V is the binding of S in M +external pred coq.gref.map.find i:gref, i:coq.gref.map A, o:A. + +% [coq.gref.map.bindings M L] L is M transformed into an associative list +external pred coq.gref.map.bindings i:coq.gref.map A, + o:list (pair gref A). + +% [coq.gref.map.filter M F M1] Filter M w.r.t. the predicate F +external pred coq.gref.map.filter i:coq.gref.map A, i:gref -> A -> prop, + o:coq.gref.map A. + +% [coq.gref.map.map M F M1] Map M w.r.t. the predicate F +external pred coq.gref.map.map i:coq.gref.map A, + i:gref -> A -> B -> prop, o:coq.gref.map B. + +kind coq.univ.set type. + +% [coq.univ.set.empty A] The empty set +external pred coq.univ.set.empty o:coq.univ.set. + +% [coq.univ.set.mem Elem A] Checks if Elem is in a +external pred coq.univ.set.mem i:univ, i:coq.univ.set. + +% [coq.univ.set.add Elem A B] B is A union {Elem} +external pred coq.univ.set.add i:univ, i:coq.univ.set, o:coq.univ.set. + +% [coq.univ.set.remove Elem A B] B is A \ {Elem} +external pred coq.univ.set.remove i:univ, i:coq.univ.set, o:coq.univ.set. + +% [coq.univ.set.union A B X] X is A union B +external pred coq.univ.set.union i:coq.univ.set, i:coq.univ.set, + o:coq.univ.set. + +% [coq.univ.set.inter A B X] X is A intersection B +external pred coq.univ.set.inter i:coq.univ.set, i:coq.univ.set, + o:coq.univ.set. + +% [coq.univ.set.diff A B X] X is A \ B +external pred coq.univ.set.diff i:coq.univ.set, i:coq.univ.set, + o:coq.univ.set. + +% [coq.univ.set.equal A B] tests A and B for equality +external pred coq.univ.set.equal i:coq.univ.set, i:coq.univ.set. + +% [coq.univ.set.subset A B] tests if A is a subset of B +external pred coq.univ.set.subset i:coq.univ.set, i:coq.univ.set. + +% [coq.univ.set.elements M L] L is M transformed into list +external pred coq.univ.set.elements i:coq.univ.set, o:list univ. + +% [coq.univ.set.cardinal M N] N is the number of elements of M +external pred coq.univ.set.cardinal i:coq.univ.set, o:int. + +% [coq.univ.set.filter M F M1] Filter M w.r.t. the predicate F +external pred coq.univ.set.filter i:coq.univ.set, i:univ -> prop, + o:coq.univ.set. + +% [coq.univ.set.map M F M1] Map M w.r.t. the predicate F +external pred coq.univ.set.map i:coq.univ.set, i:univ -> univ -> prop, + o:coq.univ.set. + +% CAVEAT: the type parameter of coq.univ.map must be a closed term + +kind coq.univ.map type -> type. + +% [coq.univ.map.empty M] The empty map +external pred coq.univ.map.empty o:coq.univ.map A. + +% [coq.univ.map.mem S M] Checks if S is bound in M +external pred coq.univ.map.mem i:univ, i:coq.univ.map A. + +% [coq.univ.map.add S V M M1] M1 is M where V is bound to S +external pred coq.univ.map.add i:univ, i:A, i:coq.univ.map A, + o:coq.univ.map A. + +% [coq.univ.map.remove S M M1] M1 is M where S is unbound +external pred coq.univ.map.remove i:univ, i:coq.univ.map A, + o:coq.univ.map A. + +% [coq.univ.map.find S M V] V is the binding of S in M +external pred coq.univ.map.find i:univ, i:coq.univ.map A, o:A. + +% [coq.univ.map.bindings M L] L is M transformed into an associative list +external pred coq.univ.map.bindings i:coq.univ.map A, + o:list (pair univ A). + +% [coq.univ.map.filter M F M1] Filter M w.r.t. the predicate F +external pred coq.univ.map.filter i:coq.univ.map A, i:univ -> A -> prop, + o:coq.univ.map A. + +% [coq.univ.map.map M F M1] Map M w.r.t. the predicate F +external pred coq.univ.map.map i:coq.univ.map A, + i:univ -> A -> B -> prop, o:coq.univ.map B. + +kind coq.univ.variable.set type. + +% [coq.univ.variable.set.empty A] The empty set +external pred coq.univ.variable.set.empty o:coq.univ.variable.set. + +% [coq.univ.variable.set.mem Elem A] Checks if Elem is in a +external pred coq.univ.variable.set.mem i:univ.variable, + i:coq.univ.variable.set. + +% [coq.univ.variable.set.add Elem A B] B is A union {Elem} +external pred coq.univ.variable.set.add i:univ.variable, + i:coq.univ.variable.set, + o:coq.univ.variable.set. + +% [coq.univ.variable.set.remove Elem A B] B is A \ {Elem} +external pred coq.univ.variable.set.remove i:univ.variable, + i:coq.univ.variable.set, + o:coq.univ.variable.set. + +% [coq.univ.variable.set.union A B X] X is A union B +external pred coq.univ.variable.set.union i:coq.univ.variable.set, + i:coq.univ.variable.set, + o:coq.univ.variable.set. + +% [coq.univ.variable.set.inter A B X] X is A intersection B +external pred coq.univ.variable.set.inter i:coq.univ.variable.set, + i:coq.univ.variable.set, + o:coq.univ.variable.set. + +% [coq.univ.variable.set.diff A B X] X is A \ B +external pred coq.univ.variable.set.diff i:coq.univ.variable.set, + i:coq.univ.variable.set, + o:coq.univ.variable.set. + +% [coq.univ.variable.set.equal A B] tests A and B for equality +external pred coq.univ.variable.set.equal i:coq.univ.variable.set, + i:coq.univ.variable.set. + +% [coq.univ.variable.set.subset A B] tests if A is a subset of B +external pred coq.univ.variable.set.subset i:coq.univ.variable.set, + i:coq.univ.variable.set. + +% [coq.univ.variable.set.elements M L] L is M transformed into list +external pred coq.univ.variable.set.elements i:coq.univ.variable.set, + o:list univ.variable. + +% [coq.univ.variable.set.cardinal M N] N is the number of elements of M +external pred coq.univ.variable.set.cardinal i:coq.univ.variable.set, + o:int. + +% [coq.univ.variable.set.filter M F M1] Filter M w.r.t. the predicate F +external pred coq.univ.variable.set.filter i:coq.univ.variable.set, + i:univ.variable -> prop, + o:coq.univ.variable.set. + +% [coq.univ.variable.set.map M F M1] Map M w.r.t. the predicate F +external pred coq.univ.variable.set.map i:coq.univ.variable.set, + i:univ.variable -> univ.variable -> prop, + o:coq.univ.variable.set. + +% CAVEAT: the type parameter of coq.univ.variable.map must be a closed +% term + +kind coq.univ.variable.map type -> type. + +% [coq.univ.variable.map.empty M] The empty map +external pred coq.univ.variable.map.empty o:coq.univ.variable.map A. + +% [coq.univ.variable.map.mem S M] Checks if S is bound in M +external pred coq.univ.variable.map.mem i:univ.variable, + i:coq.univ.variable.map A. + +% [coq.univ.variable.map.add S V M M1] M1 is M where V is bound to S +external pred coq.univ.variable.map.add i:univ.variable, i:A, + i:coq.univ.variable.map A, + o:coq.univ.variable.map A. + +% [coq.univ.variable.map.remove S M M1] M1 is M where S is unbound +external pred coq.univ.variable.map.remove i:univ.variable, + i:coq.univ.variable.map A, + o:coq.univ.variable.map A. + +% [coq.univ.variable.map.find S M V] V is the binding of S in M +external pred coq.univ.variable.map.find i:univ.variable, + i:coq.univ.variable.map A, o:A. + +% [coq.univ.variable.map.bindings M L] L is M transformed into an +% associative list +external pred coq.univ.variable.map.bindings i:coq.univ.variable.map A, + o:list (pair univ.variable A). + +% [coq.univ.variable.map.filter M F M1] Filter M w.r.t. the predicate F +external pred coq.univ.variable.map.filter i:coq.univ.variable.map A, + i:univ.variable -> A -> prop, + o:coq.univ.variable.map A. + +% [coq.univ.variable.map.map M F M1] Map M w.r.t. the predicate F +external pred coq.univ.variable.map.map i:coq.univ.variable.map A, + i:univ.variable -> A -> B -> prop, + o:coq.univ.variable.map B. + +% Coq box types for pretty printing: +% - Vertical block: each break leads to a new line +% - Horizontal block: no line breaking +% - Horizontal-vertical block: same as Vertical block, except if this block +% is small enough to fit on a single line in which case it is the same +% as a Horizontal block +% - Horizontal or Vertical block: breaks lead to new line only when +% necessary to print the content of the block (the contents flow +% inside the box) +kind coq.pp.box type. +type coq.pp.v int -> coq.pp.box. +type coq.pp.h coq.pp.box. +type coq.pp.hv int -> coq.pp.box. +type coq.pp.hov int -> coq.pp.box. + +% Coq box model for pretty printing. Items: +% - empty +% - spc: a spacem, also a breaking hint +% - str: a non breakable string +% - brk L I: a breaking hint of a given length L contributing I spaces to +% indentation when taken +% - glue: puts things together +% - box B: a box with automatic line breaking according to B +% - comment: embedded \\n are turned into nl (see below) +% - tag: ignored +% - nl: break the line (should not be used) +kind coq.pp type. +type coq.pp.empty coq.pp. +type coq.pp.spc coq.pp. +type coq.pp.str string -> coq.pp. +type coq.pp.brk int -> int -> coq.pp. +type coq.pp.glue list coq.pp -> coq.pp. +type coq.pp.box coq.pp.box -> list coq.pp -> coq.pp. +type coq.pp.comment list string -> coq.pp. +type coq.pp.tag string -> coq.pp -> coq.pp. +type coq.pp.nl coq.pp. + +% [coq.pp->string B S] Prints a pp.t box expression B to a string S +% Supported attributes: +% - @ppwidth! N (default 80, max line length) +external pred coq.pp->string i:coq.pp, o:string. + + + + diff --git a/builtin-doc/dune b/builtin-doc/dune new file mode 100644 index 000000000..15e577fa9 --- /dev/null +++ b/builtin-doc/dune @@ -0,0 +1,20 @@ +(executable + (name gen_doc) + (libraries elpi_plugin)) + +(rule + (targets + coq-builtin.elpi + coq-builtin-synterp.elpi + elpi-builtin.elpi) + (deps gen_doc.exe) + (mode promote) + (action (run ./gen_doc.exe))) + +(install + (files + coq-builtin.elpi + coq-builtin-synterp.elpi + elpi-builtin.elpi) + (section doc) + (package coq-elpi)) diff --git a/builtin-doc/elpi-builtin.elpi b/builtin-doc/elpi-builtin.elpi new file mode 100644 index 000000000..5049e2d6c --- /dev/null +++ b/builtin-doc/elpi-builtin.elpi @@ -0,0 +1,1324 @@ +% Generated file, do not edit + +% == Core builtins ===================================== + +% -- Logic -- + +pred true. + +true. + +pred fail. + +pred false. + +external pred (=) o:A, o:A. % unification + +typeabbrev int (ctype "int"). + + +typeabbrev string (ctype "string"). + + +typeabbrev float (ctype "float"). + + +pred (;) o:prop, o:prop. + +(A ; _) :- A. + +(_ ; B) :- B. + +type (:-) prop -> prop -> prop. + +type (:-) prop -> list prop -> prop. + +type (,) variadic prop prop. + +type uvar A. + +type (as) A -> A -> A. + +type (=>) prop -> prop -> prop. + +type (=>) list prop -> prop -> prop. + +% -- Control -- + +external pred !. % The cut operator + +pred not i:prop. + +not X :- X, !, fail. + +not _. + +% [declare_constraint C Key1 Key2...] declares C blocked +% on Key1 Key2 ... (variables, or lists thereof). +external type declare_constraint any -> any -> variadic any prop. + +external pred print_constraints. % prints all constraints + +% [halt ...] halts the program and print the terms +external type halt variadic any prop. + +pred stop. + +stop :- halt. + +% -- Evaluation -- + +pred (is) o:A, i:A. + +X is Y :- calc Y X. + +% [calc Expr Out] unifies Out with the value of Expr. It can be used in +% tandem with spilling, eg [f {calc (N + 1)}] +external pred calc i:A, o:A. + +% --- Operators --- + +type (-) A -> A -> A. + +type (i-) int -> int -> int. + +type (r-) float -> float -> float. + +type (+) int -> int -> int. +type (+) float -> float -> float. + +type (i+) int -> int -> int. + +type (r+) float -> float -> float. + +type (*) int -> int -> int. +type (*) float -> float -> float. + +type (/) float -> float -> float. + +type (mod) int -> int -> int. + +type (div) int -> int -> int. + +type (^) string -> string -> string. + +type (~) int -> int. +type (~) float -> float. + +type (i~) int -> int. + +type (r~) float -> float. + +type abs int -> int. +type abs float -> float. + +type iabs int -> int. + +type rabs float -> float. + +type max int -> int -> int. +type max float -> float -> float. + +type min int -> int -> int. +type min float -> float -> float. + +type sqrt float -> float. + +type sin float -> float. + +type cos float -> float. + +type arctan float -> float. + +type ln float -> float. + +type int_to_real int -> float. + +type floor float -> int. + +type ceil float -> int. + +type truncate float -> int. + +type size string -> int. + +type chr int -> string. + +type rhc string -> int. + +type string_to_int string -> int. + +type int_to_string int -> string. + +type substring string -> int -> int -> string. + +type real_to_string float -> string. + +% -- Arithmetic tests -- + +% [lt_ X Y] checks if X < Y. Works for string, int and float +external pred lt_ i:A, i:A. + +% [gt_ X Y] checks if X > Y. Works for string, int and float +external pred gt_ i:A, i:A. + +% [le_ X Y] checks if X =< Y. Works for string, int and float +external pred le_ i:A, i:A. + +% [ge_ X Y] checks if X >= Y. Works for string, int and float +external pred ge_ i:A, i:A. + +type (<), (>), (=<), (>=) A -> A -> prop. + +X > Y :- gt_ X Y. + +X < Y :- lt_ X Y. + +X =< Y :- le_ X Y. + +X >= Y :- ge_ X Y. + +type (i<), (i>), (i=<), (i>=) int -> int -> prop. + +X i< Y :- lt_ X Y. + +X i> Y :- gt_ X Y. + +X i=< Y :- le_ X Y. + +X i>= Y :- ge_ X Y. + +type (r<), (r>), (r=<), (r>=) float -> float -> prop. + +X r< Y :- lt_ X Y. + +X r> Y :- gt_ X Y. + +X r=< Y :- le_ X Y. + +X r>= Y :- ge_ X Y. + +type (s<), (s>), (s=<), (s>=) string -> string -> prop. + +X s< Y :- lt_ X Y. + +X s> Y :- gt_ X Y. + +X s=< Y :- le_ X Y. + +X s>= Y :- ge_ X Y. + +% -- Standard data types (supported in the FFI) -- + +kind list type -> type. + +type (::) X -> list X -> list X. + +type ([]) list X. + +% Boolean values: tt and ff since true and false are predicates +kind bool type. +type tt bool. +type ff bool. + +% Pair: the constructor is pr, since ',' is for conjunction +kind pair type -> type -> type. +type pr A -> B -> pair A B. + +pred fst i:pair A B, o:A. + +fst (pr A _) A. + +pred snd i:pair A B, o:B. + +snd (pr _ B) B. + +% The option type (aka Maybe) +kind option type -> type. +type none option A. +type some A -> option A. + +% Result of a comparison +kind cmp type. +type eq cmp. +type lt cmp. +type gt cmp. + +% Used in builtin variants that return Coq's error rather than failing +kind diagnostic type. +type ok diagnostic. % Success +type error string -> diagnostic. % Failure + +% == Elpi builtins ===================================== + +% [dprint ...] prints raw terms (debugging) +external type dprint variadic any prop. + +% [print ...] prints terms +external type print variadic any prop. + +% Deprecated, use trace.counter +pred counter i:string, o:int. +counter C N :- trace.counter C N. + +% [quote_syntax FileName QueryText QuotedProgram QuotedQuery] quotes the +% program from FileName and the QueryText. See elpi-quoted_syntax.elpi for +% the syntax tree +external pred quote_syntax i:string, i:string, o:list A, o:A. + +typeabbrev loc (ctype "Loc.t"). + + +% [loc.fields Loc File StartChar StopChar Line LineStartsAtChar] Decomposes +% a loc into its fields +external pred loc.fields i:loc, o:string, o:int, o:int, o:int, o:int. + +% == Regular Expressions ===================================== + +% [rex.match Rex Subject] checks if Subject matches Rex. Matching is based +% on OCaml's Str library +external pred rex.match i:string, i:string. + +% [rex.replace Rex Replacement Subject Out] Out is obtained by replacing all +% occurrences of Rex with Replacement in Subject. See also OCaml's +% Str.global_replace +external pred rex.replace i:string, i:string, i:string, o:string. + +% [rex.split Rex Subject Out] Out is obtained by splitting Subject at all +% occurrences of Rex. See also OCaml's Str.split +external pred rex.split i:string, i:string, o:list string. + +% Deprecated, use rex.match +pred rex_match i:string, i:string. +rex_match Rx S :- rex.match Rx S. + +% Deprecated, use rex.replace +pred rex_replace i:string, i:string, i:string, o:string. +rex_replace Rx R S O :- rex.replace Rx R S O. + +% Deprecated, use rex.split +pred rex_split i:string, i:string, o:list string. +rex_split Rx S L :- rex.split Rx S L. + +% == Elpi nonlogical builtins ===================================== + +% Opaque ML data types +kind ctyp type. +type ctype string -> ctyp. + +% [var V ...] checks if the term V is a variable. When used with tree +% arguments it relates an applied variable with its head and argument list. +external type var any -> variadic any prop. + +% [prune V L] V is pruned to L (V is unified with a variable that only sees +% the list of names L) +external pred prune o:any, i:list any. + +% [distinct_names L] checks if L is a list of distinct names. If L is the +% scope of a unification variable (its arguments, as per var predicate) then +% distinct_names L checks that such variable is in the Miller pattern +% fragment (L_\lambda) +external pred distinct_names i:list any. + +% [same_var V1 V2] checks if the two terms V1 and V2 are the same variable, +% ignoring the arguments of the variables +external pred same_var i:A, i:A. + +% [same_term T1 T2] checks if the two terms T1 and T2 are syntactically +% equal (no unification). It behaves differently than same_var since it +% recursively compares the arguments of the variables +external pred same_term i:A, i:A. + + +% Infix notation for same_term +pred (==) i:A, i:A. +X == Y :- same_term X Y. + + +% [cmp_term A B Cmp] Compares A and B. Only works if A and B are ground. +external pred cmp_term i:any, i:any, o:cmp. + +% [name T ...] checks if T is a eigenvariable. When used with tree arguments +% it relates an applied name with its head and argument list. +external type name any -> variadic any prop. + +% [constant T ...] checks if T is a (global) constant. When used with tree +% arguments it relates an applied constant with its head and argument list. +external type constant any -> variadic any prop. + +external pred names % generates the list of eigenvariable + o:list any. % list of eigenvariables in order of age (young first) + +external pred occurs % checks if the atom occurs in the term + i:any, % an atom, that is a global constant or a bound name (aka eigenvariable) + i:any. % a term + +% [closed_term T] unify T with a variable that has no eigenvariables in +% scope +external pred closed_term o:any. + +% [ground_term T] Checks if T contains unification variables +external pred ground_term i:any. + +% [is_cdata T Ctype] checks if T is primitive of type Ctype, eg (ctype +% "int") +external pred is_cdata i:any, o:ctyp. + +pred primitive? i:A, i:string. + +primitive? X S :- is_cdata X (ctype S). + +% [new_int N] unifies N with a different int every time it is called. Values +% of N are guaranteed to be incresing. +external pred new_int o:int. + +% [findall_solution P L] finds all the solved instances of P and puts them +% in L +% in the order in which they are found. Instances can contain +% eigenvariables +% and unification variables. + +external pred findall_solutions i:prop, o:list prop. + +% Holds data across bracktracking; can only contain closed terms +typeabbrev safe (ctype "safe"). + + +% [new_safe Safe] creates a safe: a store that persists across backtracking +external pred new_safe o:safe. + +% [stash_in_safe Safe Data] stores Data in the Safe +external pred stash_in_safe i:safe, i:A. + +% [open_safe Safe Data] retrieves the Data stored in Safe +external pred open_safe i:safe, o:list A. + + +% [if C T E] picks the first success of C then runs T (never E). +% if C has no success it runs E. +pred if i:prop, i:prop, i:prop. +if B T _ :- B, !, T. +if _ _ E :- E. + +% [if2 C1 B1 C2 B2 E] like if but with 2 then branches (and one else branch). +pred if2 i:prop, i:prop, i:prop, i:prop, i:prop. +if2 G1 P1 _ _ _ :- G1, !, P1. +if2 _ _ G2 P2 _ :- G2, !, P2. +if2 _ _ _ _ E :- !, E. + +% [random.init Seed] Initialize OCaml's PRNG with the given Seed +external pred random.init i:int. + +% [random.self_init] Initialize OCaml's PRNG with some seed +external pred random.self_init . + +% [random.int Bound N] unifies N with a random int between 0 and Bound +% (excluded) +external pred random.int i:int, o:int. + +#line 0 "builtin_stdlib.elpi" +% == stdlib ======================================================= + +% Conventions: +% - all predicates declare a mode with some input arguments, unless... +% - predicates whose name ends with R are relations (work in any direction, +% that is all arguments are in output mode) +% - predicates whose name ends with ! do contain a cut and generate only the +% first result +% - all errors given by this library end up calling fatal-error[-w-data], +% override it in order to handle them differently +% - all debug prints by this library end up calling debug-print, override it +% in order to handle them differently + +namespace std { + +pred fatal-error i:string. +:name "default-fatal-error" +fatal-error Msg :- halt Msg. + +pred fatal-error-w-data i:string, i:A. +:name "default-fatal-error-w-data" +fatal-error-w-data Msg Data :- halt Msg ":" Data. + +pred debug-print i:string, i:A. +:name "default-debug-print" +debug-print Msg Data :- print Msg Data. + +% -- Errors, Debugging, Hacks -- + +pred ignore-failure! i:prop. +ignore-failure! P :- P, !. +ignore-failure! _. + +% [assert! C M] takes the first success of C or fails with message M +pred assert! i:prop, i:string. +assert! Cond Msg :- (Cond ; fatal-error-w-data Msg Cond), !. + +% [assert-ok! C M] like assert! but the last argument of the predicate must +% be a diagnostic that is printed after M in case it is not ok +pred assert-ok! i:(diagnostic -> prop), i:string. +assert-ok! Cond Msg :- Cond Diagnostic, !, (Diagnostic = ok ; Diagnostic = error S, fatal-error-w-data Msg S), !. +assert-ok! _ Msg :- fatal-error-w-data Msg "no diagnostic returned". + +% [spy P] traces the call to P, printing all success and the final failure +pred spy i:prop. +spy P :- trace.counter "run" NR, if (not(NR = 0)) (debug-print "run=" NR) true, + debug-print "----<<---- enter: " P, + P, + debug-print "---->>---- exit: " P. +spy P :- debug-print "---->>---- fail: " P, fail. + +% [spy! P] traces the first call to P without leaving a choice point +pred spy! i:prop. +spy! P :- trace.counter "run" NR, if (not(NR = 0)) (debug-print "run=" NR) true, + debug-print "----<<---- enter: " P, + P, + debug-print "---->>---- exit: " P, !. +spy! P :- debug-print "---->>---- fail: " P, fail. + +% to silence the type checker +pred unsafe-cast o:A, o:B. +unsafe-cast X X. + +% -- List processing -- + +pred length i:list A, o:int. +length [_|L] N :- length L N1, N is N1 + 1. +length [] 0. + +pred rev i:list A, o:list A. +rev L RL :- rev.aux L [] RL. +rev.aux [X|XS] ACC R :- rev.aux XS [X|ACC] R. +rev.aux [] L L. + +pred last i:list A, o:A. +last [] _ :- fatal-error "last on empty list". +last [X] X :- !. +last [_|XS] R :- last XS R. + +pred append i:list A, i:list A, o:list A. +append [X|XS] L [X|L1] :- append XS L L1 . +append [] L L . + +pred appendR o:list A, o:list A, o:list A. +appendR [] L L. +appendR [X|XS] L [X|L1] :- appendR XS L L1. + +pred take i:int, i:list A, o:list A. +take 0 _ [] :- !. +take N [X|XS] [X|L] :- !, N1 is N - 1, take N1 XS L. +take _ _ _ :- fatal-error "take run out of list items". + +pred take-last i:int, i:list A, o:list A. +take-last N L R :- + length L M, + D is M - N, + drop D L R. + +pred drop i:int, i:list A, o:list A. +drop 0 L L :- !. +drop N [_|XS] L :- !, N1 is N - 1, drop N1 XS L. +drop _ _ _ :- fatal-error "drop run out of list items". + +pred drop-last i:int, i:list A, o:list A. +drop-last N L R :- + length L M, I is M - N, take I L R. + +pred split-at i:int, i:list A, o:list A, o:list A. +split-at 0 L [] L :- !. +split-at N [X|XS] [X|LN] LM :- !, N1 is N - 1, split-at N1 XS LN LM. +split-at _ _ _ _ :- fatal-error "split-at run out of list items". + +pred fold i:list B, i:A, i:(B -> A -> A -> prop), o:A. +fold [] A _ A. +fold [X|XS] A F R :- F X A A1, fold XS A1 F R. + +pred fold-right i:list B, i:A, i:(B -> A -> A -> prop), o:A. +fold-right [] A _ A. +fold-right [X|XS] A F R :- fold-right XS A F A', F X A' R. + +pred fold2 i:list C, i:list B, i:A, i:(C -> B -> A -> A -> prop), o:A. +fold2 [] [_|_] _ _ _ :- fatal-error "fold2 on lists of different length". +fold2 [_|_] [] _ _ _ :- fatal-error "fold2 on lists of different length". +fold2 [] [] A _ A. +fold2 [X|XS] [Y|YS] A F R :- F X Y A A1, fold2 XS YS A1 F R. + +pred map i:list A, i:(A -> B -> prop), o:list B. +map [] _ []. +map [X|XS] F [Y|YS] :- F X Y, map XS F YS. + +pred map-i i:list A, i:(int -> A -> B -> prop), o:list B. +map-i L F R :- map-i.aux L 0 F R. +map-i.aux [] _ _ []. +map-i.aux [X|XS] N F [Y|YS] :- F N X Y, M is N + 1, map-i.aux XS M F YS. + +pred map-filter i:list A, i:(A -> B -> prop), o:list B. +map-filter [] _ []. +map-filter [X|XS] F [Y|YS] :- F X Y, !, map-filter XS F YS. +map-filter [_|XS] F YS :- map-filter XS F YS. + +:index(1 1) +pred map2 i:list A, i:list B, i:(A -> B -> C -> prop), o:list C. +map2 [] [_|_] _ _ :- fatal-error "map2 on lists of different length". +map2 [_|_] [] _ _ :- fatal-error "map2 on lists of different length". +map2 [] [] _ []. +map2 [X|XS] [Y|YS] F [Z|ZS] :- F X Y Z, map2 XS YS F ZS. + +pred map2-filter i:list A, i:list B, i:(A -> B -> C -> prop), o:list C. +map2-filter [] [_|_] _ _ :- fatal-error "map2-filter on lists of different length". +map2-filter [_|_] [] _ _ :- fatal-error "map2-filter on lists of different length". +map2-filter [] [] _ []. +map2-filter [X|XS] [Y|YS] F [Z|ZS] :- F X Y Z, !, map2-filter XS YS F ZS. +map2-filter [_|XS] [_|YS] F ZS :- map2-filter XS YS F ZS. + +pred map-ok i:list A, i:(A -> B -> diagnostic -> prop), o:list A, o:diagnostic. +map-ok [X|L] P [Y|YS] S :- P X Y S0, if (S0 = ok) (map-ok L P YS S) (S = S0). +map-ok [] _ [] ok. + +pred fold-map i:list A, i:B, i:(A -> B -> C -> B -> prop), o:list C, o:B. +fold-map [] A _ [] A. +fold-map [X|XS] A F [Y|YS] A2 :- F X A Y A1, fold-map XS A1 F YS A2. + +pred omap i:option A, i:(A -> B -> prop), o:option B. +omap none _ none. +omap (some X) F (some Y) :- F X Y. + +% [nth N L X] picks in X the N-th element of L (L must be of length > N) +pred nth i:int, i:list A, o:A. +nth 0 [X|_ ] R :- !, X = R. +nth N [_|XS] R :- N > 0, !, N1 is N - 1, nth N1 XS R. +nth N _ _ :- N < 0, !, fatal-error "nth got a negative index". +nth _ _ _ :- fatal-error "nth run out of list items". + +% [lookup L K V] sees L as a map from K to V +pred lookup i:list (pair A B), i:A, o:B. +lookup [pr X Y|_] X Y. +lookup [_|LS] X Y :- lookup LS X Y. + +% [lookup! L K V] sees L as a map from K to V, stops at the first binding +pred lookup! i:list (pair A B), i:A, o:B. +lookup! [pr X Y|_] X Y :- !. +lookup! [_|LS] X Y :- lookup! LS X Y. + +% [mem! L X] succeeds once if X occurs inside L +pred mem! i:list A, o:A. +mem! [X|_] X :- !. +mem! [_|L] X :- mem! L X. + +% [mem L X] succeeds every time if X occurs inside L +pred mem i:list A, o:A. +mem [X|_] X. +mem [_|L] X :- mem L X. + +pred exists i:list A, i:(A -> prop). +exists [X|_] P :- P X. +exists [_|L] P :- exists L P. + +pred exists2 i:list A, i:list B, i:(A -> B -> prop). +exists2 [] [_|_] _ :- fatal-error "exists2 on lists of different length". +exists2 [_|_] [] _ :- fatal-error "exists2 on lists of different length". +exists2 [X|_] [Y|_] P :- P X Y. +exists2 [_|L] [_|M] P :- exists2 L M P. + +pred forall i:list A, i:(A -> prop). +forall [] _. +forall [X|L] P :- P X, forall L P. + +pred forall-ok i:list A, i:(A -> diagnostic -> prop), o:diagnostic. +forall-ok [X|L] P S :- P X S0, if (S0 = ok) (forall-ok L P S) (S = S0). +forall-ok [] _ ok. + +pred forall2 i:list A, i:list B, i:(A -> B -> prop). +forall2 [] [_|_] _ :- fatal-error "forall2 on lists of different length". +forall2 [_|_] [] _ :- fatal-error "forall2 on lists of different length". +forall2 [X|XS] [Y|YS] P :- P X Y, forall2 XS YS P. +forall2 [] [] _. + +pred filter i:list A, i:(A -> prop), o:list A. +filter [] _ []. +filter [X|L] P R :- if (P X) (R = X :: L1) (R = L1), filter L P L1. + +pred zip i:list A, i:list B, o:list (pair A B). +zip [_|_] [] _ :- fatal-error "zip on lists of different length". +zip [] [_|_] _ :- fatal-error "zip on lists of different length". +zip [X|LX] [Y|LY] [pr X Y|LR] :- zip LX LY LR. +zip [] [] []. + +pred unzip i:list (pair A B), o:list A, o:list B. +unzip [] [] []. +unzip [pr X Y|L] [X|LX] [Y|LY] :- unzip L LX LY. + +pred flatten i:list (list A), o:list A. +flatten [X|LS] R :- flatten LS LS', append X LS' R. +flatten [] []. + +pred null i:list A. +null []. + +pred iota i:int, o:list int. +iota N L :- iota.aux 0 N L. +iota.aux X X [] :- !. +iota.aux N X [N|R] :- M is N + 1, iota.aux M X R. + +% [intersperse X L R] R is [L0, X, ..., X, LN] +:index(_ 1) +pred intersperse i:A, i:list A, o:list A. +intersperse _ [] []. +intersperse _ [X] [X] :- !. +intersperse Sep [X|XS] [X,Sep|YS] :- intersperse Sep XS YS. + +% -- Misc -- + +pred flip i:(A -> B -> prop), i:B, i:A. +flip P X Y :- P Y X. + +pred time i:prop, o:float. +time P T :- gettimeofday Before, P, gettimeofday After, T is After - Before. + +pred do! i:list prop. +do! []. +do! [P|PS] :- P, !, do! PS. + +:index(_ 1) +pred do-ok! o:diagnostic, i:list (diagnostic -> prop). +do-ok! ok []. +do-ok! S [P|PS] :- P S0, !, if (S0 = ok) (do-ok! S PS) (S = S0). + +pred lift-ok i:prop, i:string, o:diagnostic. +lift-ok P Msg R :- (P, R = ok; R = error Msg). + +pred spy-do! i:list prop. +spy-do! L :- map L (x\y\y = spy x) L1, do! L1. + +pred while-ok-do! i:diagnostic, i:list (diagnostic -> prop), o:diagnostic. +while-ok-do! (error _ as E) _ E. +while-ok-do! ok [] ok. +while-ok-do! ok [P|PS] R :- P C, !, while-ok-do! C PS R. + +pred any->string i:A, o:string. +any->string X Y :- term_to_string X Y. + +pred max i:A, i:A, o:A. +max N M N :- N >= M, !. +max _ M M. + +% [findall P L] L is the list [P1,P2,P3..] where each Pi is a solution to P. +pred findall i:prop, o:list prop. +findall P L :- findall_solutions P L. + +} + +% [std.string.concat Separator Items Result] concatenates Items +% interspersing Separator +external pred std.string.concat i:string, i:list string, o:string. + +% CAVEAT: the type parameter of std.string.map must be a closed term + +kind std.string.map type -> type. + +% [std.string.map.empty M] The empty map +external pred std.string.map.empty o:std.string.map A. + +% [std.string.map.mem S M] Checks if S is bound in M +external pred std.string.map.mem i:string, i:std.string.map A. + +% [std.string.map.add S V M M1] M1 is M where V is bound to S +external pred std.string.map.add i:string, i:A, i:std.string.map A, + o:std.string.map A. + +% [std.string.map.remove S M M1] M1 is M where S is unbound +external pred std.string.map.remove i:string, i:std.string.map A, + o:std.string.map A. + +% [std.string.map.find S M V] V is the binding of S in M +external pred std.string.map.find i:string, i:std.string.map A, o:A. + +% [std.string.map.bindings M L] L is M transformed into an associative list +external pred std.string.map.bindings i:std.string.map A, + o:list (pair string A). + +% [std.string.map.filter M F M1] Filter M w.r.t. the predicate F +external pred std.string.map.filter i:std.string.map A, + i:string -> A -> prop, + o:std.string.map A. + +% [std.string.map.map M F M1] Map M w.r.t. the predicate F +external pred std.string.map.map i:std.string.map A, + i:string -> A -> B -> prop, + o:std.string.map B. + +% CAVEAT: the type parameter of std.int.map must be a closed term + +kind std.int.map type -> type. + +% [std.int.map.empty M] The empty map +external pred std.int.map.empty o:std.int.map A. + +% [std.int.map.mem S M] Checks if S is bound in M +external pred std.int.map.mem i:int, i:std.int.map A. + +% [std.int.map.add S V M M1] M1 is M where V is bound to S +external pred std.int.map.add i:int, i:A, i:std.int.map A, + o:std.int.map A. + +% [std.int.map.remove S M M1] M1 is M where S is unbound +external pred std.int.map.remove i:int, i:std.int.map A, o:std.int.map A. + +% [std.int.map.find S M V] V is the binding of S in M +external pred std.int.map.find i:int, i:std.int.map A, o:A. + +% [std.int.map.bindings M L] L is M transformed into an associative list +external pred std.int.map.bindings i:std.int.map A, o:list (pair int A). + +% [std.int.map.filter M F M1] Filter M w.r.t. the predicate F +external pred std.int.map.filter i:std.int.map A, i:int -> A -> prop, + o:std.int.map A. + +% [std.int.map.map M F M1] Map M w.r.t. the predicate F +external pred std.int.map.map i:std.int.map A, i:int -> A -> B -> prop, + o:std.int.map B. + +% CAVEAT: the type parameter of std.loc.map must be a closed term + +kind std.loc.map type -> type. + +% [std.loc.map.empty M] The empty map +external pred std.loc.map.empty o:std.loc.map A. + +% [std.loc.map.mem S M] Checks if S is bound in M +external pred std.loc.map.mem i:loc, i:std.loc.map A. + +% [std.loc.map.add S V M M1] M1 is M where V is bound to S +external pred std.loc.map.add i:loc, i:A, i:std.loc.map A, + o:std.loc.map A. + +% [std.loc.map.remove S M M1] M1 is M where S is unbound +external pred std.loc.map.remove i:loc, i:std.loc.map A, o:std.loc.map A. + +% [std.loc.map.find S M V] V is the binding of S in M +external pred std.loc.map.find i:loc, i:std.loc.map A, o:A. + +% [std.loc.map.bindings M L] L is M transformed into an associative list +external pred std.loc.map.bindings i:std.loc.map A, o:list (pair loc A). + +% [std.loc.map.filter M F M1] Filter M w.r.t. the predicate F +external pred std.loc.map.filter i:std.loc.map A, i:loc -> A -> prop, + o:std.loc.map A. + +% [std.loc.map.map M F M1] Map M w.r.t. the predicate F +external pred std.loc.map.map i:std.loc.map A, i:loc -> A -> B -> prop, + o:std.loc.map B. + +kind std.string.set type. + +% [std.string.set.empty A] The empty set +external pred std.string.set.empty o:std.string.set. + +% [std.string.set.mem Elem A] Checks if Elem is in a +external pred std.string.set.mem i:string, i:std.string.set. + +% [std.string.set.add Elem A B] B is A union {Elem} +external pred std.string.set.add i:string, i:std.string.set, + o:std.string.set. + +% [std.string.set.remove Elem A B] B is A \ {Elem} +external pred std.string.set.remove i:string, i:std.string.set, + o:std.string.set. + +% [std.string.set.union A B X] X is A union B +external pred std.string.set.union i:std.string.set, i:std.string.set, + o:std.string.set. + +% [std.string.set.inter A B X] X is A intersection B +external pred std.string.set.inter i:std.string.set, i:std.string.set, + o:std.string.set. + +% [std.string.set.diff A B X] X is A \ B +external pred std.string.set.diff i:std.string.set, i:std.string.set, + o:std.string.set. + +% [std.string.set.equal A B] tests A and B for equality +external pred std.string.set.equal i:std.string.set, i:std.string.set. + +% [std.string.set.subset A B] tests if A is a subset of B +external pred std.string.set.subset i:std.string.set, i:std.string.set. + +% [std.string.set.elements M L] L is M transformed into list +external pred std.string.set.elements i:std.string.set, o:list string. + +% [std.string.set.cardinal M N] N is the number of elements of M +external pred std.string.set.cardinal i:std.string.set, o:int. + +% [std.string.set.filter M F M1] Filter M w.r.t. the predicate F +external pred std.string.set.filter i:std.string.set, i:string -> prop, + o:std.string.set. + +% [std.string.set.map M F M1] Map M w.r.t. the predicate F +external pred std.string.set.map i:std.string.set, + i:string -> string -> prop, + o:std.string.set. + +kind std.int.set type. + +% [std.int.set.empty A] The empty set +external pred std.int.set.empty o:std.int.set. + +% [std.int.set.mem Elem A] Checks if Elem is in a +external pred std.int.set.mem i:int, i:std.int.set. + +% [std.int.set.add Elem A B] B is A union {Elem} +external pred std.int.set.add i:int, i:std.int.set, o:std.int.set. + +% [std.int.set.remove Elem A B] B is A \ {Elem} +external pred std.int.set.remove i:int, i:std.int.set, o:std.int.set. + +% [std.int.set.union A B X] X is A union B +external pred std.int.set.union i:std.int.set, i:std.int.set, + o:std.int.set. + +% [std.int.set.inter A B X] X is A intersection B +external pred std.int.set.inter i:std.int.set, i:std.int.set, + o:std.int.set. + +% [std.int.set.diff A B X] X is A \ B +external pred std.int.set.diff i:std.int.set, i:std.int.set, + o:std.int.set. + +% [std.int.set.equal A B] tests A and B for equality +external pred std.int.set.equal i:std.int.set, i:std.int.set. + +% [std.int.set.subset A B] tests if A is a subset of B +external pred std.int.set.subset i:std.int.set, i:std.int.set. + +% [std.int.set.elements M L] L is M transformed into list +external pred std.int.set.elements i:std.int.set, o:list int. + +% [std.int.set.cardinal M N] N is the number of elements of M +external pred std.int.set.cardinal i:std.int.set, o:int. + +% [std.int.set.filter M F M1] Filter M w.r.t. the predicate F +external pred std.int.set.filter i:std.int.set, i:int -> prop, + o:std.int.set. + +% [std.int.set.map M F M1] Map M w.r.t. the predicate F +external pred std.int.set.map i:std.int.set, i:int -> int -> prop, + o:std.int.set. + +kind std.loc.set type. + +% [std.loc.set.empty A] The empty set +external pred std.loc.set.empty o:std.loc.set. + +% [std.loc.set.mem Elem A] Checks if Elem is in a +external pred std.loc.set.mem i:loc, i:std.loc.set. + +% [std.loc.set.add Elem A B] B is A union {Elem} +external pred std.loc.set.add i:loc, i:std.loc.set, o:std.loc.set. + +% [std.loc.set.remove Elem A B] B is A \ {Elem} +external pred std.loc.set.remove i:loc, i:std.loc.set, o:std.loc.set. + +% [std.loc.set.union A B X] X is A union B +external pred std.loc.set.union i:std.loc.set, i:std.loc.set, + o:std.loc.set. + +% [std.loc.set.inter A B X] X is A intersection B +external pred std.loc.set.inter i:std.loc.set, i:std.loc.set, + o:std.loc.set. + +% [std.loc.set.diff A B X] X is A \ B +external pred std.loc.set.diff i:std.loc.set, i:std.loc.set, + o:std.loc.set. + +% [std.loc.set.equal A B] tests A and B for equality +external pred std.loc.set.equal i:std.loc.set, i:std.loc.set. + +% [std.loc.set.subset A B] tests if A is a subset of B +external pred std.loc.set.subset i:std.loc.set, i:std.loc.set. + +% [std.loc.set.elements M L] L is M transformed into list +external pred std.loc.set.elements i:std.loc.set, o:list loc. + +% [std.loc.set.cardinal M N] N is the number of elements of M +external pred std.loc.set.cardinal i:std.loc.set, o:int. + +% [std.loc.set.filter M F M1] Filter M w.r.t. the predicate F +external pred std.loc.set.filter i:std.loc.set, i:loc -> prop, + o:std.loc.set. + +% [std.loc.set.map M F M1] Map M w.r.t. the predicate F +external pred std.loc.set.map i:std.loc.set, i:loc -> loc -> prop, + o:std.loc.set. + +#line 0 "builtin_map.elpi" +kind std.map type -> type -> type. +type std.map std.map.private.map K V -> (K -> K -> cmp -> prop) -> std.map K V. + +namespace std.map { + +% [make Eq Ltn M] builds an empty map M where keys are compared using Eq and Ltn +pred make i:(K -> K -> cmp -> prop), o:std.map K V. +make Cmp (std.map private.empty Cmp). + +% [find K M V] looks in M for the value V associated to K +pred find i:K, i:std.map K V, o:V. +find K (std.map M Cmp) V :- private.find M Cmp K V. + +% [add K V M M1] M1 is M where K is bound to V +pred add i:K, i:V, i:std.map K V, o:std.map K V. +add K V (std.map M Cmp) (std.map M1 Cmp) :- private.add M Cmp K V M1. + +% [remove K M M1] M1 is M where K is unbound +pred remove i:K, i:std.map K V, o:std.map K V. +remove K (std.map M Cmp) (std.map M1 Cmp) :- private.remove M Cmp K M1. + +% [bindings M L] L is the key-value pairs in increasing order +pred bindings i:std.map K V, o:list (pair K V). +bindings (std.map M _) L :- private.bindings M [] L. + +namespace private { + +% Taken from OCaml's map.ml +kind map type -> type -> type. +type empty map K V. +type node map K V -> K -> V -> map K V -> int -> map K V. + +pred height i:map K V, o:int. +height empty 0. +height (node _ _ _ _ H) H. + +pred create i:map K V, i:K, i:V, i:map K V, o:map K V. +create L K V R (node L K V R H) :- H is {std.max {height L} {height R}} + 1. + +pred bal i:map K V, i:K, i:V, i:map K V, o:map K V. +bal L K V R T :- + height L HL, + height R HR, + HL2 is HL + 2, + HR2 is HR + 2, + bal.aux HL HR HL2 HR2 L K V R T. + +bal.aux HL _ _ HR2 (node LL LV LD LR _) X D R T :- + HL > HR2, {height LL} >= {height LR}, !, + create LL LV LD {create LR X D R} T. +bal.aux HL _ _ HR2 (node LL LV LD (node LRL LRV LRD LRR _) _) X D R T :- + HL > HR2, !, + create {create LL LV LD LRL} LRV LRD {create LRR X D R} T. +bal.aux _ HR HL2 _ L X D (node RL RV RD RR _) T :- + HR > HL2, {height RR} >= {height RL}, !, + create {create L X D RL} RV RD RR T. +bal.aux _ HR HL2 _ L X D (node (node RLL RLV RLD RLR _) RV RD RR _) T :- + HR > HL2, !, + create {create L X D RLL} RLV RLD {create RLR RV RD RR} T. +bal.aux _ _ _ _ L K V R T :- create L K V R T. + +pred add i:map K V, i:(K -> K -> cmp -> prop), i:K, i:V, o:map K V. +add empty _ K V T :- create empty K V empty T. +add (node _ X _ _ _ as M) Cmp X1 XD M1 :- Cmp X1 X E, add.aux E M Cmp X1 XD M1. +add.aux eq (node L _ _ R H) _ X XD T :- T = node L X XD R H. +add.aux lt (node L V D R _) Cmp X XD T :- bal {add L Cmp X XD} V D R T. +add.aux gt (node L V D R _) Cmp X XD T :- bal L V D {add R Cmp X XD} T. + +pred find i:map K V, i:(K -> K -> cmp -> prop), i:K, o:V. +find (node L K1 V1 R _) Cmp K V :- Cmp K K1 E, find.aux E Cmp L R V1 K V. +find.aux eq _ _ _ V _ V. +find.aux lt Cmp L _ _ K V :- find L Cmp K V. +find.aux gt Cmp _ R _ K V :- find R Cmp K V. + +pred remove-min-binding i:map K V, o:map K V. +remove-min-binding (node empty _ _ R _) R :- !. +remove-min-binding (node L V D R _) X :- bal {remove-min-binding L} V D R X. + +pred min-binding i:map K V, o:K, o:V. +min-binding (node empty V D _ _) V D :- !. +min-binding (node L _ _ _ _) V D :- min-binding L V D. + +pred merge i:map K V, i:map K V, o:map K V. +merge empty X X :- !. +merge X empty X :- !. +merge M1 M2 R :- + min-binding M2 X D, + bal M1 X D {remove-min-binding M2} R. + +pred remove i:map K V, i:(K -> K -> cmp -> prop), i:K, o:map K V. +remove empty _ _ empty :- !. +remove (node L V D R _) Cmp X M :- Cmp X V E, remove.aux E Cmp L R V D X M. +remove.aux eq _ L R _ _ _ M :- merge L R M. +remove.aux lt Cmp L R V D X M :- bal {remove L Cmp X} V D R M. +remove.aux gt Cmp L R V D X M :- bal L V D {remove R Cmp X} M. + +pred bindings i:map K V, i:list (pair K V), o:list (pair K V). +bindings empty X X. +bindings (node L V D R _) X X1 :- + bindings L [pr V D|{bindings R X}] X1. + + +} % std.map.private +} % std.map + + +#line 0 "builtin_set.elpi" +kind std.set type -> type. +type std.set std.set.private.set E -> (E -> E -> cmp -> prop) -> std.set E. + +namespace std.set { + +% [make Eq Ltn M] builds an empty set M where keys are compared using Eq and Ltn +pred make i:(E -> E -> cmp -> prop), o:std.set E. +make Cmp (std.set private.empty Cmp). + +% [mem E M] looks if E is in M +pred mem i:E, i:std.set E. +mem E (std.set M Cmp):- private.mem M Cmp E. + +% [add E M M1] M1 is M + {E} +pred add i:E, i:std.set E, o:std.set E. +add E (std.set M Cmp) (std.set M1 Cmp) :- private.add M Cmp E M1. + +% [remove E M M1] M1 is M - {E} +pred remove i:E, i:std.set E, o:std.set E. +remove E (std.set M Cmp) (std.set M1 Cmp) :- private.remove M Cmp E M1. + +% [cardinal S N] N is the number of elements of S +pred cardinal i:std.set E, o:int. +cardinal (std.set M _) N :- private.cardinal M N. + +pred elements i:std.set E, o:list E. +elements (std.set M _) L :- private.elements M [] L. + +namespace private { + +% Taken from OCaml's set.ml +kind set type -> type. +type empty set E. +type node set E -> E -> set E -> int -> set E. + +pred height i:set E, o:int. +height empty 0. +height (node _ _ _ H) H. + +pred create i:set E, i:E, i:set E, o:set E. +create L E R (node L E R H) :- H is {std.max {height L} {height R}} + 1. + +pred bal i:set E, i:E, i:set E, o:set E. +bal L E R T :- + height L HL, + height R HR, + HL2 is HL + 2, + HR2 is HR + 2, + bal.aux HL HR HL2 HR2 L E R T. + +bal.aux HL _ _ HR2 (node LL LV LR _) X R T :- + HL > HR2, {height LL} >= {height LR}, !, + create LL LV {create LR X R} T. +bal.aux HL _ _ HR2 (node LL LV (node LRL LRV LRR _) _) X R T :- + HL > HR2, !, + create {create LL LV LRL} LRV {create LRR X R} T. +bal.aux _ HR HL2 _ L X (node RL RV RR _) T :- + HR > HL2, {height RR} >= {height RL}, !, + create {create L X RL} RV RR T. +bal.aux _ HR HL2 _ L X (node (node RLL RLV RLR _) RV RR _) T :- + HR > HL2, !, + create {create L X RLL} RLV {create RLR RV RR} T. +bal.aux _ _ _ _ L E R T :- create L E R T. + +pred add i:set E, i:(E -> E -> cmp -> prop), i:E, o:set E. +add empty _ E T :- create empty E empty T. +add (node L X R H) Cmp X1 S :- Cmp X1 X E, add.aux E Cmp L R X X1 H S. +add.aux eq _ L R X _ H (node L X R H). +add.aux lt Cmp L R E X _ T :- bal {add L Cmp X} E R T. +add.aux gt Cmp L R E X _ T :- bal L E {add R Cmp X} T. + +pred mem i:set E, i:(E -> E -> cmp -> prop), i:E. +mem (node L K R _) Cmp E :- Cmp E K O, mem.aux O Cmp L R E. +mem.aux eq _ _ _ _. +mem.aux lt Cmp L _ E :- mem L Cmp E. +mem.aux gt Cmp _ R E :- mem R Cmp E. + +pred remove-min-binding i:set E, o:set E. +remove-min-binding (node empty _ R _) R :- !. +remove-min-binding (node L E R _) X :- bal {remove-min-binding L} E R X. + +pred min-binding i:set E, o:E. +min-binding (node empty E _ _) E :- !. +min-binding (node L _ _ _) E :- min-binding L E. + +pred merge i:set E, i:set E, o:set E. +merge empty X X :- !. +merge X empty X :- !. +merge M1 M2 R :- + min-binding M2 X, + bal M1 X {remove-min-binding M2} R. + +pred remove i:set E, i:(E -> E -> cmp -> prop), i:E, o:set E. +remove empty _ _ empty. +remove (node L E R _) Cmp X M :- Cmp X E O, remove.aux O Cmp L R E X M. +remove.aux eq _ L R _ _ M :- merge L R M. +remove.aux lt Cmp L R E X M :- bal {remove L Cmp X} E R M. +remove.aux gt Cmp L R E X M :- bal L E {remove R Cmp X} M. + +pred cardinal i:set E, o:int. +cardinal empty 0. +cardinal (node L _ R _) N :- N is {cardinal L} + 1 + {cardinal R}. + +pred elements i:set E, i:list E, o:list E. +elements empty X X. +elements (node L E R _) Acc X :- + elements L [E|{elements R Acc}] X. + +} % std.set.private +} % std.set + + +% == I/O builtins ===================================== + +% -- I/O -- + +typeabbrev in_stream (ctype "in_stream"). + +type std_in in_stream. + +typeabbrev out_stream (ctype "out_stream"). + +type std_out out_stream. +type std_err out_stream. + +% [open_in FileName InStream] opens FileName for input +external pred open_in i:string, o:in_stream. + +% [open_out FileName OutStream] opens FileName for output +external pred open_out i:string, o:out_stream. + +% [open_append FileName OutStream] opens FileName for output in append mode +external pred open_append i:string, o:out_stream. + +% [close_in InStream] closes input stream InStream +external pred close_in i:in_stream. + +% [close_out OutStream] closes output stream OutStream +external pred close_out i:out_stream. + +% [output OutStream Data] writes Data to OutStream +external pred output i:out_stream, i:string. + +% [flush OutStream] flush all output not yet finalized to OutStream +external pred flush i:out_stream. + +% [input InStream Bytes Data] reads Bytes from InStream +external pred input i:in_stream, i:int, o:string. + +% [input_line InStream Line] reads a full line from InStream +external pred input_line i:in_stream, o:string. + +% [eof InStream] checks if no more data can be read from InStream +external pred eof i:in_stream. + +% -- System -- + +% [gettimeofday T] sets T to the number of seconds elapsed since 1/1/1970 +external pred gettimeofday o:float. + +% [getenv VarName Value] Like Sys.getenv +external pred getenv i:string, o:option string. + +% [system Command RetVal] executes Command and sets RetVal to the exit code +external pred system i:string, o:int. + +% -- Unix -- + +% gathers the standard file descriptors or a process +kind unix.process type. +type unix.process out_stream -> in_stream -> in_stream -> unix.process. + +% [unix.process.open Executable Arguments Environment P Diagnostic] OCaml's +% Unix.open_process_args_full. +% Note that the first argument is the executable name (as in argv[0]). +% If Executable is omitted it defaults to the first element of +% Arguments. +% Environment can be left unspecified, defaults to the current process +% environment. +% This API only works reliably since OCaml 4.12. +external pred unix.process.open i:string, i:list string, i:list string, + o:unix.process, o:diagnostic. + +% [unix.process.close P Diagnostic] OCaml's Unix.close_process_full +external pred unix.process.close i:unix.process, o:diagnostic. + +% -- Debugging -- + +% [term_to_string T S] prints T to S +external pred term_to_string i:any, o:string. + +% == Elpi runtime builtins ===================================== + +% [trace.counter Name Value] reads the Value of a trace point Name +external pred trace.counter i:string, o:int. + +% [gc.get MinorHeapSize MajorHeapIncrement SpaceOverhead Verbose MaxOverhead +% StackLimit AllocationPolicy WindowSize] Reads the current settings of the +% garbage collector. See also OCaml's Gc.control type documentation. +external pred gc.get o:int, o:int, o:int, o:int, o:int, o:int, o:int, + o:int. + +% [gc.set MinorHeapSize MajorHeapIncrement SpaceOverhead Verbose MaxOverhead +% StackLimit AllocationPolicy WindowSize] Writes the current settings of the +% garbage collector. Any parameter left unspecificed (eg _) is not changed. +% See also OCaml's Gc.control type documentation. +external pred gc.set i:int, i:int, i:int, i:int, i:int, i:int, i:int, + i:int. + +% [gc.minor] See OCaml's Gc.minor documentation. +external pred gc.minor . + +% [gc.major] See OCaml's Gc.major documentation. +external pred gc.major . + +% [gc.full] See OCaml's Gc.full_major documentation. +external pred gc.full . + +% [gc.compact] See OCaml's Gc.compact documentation. +external pred gc.compact . + +% [gc.stat MinorWords PromotedWords MajorWords MinorCollections +% MajorCollections HeapWords HeapChunks LiveWords LiveBlocks FreeWords +% FreeBlocks LargestFree Fragments Compactions TopHeapWords StackSize] See +% OCaml's Gc.stat documentation. +external pred gc.stat o:float, o:float, o:float, o:int, o:int, o:int, + o:int, o:int, o:int, o:int, o:int, o:int, o:int, + o:int, o:int, o:int. + +% [gc.quick-stat MinorWords PromotedWords MajorWords MinorCollections +% MajorCollections HeapWords HeapChunks Compactions TopHeapWords StackSize] +% See OCaml's Gc.quick_stat documentation. +external pred gc.quick-stat o:float, o:float, o:float, o:int, o:int, + o:int, o:int, o:int, o:int, o:int. + +% == Lambda Prolog builtins ===================================== + +% -- Extra I/O -- + +% [open_string DataIn InStream] opens DataIn as an input stream +external pred open_string i:string, o:in_stream. + +% [lookahead InStream NextChar] peeks one byte from InStream +external pred lookahead i:in_stream, o:string. + +% -- Hacks -- + +% [string_to_term S T] parses a term T from S +external pred string_to_term i:string, o:any. + +% [readterm InStream T] reads T from InStream, ends with \n +external pred readterm i:in_stream, o:any. + +pred printterm i:out_stream, i:A. + +printterm S T :- term_to_string T T1, output S T1. + +pred read o:A. + +read S :- flush std_out, input_line std_in X, string_to_term X S. + + + + diff --git a/builtin-doc/gen_doc.ml b/builtin-doc/gen_doc.ml new file mode 100644 index 000000000..cf77d30f5 --- /dev/null +++ b/builtin-doc/gen_doc.ml @@ -0,0 +1,2 @@ +let _ = + Elpi_plugin.Coq_elpi_programs.document_builtins () diff --git a/coq-builtin-synterp.elpi b/coq-builtin-synterp.elpi deleted file mode 100644 index 5f1002d3f..000000000 --- a/coq-builtin-synterp.elpi +++ /dev/null @@ -1,386 +0,0 @@ - - -% -- Misc --------------------------------------------------------- - -% [coq.info ...] Prints an info message -external type coq.info variadic any prop. - -% [coq.notice ...] Prints a notice message -external type coq.notice variadic any prop. - -% [coq.say ...] Prints a notice message -external type coq.say variadic any prop. - -% [coq.warn ...] Prints a generic warning message -external type coq.warn variadic any prop. - -% [coq.warning Category Name ...] -% Prints a warning message with a Name and Category which can be used -% to silence this warning or turn it into an error. See coqc -w command -% line option -external type coq.warning string -> string -> variadic any prop. - -% [coq.error ...] Prints and *aborts* the program. It is a fatal error for -% Elpi and Ltac -external type coq.error variadic any prop. - -% [coq.version VersionString Major Minor Patch] Fetches the version of Coq, -% as a string and as 3 numbers -external pred coq.version o:string, o:int, o:int, o:int. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-arg-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% This section contains the low level data types linking Coq and elpi. -% In particular the entry points for commands - - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Entry points -% -% Command and tactic invocation -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% Entry point for commands. Eg. "#[att=true] Elpi mycommand foo 3 (f x)." becomes -% main [str "foo", int 3, trm (app[f,x])] -% in a context where -% attributes [attribute "att" (leaf "true")] -% holds. The encoding of terms is described below. -% See also the coq.parse-attributes utility. -pred main i:list argument. -pred main-interp i:list argument, i:any. -pred main-synterp i:list argument, o:any. -pred usage. -pred attributes o:list attribute. - -% see coq-lib.elpi for coq.parse-attributes generating the options below -type get-option string -> A -> prop. - -% The data type of arguments (for commands or tactics) -kind argument type. -type int int -> argument. % Eg. 1 -2. -type str string -> argument. % Eg. x "y" z.w. or any Coq keyword/symbol -type trm term -> argument. % Eg. (t). - -% Extra arguments for commands. [Definition], [Axiom], [Record] and [Context] -% take precedence over the [str] argument above (when not "quoted"). -% -% Eg. Record or Inductive -type indt-decl indt-decl -> argument. -% Eg. #[universes(polymorphic,...)] Record or Inductive -type upoly-indt-decl indt-decl -> upoly-decl -> argument. -type upoly-indt-decl indt-decl -> upoly-decl-cumul -> argument. -% Eg. Definition or Axiom (when the body is none) -type const-decl id -> option term -> arity -> argument. -% Eg. #[universes(polymorphic,...)] Definition or Axiom -type upoly-const-decl id -> option term -> arity -> upoly-decl -> argument. -% Eg. Context A (b : A). -type ctx-decl context-decl -> argument. - -% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -kind indt-decl type. -kind indc-decl type. -kind record-decl type. - -% An arity is written, in Coq syntax, as: -% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U -% This syntax is used, for example, in the type of an inductive type or -% in the type of constructors. We call the abstractions on the left of ":" -% "parameters" while we call the type following the ":" (proper) arity. - -% Note: in some contexts, like the type of an inductive type constructor, -% Coq makes no distinction between these two writings -% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ... -% while Elpi is a bit more restrictive, since it understands user directives -% such as the implicit status of an arguments (eg, using {} instead of () around -% the binder), only on parameters. -% Moreover parameters carry the name given by the user as an "id", while binders -% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see -% also the HOAS of terms). A user command can hence only use the names of -% parameters, and not the names of "forall" quantified variables in the arity. -% -% See also the arity->term predicate in coq-lib.elpi - -type parameter id -> implicit_kind -> term -> (term -> arity) -> arity. -type arity term -> arity. - -type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl. -type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive -type record id -> term -> id -> record-decl -> indt-decl. - -type constructor id -> arity -> indc-decl. - -type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl. -type end-record record-decl. - -% Example. -% Remark that A is a regular parameter; y is a non-uniform parameter and t -% also features an index of type bool. -% -% Inductive t (A : Type) | (y : nat) : bool -> Type := -% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true -% | K2 : t A y false -% -% is written -% -% (parameter "A" explicit {{ Type }} a\ -% inductive "t" tt (parameter "y" explicit {{ nat }} _\ -% arity {{ bool -> Type }}) -% t\ -% [ constructor "K1" -% (parameter "y" explicit {{ nat }} y\ -% (parameter "x" explicit a x\ -% (parameter "n" maximal {{ nat }} n\ -% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }}))) -% , constructor "K2" -% (parameter "y" explicit {{ nat }} y\ -% arity {{ lp:t lp:y false }}) ]) -% -% Remark that the uniform parameters are not passed to occurrences of t, since -% they never change, while non-uniform parameters are both abstracted -% in each constructor type and passed as arguments to t. -% -% The coq.typecheck-indt-decl API can be used to fill in implicit arguments -% an infer universe constraints in the declaration above (e.g. the hidden -% argument of "=" in the arity of K1). -% -% Note: when and inductive type declaration is passed as an argument to an -% Elpi command non uniform parameters must be separated from the uniform ones -% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since -% version 1.4, in Coq this separator is optional, but not in Elpi). - -% Context declaration (used as an argument to Elpi commands) -kind context-decl type. -% Eg. (x : T) or (x := B), body is optional, type may be a variable -type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl. -type context-end context-decl. - -typeabbrev field-attributes (list field-attribute). - -macro @global! :- get-option "coq:locality" "global". -macro @local! :- get-option "coq:locality" "local". - - -% Coq terms are not visible at synterp time, they are always holes - -kind term type. - -% -- Parsing time APIs -% ---------------------------------------------------- - -% [id] is a name that matters, we piggy back on Elpi's strings. -% Note: [name] is a name that does not matter. -typeabbrev id string. - - -% Name of a module /*E*/ -typeabbrev modpath (ctype "modpath"). - - -% Name of a module type /*E*/ -typeabbrev modtypath (ctype "modtypath"). - - -% [coq.locate-module ModName ModPath] locates a module. It's a fatal error -% if ModName cannot be located. *E* -external pred coq.locate-module i:id, o:modpath. - -% [coq.locate-module-type ModName ModPath] locates a module. It's a fatal -% error if ModName cannot be located. *E* -external pred coq.locate-module-type i:id, o:modtypath. - - -kind located type. -type loc-modpath modpath -> located. -type loc-modtypath modtypath -> located. - - -% [coq.locate-all Name Located] finds all possible meanings of a string. -% Does not fail. -external pred coq.locate-all i:id, o:list located. - -% Coq Module inline directive -kind coq.inline type. -type coq.inline.no coq.inline. % Coq's [no inline] (aka !) -type coq.inline.default coq.inline. % The default, can be omitted -type coq.inline.at int -> coq.inline. % Coq's [inline at ] - -external pred coq.env.begin-module-functor % Starts a functor *E* - i:id, % The name of the functor - i:option modtypath, % Its module type - i:list (pair id modtypath). % Parameters of the functor - - -pred coq.env.begin-module i:id, i:option modtypath. -coq.env.begin-module Name MP :- - coq.env.begin-module-functor Name MP []. - - -% [coq.env.end-module ModPath] end the current module that becomes known as -% ModPath *E* -external pred coq.env.end-module o:modpath. - -external pred coq.env.begin-module-type-functor % Starts a module type functor *E* - i:id, % The name of the functor - i:list (pair id modtypath). % The parameters of the functor - - -pred coq.env.begin-module-type i:id. -coq.env.begin-module-type Name :- - coq.env.begin-module-type-functor Name []. - - -% [coq.env.end-module-type ModTyPath] end the current module type that -% becomes known as ModPath *E* -external pred coq.env.end-module-type o:modtypath. - -external pred coq.env.apply-module-functor % Applies a functor *E* - i:id, % The name of the new module - i:option modtypath, % Its module type - i:modpath, % The functor being applied - i:list modpath, % Its arguments - i:coq.inline, % Arguments inlining - o:modpath. % The modpath of the new module - -external pred coq.env.apply-module-type-functor % Applies a type functor *E* - i:id, % The name of the new module type - i:modtypath, % The functor - i:list modpath, % Its arguments - i:coq.inline, % Arguments inlining - o:modtypath. % The modtypath of the new module type - -% [coq.env.include-module ModPath Inline] is like the vernacular Include, -% Inline can be omitted *E* -external pred coq.env.include-module i:modpath, i:coq.inline. - -% [coq.env.include-module-type ModTyPath Inline] is like the vernacular -% Include Type, Inline can be omitted *E* -external pred coq.env.include-module-type i:modtypath, i:coq.inline. - -% [coq.env.import-module ModPath] is like the vernacular Import *E* -external pred coq.env.import-module i:modpath. - -% [coq.env.export-module ModPath] is like the vernacular Export *E* -external pred coq.env.export-module i:modpath. - -% [coq.env.begin-section Name] starts a section named Name *E* -external pred coq.env.begin-section i:id. - -% [coq.env.end-section] end the current section *E* -external pred coq.env.end-section . - -% [coq.modpath->path MP FullPath] extract the full kernel name, each -% component is a separate list item -external pred coq.modpath->path i:modpath, o:list string. - -% [coq.modtypath->path MTP FullPath] extract the full kernel name, each -% component is a separate list item -external pred coq.modtypath->path i:modtypath, o:list string. - -% [coq.modpath->library MP LibraryPath] extract the enclosing module which -% can be Required -external pred coq.modpath->library i:modpath, o:modpath. - -% [coq.modtypath->library MTP LibraryPath] extract the enclosing module -% which can be Required -external pred coq.modtypath->library i:modtypath, o:modpath. - -% [coq.env.current-path Path] lists the current module path -external pred coq.env.current-path o:list string. - -% [coq.env.current-section-path Path] lists the current section path -external pred coq.env.current-section-path o:list string. - -% clauses -% -% A clause like -% :name "foo" :before "bar" foo X Y :- bar X Z, baz Z Y -% is represented as -% clause "foo" (before "bar") (pi x y z\ foo x y :- bar x z, baz z y) -% that is exactly what one would load in the context using =>. -% -% The name and the grafting specification can be left unspecified. -kind clause type. -type clause id -> grafting -> prop -> clause. - -% Specify if the clause has to be grafted before, grafted after or replace -% a named clause -kind grafting type. -type before id -> grafting. -type after id -> grafting. -type replace id -> grafting. - -% Specify to which module the clause should be attached to -kind scope type. -type execution-site scope. % The module inside which the Elpi program is run -type current scope. % The module being defined (see begin/end-module) -type library scope. % The outermost module (carrying the file name) - - -% see coq.elpi.accumulate-clauses -pred coq.elpi.accumulate i:scope, i:id, i:clause. -coq.elpi.accumulate S N C :- coq.elpi.accumulate-clauses S N [C]. - - -% [coq.elpi.accumulate-clauses Scope DbName Clauses] -% Declare that, once the program is over, the given clauses has to be -% added to the given db (see Elpi Db). -% Clauses usually belong to Coq modules: the Scope argument lets one -% select which module: -% - execution site (default) is the module in which the pogram is -% invoked -% - current is the module currently being constructed (see -% begin/end-module) -% - library is the current file (the module that is named after the file) -% The clauses are visible as soon as the enclosing module is -% Imported. -% Clauses cannot be accumulated inside functors. -% Supported attributes: -% - @local! (default: false, discard at the end of section or module) -% - @global! (default: false, always active, only if Scope is -% execution-site, discouraged) -external pred coq.elpi.accumulate-clauses i:scope, i:id, i:list clause. - -% Action executed during the parsing phase (aka synterp) -kind synterp-action type. -type begin-module id -> synterp-action. -type begin-module-type id -> synterp-action. -type begin-section id -> synterp-action. -type end-module modpath -> synterp-action. -type end-module-type modtypath -> synterp-action. -type end-section synterp-action. -type apply-module-functor id -> synterp-action. -type apply-module-type-functor id -> synterp-action. -type include-module modpath -> synterp-action. -type include-module-type modtypath -> synterp-action. -type import-module modpath -> synterp-action. -type export-module modpath -> synterp-action. - -% [coq.synterp-actions A] Get the list of actions performed during the -% parsing phase (aka synterp) up to now. -external pred coq.synterp-actions o:list synterp-action. - -% [coq.begin-synterp-group ID Group] Create and open a new synterp action -% group with the given name. -external pred coq.begin-synterp-group i:id, o:group. - -% [coq.end-synterp-group Group] End the synterp action group Group. Group -% must refer to the most recently openned group. -external pred coq.end-synterp-group i:group. - -% Generic attribute value -kind attribute-value type. -type leaf-str string -> attribute-value. -type leaf-loc loc -> attribute-value. -type node list attribute -> attribute-value. - -% Generic attribute -kind attribute type. -type attribute string -> attribute-value -> attribute. - - - - diff --git a/coq-builtin-synterp.elpi b/coq-builtin-synterp.elpi new file mode 120000 index 000000000..155d7ec29 --- /dev/null +++ b/coq-builtin-synterp.elpi @@ -0,0 +1 @@ +builtin-doc/coq-builtin-synterp.elpi \ No newline at end of file diff --git a/coq-builtin.elpi b/coq-builtin.elpi deleted file mode 100644 index 29cfde6e7..000000000 --- a/coq-builtin.elpi +++ /dev/null @@ -1,2135 +0,0 @@ - - -% Coq terms as the object language of elpi and basic API to access Coq -% license: GNU Lesser General Public License Version 2.1 or later -% ------------------------------------------------------------------------- - -% This file is automatically generated from -% - coq-HOAS.elpi -% - coq_elpi_builtin.ml -% and contains the description of the data type of Coq terms and the -% API to access Coq. - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-arg-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% This section contains the low level data types linking Coq and elpi. -% In particular the entry points for commands - - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Entry points -% -% Command and tactic invocation -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% Entry point for commands. Eg. "#[att=true] Elpi mycommand foo 3 (f x)." becomes -% main [str "foo", int 3, trm (app[f,x])] -% in a context where -% attributes [attribute "att" (leaf "true")] -% holds. The encoding of terms is described below. -% See also the coq.parse-attributes utility. -pred main i:list argument. -pred main-interp i:list argument, i:any. -pred main-synterp i:list argument, o:any. -pred usage. -pred attributes o:list attribute. - -% see coq-lib.elpi for coq.parse-attributes generating the options below -type get-option string -> A -> prop. - -% The data type of arguments (for commands or tactics) -kind argument type. -type int int -> argument. % Eg. 1 -2. -type str string -> argument. % Eg. x "y" z.w. or any Coq keyword/symbol -type trm term -> argument. % Eg. (t). - -% Extra arguments for commands. [Definition], [Axiom], [Record] and [Context] -% take precedence over the [str] argument above (when not "quoted"). -% -% Eg. Record or Inductive -type indt-decl indt-decl -> argument. -% Eg. #[universes(polymorphic,...)] Record or Inductive -type upoly-indt-decl indt-decl -> upoly-decl -> argument. -type upoly-indt-decl indt-decl -> upoly-decl-cumul -> argument. -% Eg. Definition or Axiom (when the body is none) -type const-decl id -> option term -> arity -> argument. -% Eg. #[universes(polymorphic,...)] Definition or Axiom -type upoly-const-decl id -> option term -> arity -> upoly-decl -> argument. -% Eg. Context A (b : A). -type ctx-decl context-decl -> argument. - -% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -kind indt-decl type. -kind indc-decl type. -kind record-decl type. - -% An arity is written, in Coq syntax, as: -% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U -% This syntax is used, for example, in the type of an inductive type or -% in the type of constructors. We call the abstractions on the left of ":" -% "parameters" while we call the type following the ":" (proper) arity. - -% Note: in some contexts, like the type of an inductive type constructor, -% Coq makes no distinction between these two writings -% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ... -% while Elpi is a bit more restrictive, since it understands user directives -% such as the implicit status of an arguments (eg, using {} instead of () around -% the binder), only on parameters. -% Moreover parameters carry the name given by the user as an "id", while binders -% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see -% also the HOAS of terms). A user command can hence only use the names of -% parameters, and not the names of "forall" quantified variables in the arity. -% -% See also the arity->term predicate in coq-lib.elpi - -type parameter id -> implicit_kind -> term -> (term -> arity) -> arity. -type arity term -> arity. - -type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl. -type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive -type record id -> term -> id -> record-decl -> indt-decl. - -type constructor id -> arity -> indc-decl. - -type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl. -type end-record record-decl. - -% Example. -% Remark that A is a regular parameter; y is a non-uniform parameter and t -% also features an index of type bool. -% -% Inductive t (A : Type) | (y : nat) : bool -> Type := -% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true -% | K2 : t A y false -% -% is written -% -% (parameter "A" explicit {{ Type }} a\ -% inductive "t" tt (parameter "y" explicit {{ nat }} _\ -% arity {{ bool -> Type }}) -% t\ -% [ constructor "K1" -% (parameter "y" explicit {{ nat }} y\ -% (parameter "x" explicit a x\ -% (parameter "n" maximal {{ nat }} n\ -% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }}))) -% , constructor "K2" -% (parameter "y" explicit {{ nat }} y\ -% arity {{ lp:t lp:y false }}) ]) -% -% Remark that the uniform parameters are not passed to occurrences of t, since -% they never change, while non-uniform parameters are both abstracted -% in each constructor type and passed as arguments to t. -% -% The coq.typecheck-indt-decl API can be used to fill in implicit arguments -% an infer universe constraints in the declaration above (e.g. the hidden -% argument of "=" in the arity of K1). -% -% Note: when and inductive type declaration is passed as an argument to an -% Elpi command non uniform parameters must be separated from the uniform ones -% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since -% version 1.4, in Coq this separator is optional, but not in Elpi). - -% Context declaration (used as an argument to Elpi commands) -kind context-decl type. -% Eg. (x : T) or (x := B), body is optional, type may be a variable -type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl. -type context-end context-decl. - -typeabbrev field-attributes (list field-attribute). - -macro @global! :- get-option "coq:locality" "global". -macro @local! :- get-option "coq:locality" "local". - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% This section contains the low level data types linking Coq and elpi. -% In particular the data type for terms and the evar_map entries (a sequent) -% and the entry points for tactics - -% Entry point for tactics. Eg. "elpi mytactic foo 3 (f x)." becomes -% solve -% Where [str "foo", int 3, trm (app[f,x])] is part of . -% The encoding of goals is described below. -% msolve is for tactics that operate on multiple goals (called via all: ). -pred solve i:goal, o:list sealed-goal. -pred msolve i:list sealed-goal, o:list sealed-goal. - -% Extra arguments for tactics -type tac ltac1-tactic -> argument. - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Coq's terms -% -% Types of term formers -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% -- terms -------------------------------------------------------------------- -kind term type. - -type sort sort -> term. % Prop, Type@{i} - -% constants: inductive types, inductive constructors, definitions -type global gref -> term. -type pglobal gref -> univ-instance -> term. - -% binders: to form functions, arities and local definitions -type fun name -> term -> (term -> term) -> term. % fun x : t => -type prod name -> term -> (term -> term) -> term. % forall x : t, -type let name -> term -> term -> (term -> term) -> term. % let x : T := v in - -% other term formers: function application, pattern matching and recursion -type app list term -> term. % app [hd|args] -type match term -> term -> list term -> term. % match t p [branch]) -type fix name -> int -> term -> (term -> term) -> term. % fix name rno ty bo - -type primitive primitive-value -> term. - -% NYI -%type cofix name -> term -> (term -> term) -> term. % cofix name ty bo - -% Notes about (match Scrutinee TypingFunction Branches) when -% Inductive i A : A -> nat -> Type := K : forall a : A, i A a 0 -% and -% Scrutinee be a term of type (i bool true 7) -% -% - TypingFunction has a very rigid shape that depends on i. Namely -% as many lambdas as indexes plus one lambda for the inductive itself -% where the value of the parameters are taken from the type of the scrutinee: -% fun `a` (indt "bool") a\ -% fun `n` (indt "nat) n\ -% fun `i` (app[indt "i", indt "bool", a n) i\ .. -% Such spine of fun cannot be omitted; else elpi cannot read the term back. -% See also coq.bind-ind-arity-no-let in coq-lib.elpi, that builds such spine for you, -% or the higher level api coq.build-match (same file) that also takes -% care of breanches. -% - Branches is a list of terms, the order is the canonical one (the order -% of the constructors as they were declared). If the constructor has arguments -% (excluding the parameters) then the corresponding term shall be a Coq -% function. In this case -% fun `x` (indt "bool") x\ .. - -% -- helpers ------------------------------------------------------------------ -macro @cast T TY :- (let `cast` TY T x\x). - -% -- misc --------------------------------------------------------------------- - -% When one writes Constraint Handling Rules unification variables are "frozen", -% i.e. represented by a fresh constant (the evar key) and a list of terms -% (typically the variables in scope). -kind evarkey type. -type uvar evarkey -> list term -> term. - - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Coq's evar_map -% -% Context and evar declaration -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% An evar_info (displayed as a Coq goal) is essentially a sequent: -% -% x : t -% y := v : x -% ---------- -% p x y -% -% is coded as an Elpi query -% -% pi x1\ decl x1 `x` => -% pi x2\ def x2 `y` x1 => -% declare-evar -% [def x2 `y` x1 , decl x1 `x` ] -% (RawEvar x1 x2) (

x1 x2) (Ev x1 x2) -% -% where, by default, declare-evar creates a syntactic constraint as -% -% {x1 x2} : -% decl x1 `x` , def x2 `y` x1 ?- -% evar (RawEvar x1 x2) (

x1 x2) (Ev x1 x2) /* suspended on RawEvar, Ev */ -% -% When the program is over, a remaining syntactic constraint like the one above -% is read back and transformed into the corresponding evar_info. - -pred decl i:term, o:name, o:term. % Var Name Ty -pred def i:term, o:name, o:term, o:term. % Var Name Ty Bo -pred declare-evar i:list prop, i:term, i:term, i:term. % Ctx RawEvar Ty Evar - -:name "default-declare-evar" -declare-evar Ctx RawEv Ty Ev :- - declare_constraint (declare-evar Ctx RawEv Ty Ev) [RawEv]. - -% When a goal (evar _ _ _) is turned into a constraint the context is filtered -% to only contain decl, def, pp. For now no handling rules for this set of -% constraints other than one to remove a constraint - -pred rm-evar i:term, i:term. -rm-evar (uvar as X) (uvar as Y):- !, declare_constraint (rm-evar X Y) [X,Y]. -rm-evar _ _. - -constraint declare-evar evar def decl cache rm-evar { - - % Override the actual context - rule \ (declare-evar Ctx RawEv Ty Ev) <=> (Ctx => evar RawEv Ty Ev). - - rule \ (rm-evar (uvar X _) (uvar Y _)) (evar (uvar X _) _ (uvar Y _)). - rule \ (rm-evar (uvar X _) (uvar Y _)). - -} - -% The (evar R Ty E) predicate suspends when R and E are flexible, -% and is solved otherwise. -% The client may want to provide an alternative implementation of -% the clause "default-assign-evar", for example to typechecks that the -% term assigned to E has type Ty, or that the term assigned to R -% elaborates to a term of type Ty that gets assigned to E. -% In tactic mode, elpi/coq-elaborator.elpi wires things up that way. - -pred evar i:term, i:term, o:term. % Evar Ty RefinedSolution -evar (uvar as X) T S :- var S _ VL, !, - prune T VL, prune X VL, declare_constraint (evar X T S) [X, S]. - -:name "default-assign-evar" -evar _ _ _. % volatile, only unresolved evars are considered as evars - -% To ease the creation of a context with decl and def -% Eg. @pi-decl `x` x1\ @pi-def `y` y\ ... -macro @pi-decl N T F :- pi x\ decl x N T => F x. -macro @pi-def N T B F :- pi x\ def x N T B => cache x B_ => F x. -macro @pi-parameter ID T F :- - sigma N\ (coq.id->name ID N, pi x\ decl x N T => F x). -macro @pi-inductive ID A F :- - sigma N\ (coq.id->name ID N, coq.arity->term A T, pi x\ decl x N T => F x). - -% Sometimes it can be useful to pass to Coq a term with unification variables -% representing "untyped holes" like an implicit argument _. In particular -% a unification variable may exit the so called pattern fragment (applied -% to distinct variables) and hence cannot be reliably mapped to Coq as an evar, -% but can still be considered as an implicit argument. -% By loading in the context get-option "HOAS:holes" tt one forces that -% behavior. Here a convenience macro to be put on the LHS of => -macro @holes! :- get-option "HOAS:holes" tt. - -% Similarly, some APIs take a term skeleton in input. In that case unification -% variables are totally disregarded (not even mapped to Coq evars). They are -% interpreted as the {{ lib:elpi.hole }} constant, which represents an implicit -% argument. As a consenque these APIs don't modify the input term at all, but -% rather return a copy. Note that if {{ lib:elpi.hole }} is used directly, then -% it has to be applied to all variables in scope, since Coq erases variables -% that are not used. For example using {{ forall x : nat, lib:elpi.hole }} as -% a term skeleton is equivalent to {{ nat -> lib:elpi.hole }}, while -% {{ forall x : nat, lib:elpi.hole x lib:elpi.hole more args }} puts x in -% the scope of the hole (and passes to is more args). - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Coq's goals and tactic invocation -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% A Coq goal is essentially a sequent, like the evar_info above, but since it -% has to be manipulated as first class Elpi data, it is represented in a slightly -% different way. For example -% -% x : t -% y := v : x -% ---------- -% g x y -% -% is represented by the following term of type sealed-goal -% -% nabla x1\ -% nabla x2\ -% seal -% (goal -% [def x2 `y` x1 , decl x1 `x` ] -% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2) -% (Arguments x1 x2)) - -kind goal type. -kind sealed-goal type. -type nabla (term -> sealed-goal) -> sealed-goal. -type seal goal -> sealed-goal. - -typeabbrev goal-ctx (list prop). -type goal goal-ctx -> term -> term -> term -> list argument -> goal. - -% A sealed-goal closes with nabla the bound names of a -% -% (goal Ctx RawSolution Ty Solution Arguments) -% -% where Ctx is a list of decl or def and Solution is a unification variable -% to be assigned to a term of type Ty in order to make progress. -% RawSolution is used as a trigger: when a term is assigned to it, it is -% elaborated against Ty and the resulting term is assigned to Solution. -% -% Arguments contains data attached to the goal, which lives in its context -% and can be used by tactics to solve the goals. - -% A tactic (an elpi predicate which makes progress on a Coq goal) is -% a predicate of type -% sealed-goal -> list sealed-goal -> prop -% -% while the main entry point for a tactic written in Elpi is solve -% which has type -% goal -> list sealed-goal -> prop -% -% The utility (coq.ltac.open T G GL) postulates all the variables bounds -% by nabla and loads the goal context before calling T on the unsealed -% goal. The invocation of a tactic with arguments -% 3 x "y" (h x) -% on the previous goal results in the following Elpi query: -% -% (pi x1\ decl x1 `x` => -% pi x2\ def x2 `y` x1 => -% declare-evar -% [def x2 `y` x1 , decl x1 `x` ] -% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)), -% (coq.ltac.open solve -% (nabla x1\ nabla x2\ seal -% (goal -% [def x2 `y` x1 , decl x1 `x` ] -% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2) -% [int 3, str `x`, str`y`, trm (app[const `h`,x1])])) -% NewGoals) -% -% If the goal sequent contains other evars, then a tactic invocation is -% an Elpi query made of the conjunction of all the declare-evar queries -% corresponding to these evars and the query corresponding to the goal -% sequent. NewGoals can be assigned to a list of goals that should be -% declared as open. Omitted goals are shelved. If NewGoals is not -% assigned, then all unresolved evars become new goals, but the order -% of such goals is not specified. - -% The file elpi-ltac.elpi provides a few combinators (other than coq.ltac.open) -% in the tradition of LCF tacticals. The main difference is that the arguments -% of custom written tactics must not be passed as predicate arguments but rather -% put in the goal they receive. Indeed these arguments can contain terms, and -% their bound variables cannot escape the seal. coq.ltac.set-goal-arguments -% can be used to put an argument from the current goal context into another -% goal. The coq.ltac.call utility can call Ltac1 code (written in Coq) and -% pass arguments via this mechanism. - -% Last, since Elpi is alerady a logic programming language with primitive -% support for unification variables, most of the work of a tactic can be -% performed without using tacticals (which work on sealed goals) but rather -% in the context of the original goal. The last step is typically to call -% the refine utility with a term synthesized by the tactic or invoke some -% Ltac1 code on that term (e.g. to call vm_compute, see also the example -% on the reflexive tactic). - -% ----- Multi goals tactics. ---- -% Coq provides goal selectors, such as all:, to pass to a tactic more than one -% goal. In order to write such a tactic, Coq-Elpi provides another entry point -% called msolve. To be precise, if there are two goals under focus, say and -% , then all: elpi tac runs the following query -% -% msolve [,] NewGoals ; % note the disjunction -% coq.ltac.all (coq.ltac.open solve) [,] NewGoals -% -% So, if msolve has no clause, Coq-Elpi will use solve on all the goals -% independently. If msolve has a cluse, then it can manipulate the entire list -% of sealed goals. Note that the argument is in both and but -% it is interpreted in both contexts independently. If both goals have a proof -% variable named "x" then passing (@eq_refl _ x) as equips both goals with -% a (raw) proof that "x = x", no matter what their type is. - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Declarations for Coq's API (environment read/write access, etc). -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -% tt = Yes, ff = No, unspecified = No (unspecified means "_" or a variable). -typeabbrev opaque? bool. macro @opaque! :- tt. macro @transparent! :- ff. - -%%%%%%% Attributes to be passed to APIs as in @local! => coq.something %%%%%%%% - -macro @primitive! :- get-option "coq:primitive" tt. % primitive records -macro @reversible! :- get-option "coq:reversible" tt. % coercions -macro @no-tc! :- get-option "coq:no_tc" tt. % skip typeclass inference - -macro @uinstance! I :- get-option "coq:uinstance" I. % universe instance - -% declaration of universe polymorphic constants -% The first list is the one of the unvierse variables being bound -% The first boolean is tt if this list can be extended by Coq (or it has to -% mention all universes actually used) -% The second list if the one with the constaints amond where universes -% The second boolean is tt if this list can be extended by Coq or it has to -% mention all universe constraints actually required to type check the -% declaration) -macro @udecl! Vs LV Cs LC :- get-option "coq:udecl" (upoly-decl Vs LV Cs LC). -macro @udecl-cumul! Vs LV Cs LC :- get-option "coq:udecl-cumul" (upoly-decl-cumul Vs LV Cs LC). -macro @univpoly! :- @udecl! [] tt [] tt. -macro @univpoly-cumul! :- @udecl-cumul! [] tt [] tt. - -macro @ppwidth! N :- get-option "coq:ppwidth" N. % printing width -macro @ppall! :- get-option "coq:pp" "all". % printing all -macro @ppmost! :- get-option "coq:pp" "most". % printing most of contents -macro @pplevel! N :- get-option "coq:pplevel" N. % printing precedence (for parentheses) - -macro @keepunivs! :- get-option "coq:keepunivs" tt. % skeletons elaboration -macro @dropunivs! :- get-option "coq:keepunivs" ff. % add-indt/add-const - -macro @using! S :- get-option "coq:using" S. % like the #[using=S] attribute - -macro @inline-at! N :- get-option "coq:inline" (coq.inline.at N). % like Inline(N) -macro @inline! N :- get-option "coq:inline" coq.inline.default. % like - -macro @redflags! F :- get-option "coq:redflags" F. % for whd & co - -% both arguments are strings eg "8.12.0" "use foo instead" -macro @deprecated! Since Msg :- - get-option "coq:deprecated" (pr Since Msg). - -macro @ltacfail! N :- get-option "ltac:fail" N. - -% retrocompatibility macro for Coq v8.10 -macro @coercion! :- [coercion reversible]. - - -% Attributes for a record field. Can be left unspecified, see defaults -% below. -kind field-attribute type. -type coercion coercion-status -> field-attribute. % default off -type canonical bool -> field-attribute. % default true, if field is named - -% Status of a record field w.r.t. coercions -kind coercion-status type. -type regular coercion-status. -type reversible coercion-status. -type off coercion-status. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% builtins %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% This section contains the API to access Coq -% The marker *E* means *experimental*, i.e. use at your own risk, it may change -% substantially or even disappear in future versions. - - -% -- Misc --------------------------------------------------------- - -% [coq.info ...] Prints an info message -external type coq.info variadic any prop. - -% [coq.notice ...] Prints a notice message -external type coq.notice variadic any prop. - -% [coq.say ...] Prints a notice message -external type coq.say variadic any prop. - -% [coq.warn ...] Prints a generic warning message -external type coq.warn variadic any prop. - -% [coq.warning Category Name ...] -% Prints a warning message with a Name and Category which can be used -% to silence this warning or turn it into an error. See coqc -w command -% line option -external type coq.warning string -> string -> variadic any prop. - -% [coq.error ...] Prints and *aborts* the program. It is a fatal error for -% Elpi and Ltac -external type coq.error variadic any prop. - -% [coq.version VersionString Major Minor Patch] Fetches the version of Coq, -% as a string and as 3 numbers -external pred coq.version o:string, o:int, o:int, o:int. - - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% API for objects belonging to the logic -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% -- Environment: names ----------------------------------------------- - -% To make the API more precise we use different data types for the names -% of global objects. -% Note: [ctype \"bla\"] is an opaque data type and by convention it is -% written [@bla]. - -% Global constant name -typeabbrev constant (ctype "constant"). - - -% Inductive type name -typeabbrev inductive (ctype "inductive"). - - -% Inductive constructor name -typeabbrev constructor (ctype "constructor"). - - -% Global objects: inductive types, inductive constructors, definitions -kind gref type. -type const constant -> gref. % Nat.add, List.append, ... -type indt inductive -> gref. % nat, list, ... -type indc constructor -> gref. % O, S, nil, cons, ... - -% [id] is a name that matters, we piggy back on Elpi's strings. -% Note: [name] is a name that does not matter. -typeabbrev id string. - - -% Name of a module /*E*/ -typeabbrev modpath (ctype "modpath"). - - -% Name of a module type /*E*/ -typeabbrev modtypath (ctype "modtypath"). - - -% Result of coq.locate-all -kind located type. -type loc-gref gref -> located. -type loc-modpath modpath -> located. -type loc-modtypath modtypath -> located. -type loc-abbreviation abbreviation -> located. - -% [coq.locate-all Name Located] finds all possible meanings of a string. -% Does not fail. -external pred coq.locate-all i:id, o:list located. - -% [coq.locate Name GlobalReference] locates a global definition, inductive -% type or constructor via its name. -% It unfolds syntactic notations, e.g. "Notation old_name := new_name." -% It undestands qualified names, e.g. "Nat.t". -% It understands Coqlib Registered names using the "lib:" prefix, -% eg "lib:core.bool.true". -% It's a fatal error if Name cannot be located. -external pred coq.locate i:id, o:gref. - -% -- Environment: read ------------------------------------------------ - -% Note: The type [term] is defined in coq-HOAS.elpi - -% [coq.env.typeof GR Ty] reads the type Ty of a global reference. -% Supported attributes: -% - @uinstance! I (default: fresh instance I) -external pred coq.env.typeof i:gref, o:term. - -% [coq.env.global GR T] turns a global reference GR into a term, or -% viceversa. -% T = (global GR) or, if GR points to a universe polymorphic term, -% T = (pglobal GR I). -% Supported attributes: -% - @uinstance! I (default: fresh instance I) -external pred coq.env.global o:gref, o:term. - -external pred coq.env.indt % reads the inductive type declaration for the environment. -% Supported attributes: -% - @uinstance! I (default: fresh instance I) - i:inductive, % reference to the inductive type - o:bool, % tt if the type is inductive (ff for co-inductive) - o:int, % number of parameters - o:int, % number of parameters that are uniform (<= parameters) - o:term, % type of the inductive type constructor including parameters - o:list constructor, % list of constructor names - o:list term. % list of the types of the constructors (type of KNames) including parameters - -external pred coq.env.indt-decl % reads the inductive type declaration for the environment. -% Supported attributes: -% - @uinstance! I (default: fresh instance I) - i:inductive, % reference to the inductive type - o:indt-decl. % HOAS description of the inductive type - -% [coq.env.indc->indt K I N] finds the inductive I to which constructor K -% belongs and its position N among the other constructors -external pred coq.env.indc->indt i:constructor, o:inductive, o:int. - -% [coq.env.indc GR ParamNo UnifParamNo Kno Ty] reads the type Ty of an -% inductive constructor GR, as well as -% the number of parameters ParamNo and uniform parameters -% UnifParamNo and the number of the constructor Kno (0 based). -% Supported attributes: -% - @uinstance! I (default: fresh instance I) -external pred coq.env.indc i:constructor, o:int, o:int, o:int, o:term. - -% [coq.env.informative? Ind] Checks if Ind is informative, that is, if -% it can be eliminated to build a Type. Inductive types in Type -% are -% informative, as well a singleton types in Prop (which are -% regarded as not non-informative). -external pred coq.env.informative? i:inductive. - -% [coq.env.record? Ind PrimProjs] checks if Ind is a record (PrimProjs = tt -% if Ind has primitive projections) -external pred coq.env.record? i:inductive, o:bool. - -% [coq.env.recursive? Ind] checks if Ind is recursive -external pred coq.env.recursive? i:inductive. - -% [coq.env.opaque? GR] checks if GR is an opaque constant -external pred coq.env.opaque? i:constant. - -% [coq.env.univpoly? GR PolyArity] checks if GR is universe polymorphic and -% if so returns the number of universe variables -external pred coq.env.univpoly? i:gref, o:int. - -% [coq.env.const GR Bo Ty] reads the type Ty and the body Bo of constant -% GR. -% Opaque constants have Bo = none. -% Supported attributes: -% - @uinstance! I (default: fresh instance I) -external pred coq.env.const i:constant, o:option term, o:term. - -% [coq.env.const-body GR Bo] reads the body of a constant, even if it is -% opaque. -% If such body is none, then the constant is a true axiom. -% Supported attributes: -% - @uinstance! I (default: fresh instance I) -external pred coq.env.const-body i:constant, o:option term. - -% [coq.env.primitive? GR] tests if GR is a primitive constant (like uin63 -% addition) or a primitive type (like uint63) -external pred coq.env.primitive? i:constant. - -% [coq.locate-module ModName ModPath] locates a module. It's a fatal error -% if ModName cannot be located. *E* -external pred coq.locate-module i:id, o:modpath. - -% [coq.locate-module-type ModName ModPath] locates a module. It's a fatal -% error if ModName cannot be located. *E* -external pred coq.locate-module-type i:id, o:modtypath. - -% Contents of a module -kind module-item type. -type submodule modpath -> list module-item -> module-item. -type module-type modtypath -> module-item. -type gref gref -> module-item. -type module-functor modpath -> list modtypath -> module-item. -type module-type-functor modtypath -> list modtypath -> module-item. - -% [coq.env.module MP Contents] lists the contents of a module (recurses on -% submodules) *E* -external pred coq.env.module i:modpath, o:list module-item. - -% [coq.env.module-type MTP Entries] lists the items made visible by module -% type (does not recurse on submodules) *E* -external pred coq.env.module-type i:modtypath, o:list id. - -% [coq.env.section GlobalObjects] lists the global objects that are marked -% as to be abstracted at the end of the enclosing sections -external pred coq.env.section o:list constant. - -% [coq.env.dependencies GR MP Deps] Computes the direct dependencies of GR. -% If MP is given, Deps only contains grefs from that module -external pred coq.env.dependencies i:gref, i:modpath, o:coq.gref.set. - -% [coq.env.transitive-dependencies GR MP Deps] Computes the transitive -% dependencies of GR. If MP is given, Deps only contains grefs from that -% module -external pred coq.env.transitive-dependencies i:gref, i:modpath, - o:coq.gref.set. - -% [coq.env.term-dependencies T S] Computes all the grefs S occurring in the -% term T -external pred coq.env.term-dependencies i:term, o:coq.gref.set. - -% [coq.env.current-path Path] lists the current module path -external pred coq.env.current-path o:list string. - -% [coq.env.current-section-path Path] lists the current section path -external pred coq.env.current-section-path o:list string. - -% Deprecated, use coq.env.opaque? - pred coq.env.const-opaque? i:constant. - coq.env.const-opaque? C :- - coq.warning "elpi.deprecated" "elpi.const-opaque" "use coq.env.opaque? in place of coq.env.const-opaque?", - coq.env.opaque? C. - - -% Deprecated, use coq.env.primitive? - pred coq.env.const-primitive? i:constant. - coq.env.const-primitive? C :- - coq.warning "elpi.deprecated" "elpi.const-primitive" "use coq.env.primitive? in place of coq.env.const-primitive?", - coq.env.primitive? C. - - -% -- Environment: write ----------------------------------------------- - -% Note: (monomorphic) universe constraints are taken from ELPI's -% constraints store. Use coq.univ-* in order to add constraints (or any -% higher level facility as coq.typecheck). Load in the context attributes -% such as @univpoly!, @univpoly-cumul!, @udecl! or @udecl-cumul! in order to -% declare universe polymorphic constants or inductives. - -% [coq.env.add-const Name Bo Ty Opaque C] Declare a new constant: C gets a -% constant derived from Name -% and the current module; Ty can be left unspecified and in that case -% the -% inferred one is taken (as in writing Definition x := t); Bo can be -% left -% unspecified and in that case an axiom is added (or a section variable, -% if a section is open and @local! is used). Omitting the body and the type -% is -% an error. Note: using this API for declaring an axiom or a section -% variable is -% deprecated, use coq.env.add-axiom or coq.env.add-section-variable -% instead. -% Supported attributes: -% - @local! (default: false) -% - @using! (default: section variables actually used) -% - @univpoly! (default unset) -% - @udecl! (default unset) -% - @dropunivs! (default: false, drops all universe constraints from the -% store after the definition) -% -external pred coq.env.add-const i:id, i:term, i:term, i:opaque?, - o:constant. - -% [coq.env.add-axiom Name Ty C] Declare a new axiom: C gets a constant -% derived from Name -% and the current module. -% Supported attributes: -% - @local! (default: false) -% - @univpoly! (default unset) -% - @using! (default: section variables actually used) -% - @inline! (default: no inlining) -% - @inline-at! N (default: no inlining) -external pred coq.env.add-axiom i:id, i:term, o:constant. - -% [coq.env.add-section-variable Name Ty C] Declare a new section variable: C -% gets a constant derived from Name -% and the current module -external pred coq.env.add-section-variable i:id, i:term, o:constant. - -% [coq.env.add-indt Decl I] Declares an inductive type. -% Supported attributes: -% - @dropunivs! (default: false, drops all universe constraints from the -% store after the definition) -% - @primitive! (default: false, makes records primitive) -external pred coq.env.add-indt i:indt-decl, o:inductive. - -% Interactive module construction - -% Coq Module inline directive -kind coq.inline type. -type coq.inline.no coq.inline. % Coq's [no inline] (aka !) -type coq.inline.default coq.inline. % The default, can be omitted -type coq.inline.at int -> coq.inline. % Coq's [inline at ] - -% [coq.env.fresh-global-id ID FID] Generates an id FID which is fresh in -% the current module and looks similar to ID, i.e. it is ID concatenated -% with a number, starting from 1. -% [coq.env.fresh-global-id X X] can be used to check if X is taken -external pred coq.env.fresh-global-id i:id, o:id. - -external pred coq.env.begin-module-functor % Starts a functor. bla bla - i:id, % The name of the functor - i:option modtypath, % Its module type (optional) - i:list (pair id modtypath). % Parameters of the functor (optional) - - -pred coq.env.begin-module i:id, i:option modtypath. -coq.env.begin-module Name MP :- coq.env.begin-module-functor Name MP []. - - -% [coq.env.end-module ModPath] end the current module that becomes known as -% ModPath *E*. bla bla -external pred coq.env.end-module o:modpath. - -external pred coq.env.begin-module-type-functor % Starts a module type functor *E*. bla bla - i:id, % The name of the functor - i:list (pair id modtypath). % The parameters of the functor (optional) - - -pred coq.env.begin-module-type i:id. -coq.env.begin-module-type Name :- - coq.env.begin-module-type-functor Name []. - - -% [coq.env.end-module-type ModTyPath] end the current module type that -% becomes known as ModPath *E*. bla bla -external pred coq.env.end-module-type o:modtypath. - -external pred coq.env.apply-module-functor % Applies a functor *E*. bla bla - i:id, % The name of the new module - i:option modtypath, % Its module type (optional) - i:modpath, % The functor being applied (optional) - i:list modpath, % Its arguments (optional) - i:coq.inline, % Arguments inlining (optional) - o:modpath. % The modpath of the new module - -external pred coq.env.apply-module-type-functor % Applies a type functor *E*. bla bla - i:id, % The name of the new module type - i:modtypath, % The functor (optional) - i:list modpath, % Its arguments (optional) - i:coq.inline, % Arguments inlining (optional) - o:modtypath. % The modtypath of the new module type - -% [coq.env.include-module ModPath Inline (optional)] is like the vernacular -% Include, Inline can be omitted *E*. bla bla -external pred coq.env.include-module i:modpath, i:coq.inline. - -% [coq.env.include-module-type ModTyPath Inline (optional)] is like the -% vernacular Include Type, Inline can be omitted *E*. bla bla -external pred coq.env.include-module-type i:modtypath, i:coq.inline. - -% [coq.env.import-module ModPath] is like the vernacular Import *E* -external pred coq.env.import-module i:modpath. - -% [coq.env.export-module ModPath] is like the vernacular Export *E* -external pred coq.env.export-module i:modpath. - -% Support for sections is limited, in particular sections and -% Coq quotations may interact in surprising ways. For example -% Section Test. -% Variable x : nat. -% Elpi Query lp:{{ coq.say {{ x }} }}. -% works since x is a global Coq term while -% Elpi Query lp:{{ -% coq.env.begin-section "Test", -% coq.env.add-const "x" _ {{ nat }} _ @local! GRX, -% coq.say {{ x }} -% }}. -% may work in a surprising way or may not work at all since -% x is resolved before the section is started hence it cannot -% denote the same x as before. - -% [coq.env.begin-section Name] starts a section named Name *E* -external pred coq.env.begin-section i:id. - -% [coq.env.end-section] end the current section *E* -external pred coq.env.end-section . - -% [coq.env.projections StructureName Projections] given a record -% StructureName lists all projections -external pred coq.env.projections i:inductive, o:list (option constant). - -% [coq.env.primitive-projections StructureName Projections] given a record -% StructureName lists all primitive projections -external pred coq.env.primitive-projections i:inductive, - o:list (option (pair projection int)). - -% -- Sorts (and their universe level, if applicable) ---------------- - -% Warning: universe polymorphism has to be considered experimental *E* as -% a feature, not just as a set of APIs. Unfortunately some of the -% current complexity is exposed to the programmer, bare with us. -% -% The big bang is that in Coq one has terms, types and sorts (which are -% the types of types). Some sorts (as of today only Type) some with -% a universe level, on paper Type_i for some i. At the sort level -% Coq features some form of subtyping: a function expecting a function -% to Type, e.g. nat -> Type, can receive a function to Prop, since -% Prop <= Type. So far, so good. But what are these levels i -% exactly? -% -% Universe levels are said to be "algebraic", they are made of -% variables (see the next section) and the two operators +1 and max. -% This is a sort of internal optimization that leaks to the -% user/programmer. Indeed these universe levels cannot be (directly) used -% in all APIs morally expecting a universe level "i", in particular -% the current constraint engine cannot handle constraint with an -% algebraic level on the right, e.g. i <= j+1. Since some APIs only -% accept universe variables, we provide the coq.univ.variable API -% which is able to craft a universe variable which is roughly -% equivalent to an algebraic universe, e.g. k such that j+1 = k. -% -% Coq-Elpi systematically purges algebraic universes from terms (and -% types and sorts) when one reads them from the environment. This -% makes the embedding of terms less precise than what it could be. -% The different data types stay, since Coq will eventually become -% able to handle algebraic universes consistently, making this purging -% phase unnecessary. - -% universe level (algebraic: max, +1, univ.variable) -typeabbrev univ (ctype "univ"). - - -% Sorts (kinds of types) -kind sort type. -type prop sort. % impredicative sort of propositions -type sprop sort. % impredicative sort of propositions with definitional proof irrelevance -type typ univ -> - sort. % predicative sort of data (carries a universe level) - -% [coq.sort.leq S1 S2] constrains S1 <= S2 -external pred coq.sort.leq o:sort, o:sort. - -% [coq.sort.eq S1 S2] constrains S1 = S2 -external pred coq.sort.eq o:sort, o:sort. - -% [coq.sort.sup S1 S2] constrains S2 = S1 + 1 -external pred coq.sort.sup o:sort, o:sort. - -% [coq.sort.pts-triple S1 S2 S3] constrains S3 = sort of product with domain -% in S1 and codomain in S2 -external pred coq.sort.pts-triple o:sort, o:sort, o:sort. - -% [coq.univ.print] prints the set of universe constraints -external pred coq.univ.print . - -% [coq.univ.new U] A fresh universe. -external pred coq.univ.new o:univ. - -% [coq.univ Name U] Finds a named unvierse. Can fail. -external pred coq.univ o:id, o:univ. - -% [coq.univ.global? U] succeeds if U is a global universe -external pred coq.univ.global? i:univ. - -% [coq.univ.constraints CL] gives the list of constraints, see also -% coq.univ.variable.constraints -external pred coq.univ.constraints o:list univ-constraint. - -% -- Universe variables ------ - -% universe level variable -typeabbrev univ.variable (ctype "univ.variable"). - - -% [coq.univ.variable U L] relates a univ.variable L to a univ U -external pred coq.univ.variable o:univ, o:univ.variable. - -% [coq.univ.variable.constraints L CL] gives the list of constraints on L. -% Can be used to craft a strict upoly-decl -external pred coq.univ.variable.constraints i:univ.variable, - o:list univ-constraint. - -% [coq.univ.variable.of-term T S] collects all univ.variables occurring in T -external pred coq.univ.variable.of-term i:term, o:coq.univ.variable.set. - -% -- Universe instance (for universe polymorphic global terms) ------ - -% As of today a universe polymorphic constant can only be instantiated -% with universe level variables. That is f@{Prop} is not valid, nor -% is f@{u+1}. One can only write f@{u} for any u. -% -% A univ-instance is morally a list of universe level variables, -% but its list syntax is hidden in the terms. If you really need to -% craft or inspect one of these, the following APIs can help you. -% -% Most of the time the user is expected to use coq.env.global which -% crafts a fresh, appropriate, universe instance and possibly unify that -% term (of the instance it contains) with another one. - -% Universes level instance for a universe-polymorphic constant -typeabbrev univ-instance (ctype "univ-instance"). - - -% [coq.univ-instance UI UL] relates a univ-instance UI and a list of -% universe level variables UL -external pred coq.univ-instance o:univ-instance, o:list univ.variable. - -% [coq.univ-instance.unify-eq GR UI1 UI2 Diagnostic] unifies the two -% universe instances for the same gref -external pred coq.univ-instance.unify-eq i:gref, i:univ-instance, - i:univ-instance, o:diagnostic. - -% [coq.univ-instance.unify-leq GR UI1 UI2 Diagnostic] unifies the two -% universe instances for the same gref. Note: if the GR is not *cumulative* -% (see Cumulative or #[universes(cumulative)]) then this API imposes an -% equality constraint. -external pred coq.univ-instance.unify-leq i:gref, i:univ-instance, - i:univ-instance, o:diagnostic. - -% -- Declaration of universe polymorphic global terms ----------- - -% These are the data types used to declare how constants -% and inductive types should be declared (see also the @udecl! -% and -% @udecl-cumul! macros). Note that only inductive types can be -% declared as cumulative. - -% Constraint between two universes level variables -kind univ-constraint type. -type lt univ.variable -> univ.variable -> univ-constraint. -type le univ.variable -> univ.variable -> univ-constraint. -type eq univ.variable -> univ.variable -> univ-constraint. - -% Variance of a universe level variable -kind univ-variance type. -type auto univ.variable -> univ-variance. -type covariant univ.variable -> univ-variance. -type invariant univ.variable -> univ-variance. -type irrelevant univ.variable -> univ-variance. - -% Constraints for a non-cumulative declaration. Boolean tt means loose -% (e.g. the '+' in f@{u v + | u < v +}) -kind upoly-decl type. -type upoly-decl list univ.variable -> bool -> list univ-constraint -> - bool -> upoly-decl. - -% Constraints for a cumulative declaration. Boolean tt means loose (e.g. -% the '+' in f@{u v + | u < v +}) -kind upoly-decl-cumul type. -type upoly-decl-cumul list univ-variance -> bool -> - list univ-constraint -> bool -> upoly-decl-cumul. - -% -- Primitive -------------------------------------------------------- - -typeabbrev uint63 (ctype "uint63"). - - -typeabbrev float64 (ctype "float64"). - - -typeabbrev projection (ctype "projection"). - - -% Primitive values -kind primitive-value type. -type uint63 uint63 -> primitive-value. % unsigned integers over 63 bits -type float64 float64 -> - primitive-value. % double precision foalting points -type proj projection -> int -> primitive-value. % primitive projection - -% [coq.uint63->int U I] Transforms a primitive unsigned integer U into an -% elpi integer I. Fails if it does not fit. -external pred coq.uint63->int i:uint63, o:int. - -% [coq.int->uint63 I U] Transforms an elpi integer I into a primitive -% unsigned integer U. Fails if I is negative. -external pred coq.int->uint63 i:int, o:uint63. - -% [coq.float64->float F64 F] Transforms a primitive float on 64 bits to an -% elpi one. Currently, it should not fail. -external pred coq.float64->float i:float64, o:float. - -% [coq.float->float64 F F64] Transforms an elpi float F to a primitive float -% on 64 bits. Currently, it should not fail. -external pred coq.float->float64 i:float, o:float64. - -% [coq.primitive.projection-unfolded P PU] Relates a primitive projection P -% to its unfolded version PU. PU is still a primitive projection, but it is -% displayed as a match and some Ltac code can see that. -external pred coq.primitive.projection-unfolded o:projection, - o:projection. - - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% API for extra logical objects -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% -- Databases (TC, CS, Coercions) ------------------------------------ - -% Pattern for canonical values -kind cs-pattern type. -type cs-gref gref -> cs-pattern. -type cs-prod cs-pattern. -type cs-default cs-pattern. -type cs-sort sort -> cs-pattern. - -% Canonical Structure instances: (cs-instance Proj ValPat Inst) -kind cs-instance type. -type cs-instance gref -> cs-pattern -> gref -> cs-instance. - -% [coq.CS.declare-instance GR] Declares GR as a canonical structure -% instance. -% Supported attributes: -% - @local! (default: false) -external pred coq.CS.declare-instance i:gref. - -% [coq.CS.db Db] reads all instances -external pred coq.CS.db o:list cs-instance. - -% [coq.CS.db-for Proj Value Db] reads all instances for a given Projection -% or canonical Value, or both -external pred coq.CS.db-for i:gref, i:cs-pattern, o:list cs-instance. - -% [coq.TC.declare-class GR] Declare GR as a type class -external pred coq.TC.declare-class i:gref. - -% [coq.elpi.toposort Graph Nodes in toposort order] takes a graph and -% returns the nodes in topological order -external pred coq.elpi.toposort i:list (pair A (list A)), o:list A. - -% Type class instance priority -kind tc-priority type. -type tc-priority-given int -> tc-priority. % User given priority -type tc-priority-computed int -> tc-priority. % Coq computed priority - -% Type class instance with priority -kind tc-instance type. -type tc-instance gref -> tc-priority -> tc-instance. - -% [coq.TC.declare-instance GR Priority] Declare GR as a Global type class -% instance with Priority. -% Supported attributes: -% - @global! (default: true) -external pred coq.TC.declare-instance i:gref, i:int. - -% [coq.TC.db Instances] reads all type class instances -external pred coq.TC.db o:list tc-instance. - -% [coq.TC.db-tc TypeClasses] reads all type classes -external pred coq.TC.db-tc o:list gref. - -% [coq.TC.db-for GR InstanceList] reads all instances of the given class GR. -% Instances are in their precedence order. -external pred coq.TC.db-for i:gref, o:list tc-instance. - -% [coq.TC.get-inst-prio ClassGR InstGR InstPrio] reads the priority of an -% instance -external pred coq.TC.get-inst-prio i:gref, i:gref, o:tc-priority. - -% [coq.TC.class? GR] checks if GR is a class -external pred coq.TC.class? i:gref. - -% Node of the coercion graph -kind class type. -type funclass class. -type sortclass class. -type grefclass gref -> class. - -% Edge of the coercion graph -kind coercion type. -type coercion gref -> int -> gref -> class -> - coercion. % ref, nparams, src, tgt - -% [coq.coercion.declare C] Declares C = (coercion GR NParams From To) as a -% coercion From >-> To. -% NParams can always be omitted, since it is inferred. -% If From or To is unspecified, then the endpoints are inferred. -% Supported attributes: -% - @global! (default: false) -% - @nonuniform! (default: false) -% - @reversible! (default: false) -external pred coq.coercion.declare i:coercion. - -% [coq.coercion.db L] reads all declared coercions -external pred coq.coercion.db o:list coercion. - -% [coq.coercion.db-for From To L] L is a path From -> To -external pred coq.coercion.db-for i:class, i:class, - o:list (pair gref int). - -% Deprecated, use coq.env.projections -pred coq.CS.canonical-projections i:inductive, o:list (option constant). -coq.CS.canonical-projections I L :- - coq.warning "elpi.deprecated" "elpi.canonical-projections" "use coq.env.projections in place of coq.CS.canonical-projections", - coq.env.projections I L. - - -% -- Coq's Hint DB ------------------------------------- - -% Locality of hints is a delicate matter since the Coq default -% is, in some cases, to make an hint active even if the module it belongs -% to is not imported (just merely required, which can happen -% transitively). -% Coq is aiming at changing the default to #[export], that makes an -% hint active only when its enclosing module is imported. -% See: -% https://coq.discourse.group/t/change-of-default-locality-for-hint-commands-in-coq-8-13/1140 -% -% This old behavior is available via the @global! flag, but is discouraged. -% - -% Hint Mode -kind hint-mode type. -type mode-ground hint-mode. % No Evar -type mode-input hint-mode. % No Head Evar -type mode-output hint-mode. % Anything - -% [coq.hints.add-mode GR DB Mode] Adds a mode declaration to DB about -% GR. -% Supported attributes: -% - @local! (default is export) -% - @global! (discouraged, may become deprecated) -external pred coq.hints.add-mode i:gref, i:string, i:list hint-mode. - -% [coq.hints.modes GR DB Modes] Gets all the mode declarations in DB about -% GR -external pred coq.hints.modes i:gref, i:string, o:list (list hint-mode). - -% [coq.hints.set-opaque C DB Opaque] Like Hint Opaque C : DB (or Hint -% Transparent, if the boolean is ff). -% Supported attributes: -% - @local! (default is export) -% - @global! (discouraged, may become deprecated) -external pred coq.hints.set-opaque i:constant, i:string, i:bool. - -% [coq.hints.opaque C DB Opaque] Reads if constant C is opaque (tt) or -% transparent (ff) in DB -external pred coq.hints.opaque i:constant, i:string, o:bool. - -% [coq.hints.add-resolve GR DB Priority Pattern] Like Hint Resolve GR | -% Priority Pattern : DB. -% Supported attributes: -% - @local! (default is export) -% - @global! (discouraged, may become deprecated) -external pred coq.hints.add-resolve i:gref, i:string, i:int, i:term. - -% -- Coq's notational mechanisms ------------------------------------- - -% Implicit status of an argument -kind implicit_kind type. -type implicit implicit_kind. % regular implicit argument, eg Arguments foo [x] -type maximal implicit_kind. % maximally inserted implicit argument, eg Arguments foo {x} -type explicit implicit_kind. % explicit argument, eg Arguments foo x - -% [coq.arguments.implicit GR Imps] reads the implicit arguments declarations -% associated to a global reference. See also the [] and {} flags for the -% Arguments command. -external pred coq.arguments.implicit i:gref, o:list (list implicit_kind). - -% [coq.arguments.set-implicit GR Imps] sets the implicit arguments -% declarations associated to a global reference. -% Unspecified means explicit. -% See also the [] and {} flags for the Arguments command. -% Supported attributes: -% - @global! (default: false) -external pred coq.arguments.set-implicit i:gref, - i:list (list implicit_kind). - -% [coq.arguments.set-default-implicit GR] sets the default implicit -% arguments declarations associated to a global reference. -% See also the "default implicits" flag to the Arguments command. -% Supported attributes: -% - @global! (default: false) -external pred coq.arguments.set-default-implicit i:gref. - -% [coq.arguments.name GR Names] reads the Names of the arguments of a global -% reference. See also the (f (A := v)) syntax. -external pred coq.arguments.name i:gref, o:list (option id). - -% [coq.arguments.set-name GR Names] sets the Names of the arguments of a -% global reference. -% See also the :rename flag to the Arguments command. -% Supported attributes: -% - @global! (default: false) -external pred coq.arguments.set-name i:gref, i:list (option id). - -% [coq.arguments.scope GR Scopes] reads the notation scope of the arguments -% of a global reference. See also the %scope modifier for the Arguments -% command -external pred coq.arguments.scope i:gref, o:list (list id). - -% [coq.arguments.set-scope GR Scopes] sets the notation scope of the -% arguments of a global reference. -% Scope can be a scope name or its delimiter. -% See also the %scope modifier for the Arguments command. -% Supported attributes: -% - @global! (default: false) -external pred coq.arguments.set-scope i:gref, i:list (list id). - -% Strategy for simplification tactics -kind simplification_strategy type. -type never simplification_strategy. % Arguments foo : simpl never -type when list int -> option int -> - simplification_strategy. % Arguments foo .. / .. ! .. -type when-nomatch list int -> option int -> - simplification_strategy. % Arguments foo .. / .. ! .. : simpl nomatch - -% [coq.arguments.simplification GR Strategy] reads the behavior of the -% simplification tactics. Positions are 0 based. See also the ! and / -% modifiers for the Arguments command -external pred coq.arguments.simplification i:gref, - o:option simplification_strategy. - -% [coq.arguments.set-simplification GR Strategy] sets the behavior of the -% simplification tactics. -% Positions are 0 based. -% See also the ! and / modifiers for the Arguments command. -% Supported attributes: -% - @global! (default: false) -external pred coq.arguments.set-simplification i:gref, - i:simplification_strategy. - -% [coq.locate-abbreviation Name Abbreviation] locates an abbreviation. It's -% a fatal error if Name cannot be located. -external pred coq.locate-abbreviation i:id, o:abbreviation. - -% Name of an abbreviation -typeabbrev abbreviation (ctype "abbreviation"). - - -% [coq.notation.add-abbreviation Name Nargs Body OnlyParsing Abbreviation] -% Declares an abbreviation Name with Nargs arguments. -% The term must begin with at least Nargs "fun" nodes whose domain is -% ignored, eg (fun _ _ x\ fun _ _ y\ app[global "add",x,y]). -% Supported attributes: -% - @deprecated! (default: not deprecated) -% - @global! (default: false) -external pred coq.notation.add-abbreviation i:id, i:int, i:term, i:bool, - o:abbreviation. - -% [coq.notation.abbreviation Abbreviation Args Body] Unfolds an abbreviation -external pred coq.notation.abbreviation i:abbreviation, i:list term, - o:term. - -% [coq.notation.abbreviation-body Abbreviation Nargs Body] Retrieves the -% body of an abbreviation -external pred coq.notation.abbreviation-body i:abbreviation, o:int, - o:term. - -% [coq.notation.add-abbreviation-for-tactic Name TacticName FixedArgs] -% Declares a parsing rule similar to -% Notation Name X1..Xn := ltac:(elpi TacticName FixedArgs (X1)..(Xn)) -% so that Name can be used in the middle of a term to invoke an -% elpi tactic. While FixedArgs can contain str, int, and trm all -% other arguments will necessarily be terms, and their number is -% not fixed (the user can pass as many as he likes). -% The tactic receives as the elpi.loc attribute the precise location -% at which the term is written (unlike if a regular abbreviation was -% declared by hand). -% A call to coq.notation.add-abbreviation-for-tactic TacName TacName [] -% is equivalent to Elpi Export TacName. -external pred coq.notation.add-abbreviation-for-tactic i:string, - i:string, - i:list argument. - -% Generic attribute value -kind attribute-value type. -type leaf-str string -> attribute-value. -type leaf-loc loc -> attribute-value. -type node list attribute -> attribute-value. - -% Generic attribute -kind attribute type. -type attribute string -> attribute-value -> attribute. - -% -- Coq's pretyper --------------------------------------------------- - -% [coq.sigma.print] Prints Coq's Evarmap and the mapping to/from Elpi's -% unification variables -external pred coq.sigma.print . - -% [coq.typecheck T Ty Diagnostic] typchecks a term T returning its type Ty. -% If Ty is provided, then -% the inferred type is unified (see unify-leq) with it. -% Universe constraints are put in the constraint store. -external pred coq.typecheck i:term, o:term, o:diagnostic. - -% [coq.typecheck-ty Ty U Diagnostic] typchecks a type Ty returning its -% universe U. If U is provided, then -% the inferred universe is unified (see unify-leq) with it. -% Universe constraints are put in the constraint store. -external pred coq.typecheck-ty i:term, o:sort, o:diagnostic. - -% [coq.unify-eq A B Diagnostic] unifies the two terms -external pred coq.unify-eq i:term, i:term, o:diagnostic. - -% [coq.unify-leq A B Diagnostic] unifies the two terms (with cumulativity, -% if they are types) -external pred coq.unify-leq i:term, i:term, o:diagnostic. - -% [coq.elaborate-skeleton T ETy E Diagnostic] elabotares T against the -% expected type ETy. -% T is allowed to contain holes (unification variables) but these are -% not assigned even if the elaborated term has a term in place of the -% hole. Similarly universe levels present in T are disregarded. -% Supported attributes: -% - @keepunivs! (default false, do not disregard universe levels) -% - @no-tc! (default false, do not infer typeclasses) -external pred coq.elaborate-skeleton i:term, o:term, o:term, o:diagnostic. - -% [coq.elaborate-ty-skeleton T U E Diagnostic] elabotares T expecting it to -% be a type of sort U. -% T is allowed to contain holes (unification variables) but these are -% not assigned even if the elaborated term has a term in place of the -% hole. Similarly universe levels present in T are disregarded. -% Supported attributes: -% - @keepunivs! (default false, do not disregard universe levels) -% - @no-tc! (default false, do not infer typeclasses) -external pred coq.elaborate-ty-skeleton i:term, o:sort, o:term, - o:diagnostic. - -% -- Coq's reduction flags ------------------------------------ - -% Flags for lazy, cbv, ... reductions -kind coq.redflag type. -type coq.redflags.beta coq.redflag. -type coq.redflags.delta coq.redflag. % if set then coq.redflags.const disables unfolding -type coq.redflags.match coq.redflag. -type coq.redflags.fix coq.redflag. -type coq.redflags.cofix coq.redflag. -type coq.redflags.zeta coq.redflag. -type coq.redflags.const constant -> - coq.redflag. % enable/disable unfolding - -% Set of flags for lazy, cbv, ... reductions -typeabbrev coq.redflags (ctype "coq.redflags"). - -type coq.redflags.all coq.redflags. -type coq.redflags.allnolet coq.redflags. -type coq.redflags.beta coq.redflags. -type coq.redflags.betadeltazeta coq.redflags. -type coq.redflags.betaiota coq.redflags. -type coq.redflags.betaiotazeta coq.redflags. -type coq.redflags.betazeta coq.redflags. -type coq.redflags.delta coq.redflags. -type coq.redflags.zeta coq.redflags. -type coq.redflags.nored coq.redflags. - -% [coq.redflags.add Flags Options NewFlags] Updates reduction Flags by -% adding Options -external pred coq.redflags.add i:coq.redflags, i:list coq.redflag, - o:coq.redflags. - -% [coq.redflags.sub Flags Options NewFlags] Updates reduction Flags by -% removing Options -external pred coq.redflags.sub i:coq.redflags, i:list coq.redflag, - o:coq.redflags. - -% -- Coq's reduction machines ------------------------------------ - -% [coq.reduction.lazy.whd T Tred] Puts T in weak head normal form. -% Supported attributes: -% - @redflags! (default coq.redflags.all) -external pred coq.reduction.lazy.whd i:term, o:term. - -% [coq.reduction.lazy.norm T Tred] Puts T in normal form. -% Supported attributes: -% - @redflags! (default coq.redflags.all) -external pred coq.reduction.lazy.norm i:term, o:term. - -% [coq.reduction.lazy.bi-norm T Tred] Puts T in normal form only reducing -% beta and iota redexes -external pred coq.reduction.lazy.bi-norm i:term, o:term. - -% [coq.reduction.cbv.norm T Tred] Puts T in normal form using the call by -% value strategy. -% Supported attributes: -% - @redflags! (default coq.redflags.all) -external pred coq.reduction.cbv.norm i:term, o:term. - -% [coq.reduction.vm.norm T Ty Tred] Puts T in normal form using -% [vm_compute]'s machinery. Its type Ty can be omitted (but is recomputed) -external pred coq.reduction.vm.norm i:term, i:term, o:term. - -% [coq.reduction.native.norm T Ty Tred] Puts T in normal form using -% [native_compute]'s machinery. Its type Ty can be omitted (but is -% recomputed). Falls back to vm.norm if native compilation is not available. -external pred coq.reduction.native.norm i:term, i:term, o:term. - -% [coq.reduction.native.available?] Is native compilation available on this -% system/configuration? -external pred coq.reduction.native.available? . - -% Deprecated, use coq.reduction.cbv.norm -pred coq.reduction.cbv.whd_all i:term, o:term. -coq.reduction.cbv.whd_all T R :- - coq.warning "elpi.deprecated" "elpi.cbv-whd-all" "use coq.reduction.cbv.norm in place of coq.reduction.cbv.whd_all", - coq.reduction.cbv.norm T R. - - -% Deprecated, use coq.reduction.vm.norm -pred coq.reduction.vm.whd_all i:term, i:term, o:term. -coq.reduction.vm.whd_all T TY R :- - coq.warning "elpi.deprecated" "elpi.vm-whd-all" "use coq.reduction.vm.norm in place of coq.reduction.vm.whd_all", - coq.reduction.vm.norm T TY R. - - - -pred coq.reduction.lazy.whd_all i:term, o:term. -coq.reduction.lazy.whd_all X Y :- - @redflags! coq.redflags.all => coq.reduction.lazy.whd X Y. - - -% [coq.reduction.eta-contract T Tred] Removes all eta expansions from T -external pred coq.reduction.eta-contract i:term, o:term. - -% -- Coq's conversion strategy tweaks -------------------------- - -% Strategy for conversion test -% expand < ... < level -1 < level 0 < level 1 < ... < opaque -kind conversion_strategy type. -type opaque conversion_strategy. -type expand conversion_strategy. -type level int -> conversion_strategy. % default is 0, aka transparent - -% [coq.strategy.set CL Level] Sets the unfolding priority for all the -% constants in the list CL. See the command Strategy. -external pred coq.strategy.set i:list constant, i:conversion_strategy. - -% [coq.strategy.get C Level] Gets the unfolding priority for C -external pred coq.strategy.get i:constant, o:conversion_strategy. - -% -- Coq's tactics -------------------------------------------- - -% LTac1 tactic expression -typeabbrev ltac1-tactic (ctype "ltac1-tactic"). - - -% [coq.ltac.fail Level ...] Interrupts the Elpi program and calls Ltac's -% fail Level Msg, where Msg is the printing of the remaining arguments. -% Level can be left unspecified and defaults to 0 -external type coq.ltac.fail int -> variadic any prop. - -% [coq.ltac.collect-goals T Goals ShelvedGoals] -% Turns the holes in T into Goals. -% Goals are closed with nablas. -% ShelvedGoals are goals which can be solved by side effect (they occur -% in the type of the other goals). -% The order of Goals is given by the traversal order of EConstr.fold -% (a -% fold_left over the terms, letin body comes before the type). -% -external pred coq.ltac.collect-goals i:term, o:list sealed-goal, - o:list sealed-goal. - -% [coq.ltac.call-ltac1 Tac G GL] Calls Ltac1 tactic Tac on goal G (passing -% the arguments of G, see coq.ltac.call for a handy wrapper). -% Tac can either be a string (the tactic name), or a value -% of type ltac1-tactic, see the tac argument constructor -% and the ltac_tactic:(...) syntax to pass arguments to -% an elpi tactic. -% Supported attributes: -% - @no-tc! (default false, do not infer typeclasses) -external pred coq.ltac.call-ltac1 i:any, i:goal, o:list sealed-goal. - -% [coq.ltac.id-free? ID G] -% Fails if ID is already used in G. Note that ids which are taken are -% renamed -% on the fly (since in the HOAS of terms, names are just pretty printing -% hints), but for the ergonomy of a tactic it may help to know if an -% hypothesis name is already taken. -% -external pred coq.ltac.id-free? i:id, i:goal. - -% [coq.ltac.fresh-id Default Ty FreshID] TODO -external pred coq.ltac.fresh-id i:id, i:term, o:id. - -% -- Coq's options system -------------------------------------------- - -% Coq option value -kind coq.option type. -type coq.option.int option int -> coq.option. % none means unset -type coq.option.string option string -> coq.option. % none means unset -type coq.option.bool bool -> coq.option. - -% [coq.option.get Option Value] reads Option. Reading a non existing option -% is a fatal error. -external pred coq.option.get i:list string, o:coq.option. - -% [coq.option.set Option Value] writes Option. Writing a non existing option -% is a fatal error. -external pred coq.option.set i:list string, i:coq.option. - -% [coq.option.available? Option Deprecated] checks if Option exists and -% tells if is deprecated (tt) or not (ff) -external pred coq.option.available? i:list string, o:bool. - -% [coq.option.add Option Value Deprecated] -% adds a new option to Coq setting its current value (and type). -% Deprecated can be left unspecified and defaults to ff. -% This call cannot be undone in a Coq interactive session, use it once -% and for all in a .v file which your clients will load. Eg. -% -% Elpi Query lp:{{ coq.option.add ... }}. -% -% -external pred coq.option.add i:list string, i:coq.option, i:bool. - -% -- Datatypes conversions -------------------------------------------- - -% Name.Name.t: Name hints (in binders), can be input writing a name -% between backticks, e.g. `x` or `_` for anonymous. Important: these are -% just printing hints with no meaning, hence in elpi two name are always -% related: `x` = `y` -typeabbrev name (ctype "name"). - - -% [coq.name-suffix Name Suffix NameSuffix] suffixes a Name with a string or -% an int or another name -external pred coq.name-suffix i:name, i:any, o:name. - -% [coq.string->name Hint Name] creates a name hint -external pred coq.string->name i:string, o:name. - - -pred coq.id->name i:id, o:name. -coq.id->name S N :- coq.string->name S N. - - -% [coq.name->id Name Id] tuns a pretty printing hint into a string. This API -% is for internal use, no guarantee on its behavior. -external pred coq.name->id i:name, o:id. - -% [coq.gref->id GR Id] extracts the label (last component of a full kernel -% name) -external pred coq.gref->id i:gref, o:id. - -% [coq.gref->string GR FullPath] extract the full kernel name -external pred coq.gref->string i:gref, o:string. - -% [coq.gref->path GR FullPath] extract the full path (kernel name without -% final id), each component is a separate list item -external pred coq.gref->path i:gref, o:list string. - -% [coq.modpath->path MP FullPath] extract the full kernel name, each -% component is a separate list item -external pred coq.modpath->path i:modpath, o:list string. - -% [coq.modtypath->path MTP FullPath] extract the full kernel name, each -% component is a separate list item -external pred coq.modtypath->path i:modtypath, o:list string. - -% [coq.modpath->library MP LibraryPath] extract the enclosing module which -% can be Required -external pred coq.modpath->library i:modpath, o:modpath. - -% [coq.modtypath->library MTP LibraryPath] extract the enclosing module -% which can be Required -external pred coq.modtypath->library i:modtypath, o:modpath. - -% [coq.term->string T S] prints a term T to a string S using Coq's pretty -% printer -% Supported attributes: -% - @ppwidth! N (default 80, max line length) -% - @ppall! (default: false, prints all details) -% - @ppmost! (default: false, prints most details) -% - @pplevel! (default: _, prints parentheses to reach that level, 200 = -% off) -% - @holes! (default: false, prints evars as _) -external pred coq.term->string i:term, o:string. - -% [coq.term->pp T B] prints a term T to a pp.t B using Coq's pretty -% printer" -% Supported attributes: -% - @ppall! (default: false, prints all details) -% - @ppmost! (default: false, prints most details) -% - @pplevel! (default: _, prints parentheses to reach that level, 200 = -% off) -% - @holes! (default: false, prints evars as _) -external pred coq.term->pp i:term, o:coq.pp. - -% [coq.goal->pp G B] prints a goal G to a pp.t B using Coq's pretty -% printer" -% Supported attributes: -% - @ppall! (default: false, prints all details) -% - @ppmost! (default: false, prints most details) -% - @pplevel! (default: _, prints parentheses to reach that level, 200 = -% off) -% - @holes! (default: false, prints evars as _) -external pred coq.goal->pp i:goal, o:coq.pp. - -% -- Extra Dependencies ----------------------------------------------- - -% [coq.extra-dep Identifier FileName] Resolve the file name of an extra -% dependency. See also Coq's From xxx Extra Dependency yyy as zzz. -external pred coq.extra-dep i:id, o:option id. - -% -- Access to Elpi's data -------------------------------------------- - -% clauses -% -% A clause like -% :name "foo" :before "bar" foo X Y :- bar X Z, baz Z Y -% is represented as -% clause "foo" (before "bar") (pi x y z\ foo x y :- bar x z, baz z y) -% that is exactly what one would load in the context using =>. -% -% The name and the grafting specification can be left unspecified. -kind clause type. -type clause id -> grafting -> prop -> clause. - -% Specify if the clause has to be grafted before, grafted after or replace -% a named clause -kind grafting type. -type before id -> grafting. -type after id -> grafting. -type replace id -> grafting. - -% Specify to which module the clause should be attached to -kind scope type. -type execution-site scope. % The module inside which the Elpi program is run -type current scope. % The module being defined (see begin/end-module) -type library scope. % The outermost module (carrying the file name) - - -% see coq.elpi.accumulate-clauses -pred coq.elpi.accumulate i:scope, i:id, i:clause. -coq.elpi.accumulate S N C :- coq.elpi.accumulate-clauses S N [C]. - - -% [coq.elpi.accumulate-clauses Scope DbName Clauses] -% Declare that, once the program is over, the given clauses has to be -% added to the given db (see Elpi Db). -% Clauses usually belong to Coq modules: the Scope argument lets one -% select which module: -% - execution site (default) is the module in which the pogram is -% invoked -% - current is the module currently being constructed (see -% begin/end-module) -% - library is the current file (the module that is named after the file) -% The clauses are visible as soon as the enclosing module is Imported. -% A clause that mentions a section variable is automatically discarded -% at the end of the section. -% Clauses cannot be accumulated inside functors. -% Supported attributes: -% - @local! (default: false, discard at the end of section or module) -% - @global! (default: false, always active, only if Scope is -% execution-site, discouraged) -external pred coq.elpi.accumulate-clauses i:scope, i:id, i:list clause. - -% Specify if a predicate argument is in input or output mode -kind argument_mode type. -type in argument_mode. -type out argument_mode. - -% [coq.elpi.add-predicate Db Indexing PredName Spec] Declares a new -% predicate PredName in the data base Db. -% Indexing can be left unspecified. Spec gathers a mode and a -% type for each argument. CAVEAT: types and indexing are strings -% instead of proper data types; beware parsing errors are fatal. -% Supported attributes: -% - @local! (default: false, discard at the end of section or module) -% - @global! (default: false, always active -external pred coq.elpi.add-predicate i:string, i:string, i:string, - i:list (pair argument_mode string). - -% [coq.elpi.predicate PredName Args Pred] Pred is the application of -% PredName to Args -external pred coq.elpi.predicate i:string, i:list any, o:prop. - -% -- Synterp ---------------------------------------------------------- - -% Action executed during the parsing phase (aka synterp) -kind synterp-action type. -type begin-module id -> synterp-action. -type begin-module-type id -> synterp-action. -type begin-section id -> synterp-action. -type end-module modpath -> synterp-action. -type end-module-type modtypath -> synterp-action. -type end-section synterp-action. -type apply-module-functor id -> synterp-action. -type apply-module-type-functor id -> synterp-action. -type include-module modpath -> synterp-action. -type include-module-type modtypath -> synterp-action. -type import-module modpath -> synterp-action. -type export-module modpath -> synterp-action. - -% Synterp action group -typeabbrev group (ctype "group"). - - -% [coq.next-synterp-action A] Get the next action performed during parsing -% (aka synterp), that is also the next action to be performed during -% execution (aka interp). See also coq.replay-synterp-action -external pred coq.next-synterp-action o:synterp-action. - -% [coq.replay-synterp-action-group ID] Execute all actions of synterp action -% group ID. ID must be the name of the next group, it must not be opened -% already, and there must not be any actions before it. -external pred coq.replay-synterp-action-group i:id. - -% [coq.begin-synterp-group ID Group] Match a begin-synterp-group synterp -% operation. ID must be the name of the next synterp action group and there -% must not be any actions before it. -external pred coq.begin-synterp-group i:id, o:group. - -% [coq.end-synterp-group Group] Match a end-synterp-group synterp operation. -% Group must be the currently opened synterp action group and the group must -% not have any more synterp actions or groups left to replay. -external pred coq.end-synterp-group i:group. - -% -- Utils ------------------------------------------------------------ - -kind coq.gref.set type. - -% [coq.gref.set.empty A] The empty set -external pred coq.gref.set.empty o:coq.gref.set. - -% [coq.gref.set.mem Elem A] Checks if Elem is in a -external pred coq.gref.set.mem i:gref, i:coq.gref.set. - -% [coq.gref.set.add Elem A B] B is A union {Elem} -external pred coq.gref.set.add i:gref, i:coq.gref.set, o:coq.gref.set. - -% [coq.gref.set.remove Elem A B] B is A \ {Elem} -external pred coq.gref.set.remove i:gref, i:coq.gref.set, o:coq.gref.set. - -% [coq.gref.set.union A B X] X is A union B -external pred coq.gref.set.union i:coq.gref.set, i:coq.gref.set, - o:coq.gref.set. - -% [coq.gref.set.inter A B X] X is A intersection B -external pred coq.gref.set.inter i:coq.gref.set, i:coq.gref.set, - o:coq.gref.set. - -% [coq.gref.set.diff A B X] X is A \ B -external pred coq.gref.set.diff i:coq.gref.set, i:coq.gref.set, - o:coq.gref.set. - -% [coq.gref.set.equal A B] tests A and B for equality -external pred coq.gref.set.equal i:coq.gref.set, i:coq.gref.set. - -% [coq.gref.set.subset A B] tests if A is a subset of B -external pred coq.gref.set.subset i:coq.gref.set, i:coq.gref.set. - -% [coq.gref.set.elements M L] L is M transformed into list -external pred coq.gref.set.elements i:coq.gref.set, o:list gref. - -% [coq.gref.set.cardinal M N] N is the number of elements of M -external pred coq.gref.set.cardinal i:coq.gref.set, o:int. - -% [coq.gref.set.filter M F M1] Filter M w.r.t. the predicate F -external pred coq.gref.set.filter i:coq.gref.set, i:gref -> prop, - o:coq.gref.set. - -% [coq.gref.set.map M F M1] Map M w.r.t. the predicate F -external pred coq.gref.set.map i:coq.gref.set, i:gref -> gref -> prop, - o:coq.gref.set. - -% CAVEAT: the type parameter of coq.gref.map must be a closed term - -kind coq.gref.map type -> type. - -% [coq.gref.map.empty M] The empty map -external pred coq.gref.map.empty o:coq.gref.map A. - -% [coq.gref.map.mem S M] Checks if S is bound in M -external pred coq.gref.map.mem i:gref, i:coq.gref.map A. - -% [coq.gref.map.add S V M M1] M1 is M where V is bound to S -external pred coq.gref.map.add i:gref, i:A, i:coq.gref.map A, - o:coq.gref.map A. - -% [coq.gref.map.remove S M M1] M1 is M where S is unbound -external pred coq.gref.map.remove i:gref, i:coq.gref.map A, - o:coq.gref.map A. - -% [coq.gref.map.find S M V] V is the binding of S in M -external pred coq.gref.map.find i:gref, i:coq.gref.map A, o:A. - -% [coq.gref.map.bindings M L] L is M transformed into an associative list -external pred coq.gref.map.bindings i:coq.gref.map A, - o:list (pair gref A). - -% [coq.gref.map.filter M F M1] Filter M w.r.t. the predicate F -external pred coq.gref.map.filter i:coq.gref.map A, i:gref -> A -> prop, - o:coq.gref.map A. - -% [coq.gref.map.map M F M1] Map M w.r.t. the predicate F -external pred coq.gref.map.map i:coq.gref.map A, - i:gref -> A -> B -> prop, o:coq.gref.map B. - -kind coq.univ.set type. - -% [coq.univ.set.empty A] The empty set -external pred coq.univ.set.empty o:coq.univ.set. - -% [coq.univ.set.mem Elem A] Checks if Elem is in a -external pred coq.univ.set.mem i:univ, i:coq.univ.set. - -% [coq.univ.set.add Elem A B] B is A union {Elem} -external pred coq.univ.set.add i:univ, i:coq.univ.set, o:coq.univ.set. - -% [coq.univ.set.remove Elem A B] B is A \ {Elem} -external pred coq.univ.set.remove i:univ, i:coq.univ.set, o:coq.univ.set. - -% [coq.univ.set.union A B X] X is A union B -external pred coq.univ.set.union i:coq.univ.set, i:coq.univ.set, - o:coq.univ.set. - -% [coq.univ.set.inter A B X] X is A intersection B -external pred coq.univ.set.inter i:coq.univ.set, i:coq.univ.set, - o:coq.univ.set. - -% [coq.univ.set.diff A B X] X is A \ B -external pred coq.univ.set.diff i:coq.univ.set, i:coq.univ.set, - o:coq.univ.set. - -% [coq.univ.set.equal A B] tests A and B for equality -external pred coq.univ.set.equal i:coq.univ.set, i:coq.univ.set. - -% [coq.univ.set.subset A B] tests if A is a subset of B -external pred coq.univ.set.subset i:coq.univ.set, i:coq.univ.set. - -% [coq.univ.set.elements M L] L is M transformed into list -external pred coq.univ.set.elements i:coq.univ.set, o:list univ. - -% [coq.univ.set.cardinal M N] N is the number of elements of M -external pred coq.univ.set.cardinal i:coq.univ.set, o:int. - -% [coq.univ.set.filter M F M1] Filter M w.r.t. the predicate F -external pred coq.univ.set.filter i:coq.univ.set, i:univ -> prop, - o:coq.univ.set. - -% [coq.univ.set.map M F M1] Map M w.r.t. the predicate F -external pred coq.univ.set.map i:coq.univ.set, i:univ -> univ -> prop, - o:coq.univ.set. - -% CAVEAT: the type parameter of coq.univ.map must be a closed term - -kind coq.univ.map type -> type. - -% [coq.univ.map.empty M] The empty map -external pred coq.univ.map.empty o:coq.univ.map A. - -% [coq.univ.map.mem S M] Checks if S is bound in M -external pred coq.univ.map.mem i:univ, i:coq.univ.map A. - -% [coq.univ.map.add S V M M1] M1 is M where V is bound to S -external pred coq.univ.map.add i:univ, i:A, i:coq.univ.map A, - o:coq.univ.map A. - -% [coq.univ.map.remove S M M1] M1 is M where S is unbound -external pred coq.univ.map.remove i:univ, i:coq.univ.map A, - o:coq.univ.map A. - -% [coq.univ.map.find S M V] V is the binding of S in M -external pred coq.univ.map.find i:univ, i:coq.univ.map A, o:A. - -% [coq.univ.map.bindings M L] L is M transformed into an associative list -external pred coq.univ.map.bindings i:coq.univ.map A, - o:list (pair univ A). - -% [coq.univ.map.filter M F M1] Filter M w.r.t. the predicate F -external pred coq.univ.map.filter i:coq.univ.map A, i:univ -> A -> prop, - o:coq.univ.map A. - -% [coq.univ.map.map M F M1] Map M w.r.t. the predicate F -external pred coq.univ.map.map i:coq.univ.map A, - i:univ -> A -> B -> prop, o:coq.univ.map B. - -kind coq.univ.variable.set type. - -% [coq.univ.variable.set.empty A] The empty set -external pred coq.univ.variable.set.empty o:coq.univ.variable.set. - -% [coq.univ.variable.set.mem Elem A] Checks if Elem is in a -external pred coq.univ.variable.set.mem i:univ.variable, - i:coq.univ.variable.set. - -% [coq.univ.variable.set.add Elem A B] B is A union {Elem} -external pred coq.univ.variable.set.add i:univ.variable, - i:coq.univ.variable.set, - o:coq.univ.variable.set. - -% [coq.univ.variable.set.remove Elem A B] B is A \ {Elem} -external pred coq.univ.variable.set.remove i:univ.variable, - i:coq.univ.variable.set, - o:coq.univ.variable.set. - -% [coq.univ.variable.set.union A B X] X is A union B -external pred coq.univ.variable.set.union i:coq.univ.variable.set, - i:coq.univ.variable.set, - o:coq.univ.variable.set. - -% [coq.univ.variable.set.inter A B X] X is A intersection B -external pred coq.univ.variable.set.inter i:coq.univ.variable.set, - i:coq.univ.variable.set, - o:coq.univ.variable.set. - -% [coq.univ.variable.set.diff A B X] X is A \ B -external pred coq.univ.variable.set.diff i:coq.univ.variable.set, - i:coq.univ.variable.set, - o:coq.univ.variable.set. - -% [coq.univ.variable.set.equal A B] tests A and B for equality -external pred coq.univ.variable.set.equal i:coq.univ.variable.set, - i:coq.univ.variable.set. - -% [coq.univ.variable.set.subset A B] tests if A is a subset of B -external pred coq.univ.variable.set.subset i:coq.univ.variable.set, - i:coq.univ.variable.set. - -% [coq.univ.variable.set.elements M L] L is M transformed into list -external pred coq.univ.variable.set.elements i:coq.univ.variable.set, - o:list univ.variable. - -% [coq.univ.variable.set.cardinal M N] N is the number of elements of M -external pred coq.univ.variable.set.cardinal i:coq.univ.variable.set, - o:int. - -% [coq.univ.variable.set.filter M F M1] Filter M w.r.t. the predicate F -external pred coq.univ.variable.set.filter i:coq.univ.variable.set, - i:univ.variable -> prop, - o:coq.univ.variable.set. - -% [coq.univ.variable.set.map M F M1] Map M w.r.t. the predicate F -external pred coq.univ.variable.set.map i:coq.univ.variable.set, - i:univ.variable -> univ.variable -> prop, - o:coq.univ.variable.set. - -% CAVEAT: the type parameter of coq.univ.variable.map must be a closed -% term - -kind coq.univ.variable.map type -> type. - -% [coq.univ.variable.map.empty M] The empty map -external pred coq.univ.variable.map.empty o:coq.univ.variable.map A. - -% [coq.univ.variable.map.mem S M] Checks if S is bound in M -external pred coq.univ.variable.map.mem i:univ.variable, - i:coq.univ.variable.map A. - -% [coq.univ.variable.map.add S V M M1] M1 is M where V is bound to S -external pred coq.univ.variable.map.add i:univ.variable, i:A, - i:coq.univ.variable.map A, - o:coq.univ.variable.map A. - -% [coq.univ.variable.map.remove S M M1] M1 is M where S is unbound -external pred coq.univ.variable.map.remove i:univ.variable, - i:coq.univ.variable.map A, - o:coq.univ.variable.map A. - -% [coq.univ.variable.map.find S M V] V is the binding of S in M -external pred coq.univ.variable.map.find i:univ.variable, - i:coq.univ.variable.map A, o:A. - -% [coq.univ.variable.map.bindings M L] L is M transformed into an -% associative list -external pred coq.univ.variable.map.bindings i:coq.univ.variable.map A, - o:list (pair univ.variable A). - -% [coq.univ.variable.map.filter M F M1] Filter M w.r.t. the predicate F -external pred coq.univ.variable.map.filter i:coq.univ.variable.map A, - i:univ.variable -> A -> prop, - o:coq.univ.variable.map A. - -% [coq.univ.variable.map.map M F M1] Map M w.r.t. the predicate F -external pred coq.univ.variable.map.map i:coq.univ.variable.map A, - i:univ.variable -> A -> B -> prop, - o:coq.univ.variable.map B. - -% Coq box types for pretty printing: -% - Vertical block: each break leads to a new line -% - Horizontal block: no line breaking -% - Horizontal-vertical block: same as Vertical block, except if this block -% is small enough to fit on a single line in which case it is the same -% as a Horizontal block -% - Horizontal or Vertical block: breaks lead to new line only when -% necessary to print the content of the block (the contents flow -% inside the box) -kind coq.pp.box type. -type coq.pp.v int -> coq.pp.box. -type coq.pp.h coq.pp.box. -type coq.pp.hv int -> coq.pp.box. -type coq.pp.hov int -> coq.pp.box. - -% Coq box model for pretty printing. Items: -% - empty -% - spc: a spacem, also a breaking hint -% - str: a non breakable string -% - brk L I: a breaking hint of a given length L contributing I spaces to -% indentation when taken -% - glue: puts things together -% - box B: a box with automatic line breaking according to B -% - comment: embedded \\n are turned into nl (see below) -% - tag: ignored -% - nl: break the line (should not be used) -kind coq.pp type. -type coq.pp.empty coq.pp. -type coq.pp.spc coq.pp. -type coq.pp.str string -> coq.pp. -type coq.pp.brk int -> int -> coq.pp. -type coq.pp.glue list coq.pp -> coq.pp. -type coq.pp.box coq.pp.box -> list coq.pp -> coq.pp. -type coq.pp.comment list string -> coq.pp. -type coq.pp.tag string -> coq.pp -> coq.pp. -type coq.pp.nl coq.pp. - -% [coq.pp->string B S] Prints a pp.t box expression B to a string S -% Supported attributes: -% - @ppwidth! N (default 80, max line length) -external pred coq.pp->string i:coq.pp, o:string. - - - - diff --git a/coq-builtin.elpi b/coq-builtin.elpi new file mode 120000 index 000000000..04c9c6540 --- /dev/null +++ b/coq-builtin.elpi @@ -0,0 +1 @@ +builtin-doc/coq-builtin.elpi \ No newline at end of file diff --git a/coq-elpi.opam b/coq-elpi.opam index 118585cd0..5a1b266cf 100644 --- a/coq-elpi.opam +++ b/coq-elpi.opam @@ -1,42 +1,41 @@ +# This file is generated by dune, edit dune-project instead opam-version: "2.0" -name: "coq-elpi" -version: "dev" -maintainer: "Enrico Tassi " -authors: [ "Enrico Tassi" ] +synopsis: "Elpi extension language for Coq" +description: + "Coq-elpi provides a Coq plugin that embeds ELPI. It also provides a way to embed Coq's terms into λProlog using the Higher-Order Abstract Syntax approach and a way to read terms back. In addition to that it exports to ELPI a set of Coq's primitives, e.g. printing a message, accessing the environment of theorems and data types, defining a new constant and so on. For convenience it also provides a quotation and anti-quotation for Coq's syntax in λProlog. E.g., `{{nat}}` is expanded to the type name of natural numbers, or `{{A -> B}}` to the representation of a product by unfolding the `->` notation. Finally it provides a way to define new vernacular commands and new tactics." +maintainer: ["Enrico Tassi "] +authors: ["Enrico Tassi "] license: "LGPL-2.1-or-later" +tags: [ + "category:Miscellaneous/Coq Extensions" + "keyword:λProlog" + "keyword:higher order abstract syntax" + "logpath:elpi" +] homepage: "https://github.com/LPCIC/coq-elpi" bug-reports: "https://github.com/LPCIC/coq-elpi/issues" -dev-repo: "git+https://github.com/LPCIC/coq-elpi" - -build: [ [ make "build" "COQBIN=%{bin}%/" "ELPIDIR=%{prefix}%/lib/elpi" "OCAMLWARN=" ] - [ make "test" "COQBIN=%{bin}%/" "ELPIDIR=%{prefix}%/lib/elpi" ] {with-test} - ] -install: [ make "install" "COQBIN=%{bin}%/" "ELPIDIR=%{prefix}%/lib/elpi" ] depends: [ - "ocaml" {>= "4.09.0" } + "dune" {>= "3.13"} + "ocaml" {>= "4.09.0"} "stdlib-shims" "elpi" {>= "1.18.2" & < "1.19.0~"} - "coq" {>= "8.19" & < "8.20~" } - "dot-merlin-reader" {with-dev} - "ocaml-lsp-server" {with-dev} + "coq" {>= "8.19" & < "8.20~"} + "dot-merlin-reader" {dev} + "ocaml-lsp-server" {dev} + "odoc" {with-doc} ] -tags: [ - "category:Miscellaneous/Coq Extensions" - "keyword:λProlog" - "keyword:higher order abstract syntax" - "logpath:elpi" +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] ] -synopsis: "Elpi extension language for Coq" -description: """ -Coq-elpi provides a Coq plugin that embeds ELPI. -It also provides a way to embed Coq's terms into λProlog using -the Higher-Order Abstract Syntax approach -and a way to read terms back. In addition to that it exports to ELPI a -set of Coq's primitives, e.g. printing a message, accessing the -environment of theorems and data types, defining a new constant and so on. -For convenience it also provides a quotation and anti-quotation for Coq's -syntax in λProlog. E.g. `{{nat}}` is expanded to the type name of natural -numbers, or `{{A -> B}}` to the representation of a product by unfolding - the `->` notation. Finally it provides a way to define new vernacular commands -and -new tactics.""" +dev-repo: "git+https://github.com/LPCIC/coq-elpi.git" diff --git a/dune b/dune new file mode 100644 index 000000000..0a3aa59ef --- /dev/null +++ b/dune @@ -0,0 +1,7 @@ +(env + (dev + (flags (:standard -w -9 -w -32 -w -27 -w -6 -w -37 -warn-error -A)) + (coq (flags -w +elpi.deprecated))) + (fatalwarnings + (flags (:standard -w -9 -w -32 -w -27 -w -6 -w -37 -warn-error +A)) + (coq (flags -w +elpi.deprecated)))) diff --git a/dune-project b/dune-project index e69de29bb..51e6ba12b 100644 --- a/dune-project +++ b/dune-project @@ -0,0 +1,37 @@ +(lang dune 3.13) +(using coq 0.8) +(name coq-elpi) +(generate_opam_files) + +(source (github LPCIC/coq-elpi)) +(license LGPL-2.1-or-later) +(authors "Enrico Tassi ") +(maintainers "Enrico Tassi ") + +(package + (name coq-elpi) + (synopsis "Elpi extension language for Coq") + (description + "Coq-elpi provides a Coq plugin that embeds ELPI. It also provides \ + a way to embed Coq's terms into λProlog using the Higher-Order \ + Abstract Syntax approach and a way to read terms back. In addition \ + to that it exports to ELPI a set of Coq's primitives, e.g. printing \ + a message, accessing the environment of theorems and data types, \ + defining a new constant and so on. For convenience it also provides \ + a quotation and anti-quotation for Coq's syntax in λProlog. E.g., \ + `{{nat}}` is expanded to the type name of natural numbers, or \ + `{{A -> B}}` to the representation of a product by unfolding the \ + `->` notation. Finally it provides a way to define new vernacular \ + commands and new tactics.") + (tags + ("category:Miscellaneous/Coq Extensions" + "keyword:λProlog" + "keyword:higher order abstract syntax" + "logpath:elpi")) + (depends + (ocaml (>= 4.09.0)) + stdlib-shims + (elpi (and (>= 1.18.2) (< 1.19.0~))) + (coq (and (>= 8.19) (< 8.20~))) + (dot-merlin-reader :dev) + (ocaml-lsp-server :dev))) diff --git a/elpi-builtin.elpi b/elpi-builtin.elpi deleted file mode 100644 index 32349ec6b..000000000 --- a/elpi-builtin.elpi +++ /dev/null @@ -1,1324 +0,0 @@ -% Generated file, do not edit - -% == Core builtins ===================================== - -% -- Logic -- - -pred true. - -true. - -pred fail. - -pred false. - -external pred (=) o:A, o:A. % unification - -typeabbrev int (ctype "int"). - - -typeabbrev string (ctype "string"). - - -typeabbrev float (ctype "float"). - - -pred (;) o:prop, o:prop. - -(A ; _) :- A. - -(_ ; B) :- B. - -type (:-) prop -> prop -> prop. - -type (:-) prop -> list prop -> prop. - -type (,) variadic prop prop. - -type uvar A. - -type (as) A -> A -> A. - -type (=>) prop -> prop -> prop. - -type (=>) list prop -> prop -> prop. - -% -- Control -- - -external pred !. % The cut operator - -pred not i:prop. - -not X :- X, !, fail. - -not _. - -% [declare_constraint C Key1 Key2...] declares C blocked -% on Key1 Key2 ... (variables, or lists thereof). -external type declare_constraint any -> any -> variadic any prop. - -external pred print_constraints. % prints all constraints - -% [halt ...] halts the program and print the terms -external type halt variadic any prop. - -pred stop. - -stop :- halt. - -% -- Evaluation -- - -pred (is) o:A, i:A. - -X is Y :- calc Y X. - -% [calc Expr Out] unifies Out with the value of Expr. It can be used in -% tandem with spilling, eg [f {calc (N + 1)}] -external pred calc i:A, o:A. - -% --- Operators --- - -type (-) A -> A -> A. - -type (i-) int -> int -> int. - -type (r-) float -> float -> float. - -type (+) int -> int -> int. -type (+) float -> float -> float. - -type (i+) int -> int -> int. - -type (r+) float -> float -> float. - -type (*) int -> int -> int. -type (*) float -> float -> float. - -type (/) float -> float -> float. - -type (mod) int -> int -> int. - -type (div) int -> int -> int. - -type (^) string -> string -> string. - -type (~) int -> int. -type (~) float -> float. - -type (i~) int -> int. - -type (r~) float -> float. - -type abs int -> int. -type abs float -> float. - -type iabs int -> int. - -type rabs float -> float. - -type max int -> int -> int. -type max float -> float -> float. - -type min int -> int -> int. -type min float -> float -> float. - -type sqrt float -> float. - -type sin float -> float. - -type cos float -> float. - -type arctan float -> float. - -type ln float -> float. - -type int_to_real int -> float. - -type floor float -> int. - -type ceil float -> int. - -type truncate float -> int. - -type size string -> int. - -type chr int -> string. - -type rhc string -> int. - -type string_to_int string -> int. - -type int_to_string int -> string. - -type substring string -> int -> int -> string. - -type real_to_string float -> string. - -% -- Arithmetic tests -- - -% [lt_ X Y] checks if X < Y. Works for string, int and float -external pred lt_ i:A, i:A. - -% [gt_ X Y] checks if X > Y. Works for string, int and float -external pred gt_ i:A, i:A. - -% [le_ X Y] checks if X =< Y. Works for string, int and float -external pred le_ i:A, i:A. - -% [ge_ X Y] checks if X >= Y. Works for string, int and float -external pred ge_ i:A, i:A. - -type (<), (>), (=<), (>=) A -> A -> prop. - -X > Y :- gt_ X Y. - -X < Y :- lt_ X Y. - -X =< Y :- le_ X Y. - -X >= Y :- ge_ X Y. - -type (i<), (i>), (i=<), (i>=) int -> int -> prop. - -X i< Y :- lt_ X Y. - -X i> Y :- gt_ X Y. - -X i=< Y :- le_ X Y. - -X i>= Y :- ge_ X Y. - -type (r<), (r>), (r=<), (r>=) float -> float -> prop. - -X r< Y :- lt_ X Y. - -X r> Y :- gt_ X Y. - -X r=< Y :- le_ X Y. - -X r>= Y :- ge_ X Y. - -type (s<), (s>), (s=<), (s>=) string -> string -> prop. - -X s< Y :- lt_ X Y. - -X s> Y :- gt_ X Y. - -X s=< Y :- le_ X Y. - -X s>= Y :- ge_ X Y. - -% -- Standard data types (supported in the FFI) -- - -kind list type -> type. - -type (::) X -> list X -> list X. - -type ([]) list X. - -% Boolean values: tt and ff since true and false are predicates -kind bool type. -type tt bool. -type ff bool. - -% Pair: the constructor is pr, since ',' is for conjunction -kind pair type -> type -> type. -type pr A -> B -> pair A B. - -pred fst i:pair A B, o:A. - -fst (pr A _) A. - -pred snd i:pair A B, o:B. - -snd (pr _ B) B. - -% The option type (aka Maybe) -kind option type -> type. -type none option A. -type some A -> option A. - -% Result of a comparison -kind cmp type. -type eq cmp. -type lt cmp. -type gt cmp. - -% Used in builtin variants that return Coq's error rather than failing -kind diagnostic type. -type ok diagnostic. % Success -type error string -> diagnostic. % Failure - -% == Elpi builtins ===================================== - -% [dprint ...] prints raw terms (debugging) -external type dprint variadic any prop. - -% [print ...] prints terms -external type print variadic any prop. - -% Deprecated, use trace.counter -pred counter i:string, o:int. -counter C N :- trace.counter C N. - -% [quote_syntax FileName QueryText QuotedProgram QuotedQuery] quotes the -% program from FileName and the QueryText. See elpi-quoted_syntax.elpi for -% the syntax tree -external pred quote_syntax i:string, i:string, o:list A, o:A. - -typeabbrev loc (ctype "Loc.t"). - - -% [loc.fields Loc File StartChar StopChar Line LineStartsAtChar] Decomposes -% a loc into its fields -external pred loc.fields i:loc, o:string, o:int, o:int, o:int, o:int. - -% == Regular Expressions ===================================== - -% [rex.match Rex Subject] checks if Subject matches Rex. Matching is based -% on OCaml's Str library -external pred rex.match i:string, i:string. - -% [rex.replace Rex Replacement Subject Out] Out is obtained by replacing all -% occurrences of Rex with Replacement in Subject. See also OCaml's -% Str.global_replace -external pred rex.replace i:string, i:string, i:string, o:string. - -% [rex.split Rex Subject Out] Out is obtained by splitting Subject at all -% occurrences of Rex. See also OCaml's Str.split -external pred rex.split i:string, i:string, o:list string. - -% Deprecated, use rex.match -pred rex_match i:string, i:string. -rex_match Rx S :- rex.match Rx S. - -% Deprecated, use rex.replace -pred rex_replace i:string, i:string, i:string, o:string. -rex_replace Rx R S O :- rex.replace Rx R S O. - -% Deprecated, use rex.split -pred rex_split i:string, i:string, o:list string. -rex_split Rx S L :- rex.split Rx S L. - -% == Elpi nonlogical builtins ===================================== - -% Opaque ML data types -kind ctyp type. -type ctype string -> ctyp. - -% [var V ...] checks if the term V is a variable. When used with tree -% arguments it relates an applied variable with its head and argument list. -external type var any -> variadic any prop. - -% [prune V L] V is pruned to L (V is unified with a variable that only sees -% the list of names L) -external pred prune o:any, i:list any. - -% [distinct_names L] checks if L is a list of distinct names. If L is the -% scope of a unification variable (its arguments, as per var predicate) then -% distinct_names L checks that such variable is in the Miller pattern -% fragment (L_\lambda) -external pred distinct_names i:list any. - -% [same_var V1 V2] checks if the two terms V1 and V2 are the same variable, -% ignoring the arguments of the variables -external pred same_var i:A, i:A. - -% [same_term T1 T2] checks if the two terms T1 and T2 are syntactically -% equal (no unification). It behaves differently than same_var since it -% recursively compares the arguments of the variables -external pred same_term i:A, i:A. - - -% Infix notation for same_term -pred (==) i:A, i:A. -X == Y :- same_term X Y. - - -% [cmp_term A B Cmp] Compares A and B. Only works if A and B are ground. -external pred cmp_term i:any, i:any, o:cmp. - -% [name T ...] checks if T is a eigenvariable. When used with tree arguments -% it relates an applied name with its head and argument list. -external type name any -> variadic any prop. - -% [constant T ...] checks if T is a (global) constant. When used with tree -% arguments it relates an applied constant with its head and argument list. -external type constant any -> variadic any prop. - -external pred names % generates the list of eigenvariable - o:list any. % list of eigenvariables in order of age (young first) - -external pred occurs % checks if the atom occurs in the term - i:any, % an atom, that is a global constant or a bound name (aka eigenvariable) - i:any. % a term - -% [closed_term T] unify T with a variable that has no eigenvariables in -% scope -external pred closed_term o:any. - -% [ground_term T] Checks if T contains unification variables -external pred ground_term i:any. - -% [is_cdata T Ctype] checks if T is primitive of type Ctype, eg (ctype -% "int") -external pred is_cdata i:any, o:ctyp. - -pred primitive? i:A, i:string. - -primitive? X S :- is_cdata X (ctype S). - -% [new_int N] unifies N with a different int every time it is called. Values -% of N are guaranteed to be incresing. -external pred new_int o:int. - -% [findall_solution P L] finds all the solved instances of P and puts them -% in L -% in the order in which they are found. Instances can contain -% eigenvariables -% and unification variables. - -external pred findall_solutions i:prop, o:list prop. - -% Holds data across bracktracking; can only contain closed terms -typeabbrev safe (ctype "safe"). - - -% [new_safe Safe] creates a safe: a store that persists across backtracking -external pred new_safe o:safe. - -% [stash_in_safe Safe Data] stores Data in the Safe -external pred stash_in_safe i:safe, i:A. - -% [open_safe Safe Data] retrieves the Data stored in Safe -external pred open_safe i:safe, o:list A. - - -% [if C T E] picks the first success of C then runs T (never E). -% if C has no success it runs E. -pred if i:prop, i:prop, i:prop. -if B T _ :- B, !, T. -if _ _ E :- E. - -% [if2 C1 B1 C2 B2 E] like if but with 2 then branches (and one else branch). -pred if2 i:prop, i:prop, i:prop, i:prop, i:prop. -if2 G1 P1 _ _ _ :- G1, !, P1. -if2 _ _ G2 P2 _ :- G2, !, P2. -if2 _ _ _ _ E :- !, E. - -% [random.init Seed] Initialize OCaml's PRNG with the given Seed -external pred random.init i:int. - -% [random.self_init] Initialize OCaml's PRNG with some seed -external pred random.self_init . - -% [random.int Bound N] unifies N with a random int between 0 and Bound -% (excluded) -external pred random.int i:int, o:int. - -#line 0 "builtin_stdlib.elpi" -% == stdlib ======================================================= - -% Conventions: -% - all predicates declare a mode with some input arguments, unless... -% - predicates whose name ends with R are relations (work in any direction, -% that is all arguments are in output mode) -% - predicates whose name ends with ! do contain a cut and generate only the -% first result -% - all errors given by this library end up calling fatal-error[-w-data], -% override it in order to handle them differently -% - all debug prints by this library end up calling debug-print, override it -% in order to handle them differently - -namespace std { - -pred fatal-error i:string. -:name "default-fatal-error" -fatal-error Msg :- halt Msg. - -pred fatal-error-w-data i:string, i:A. -:name "default-fatal-error-w-data" -fatal-error-w-data Msg Data :- halt Msg ":" Data. - -pred debug-print i:string, i:A. -:name "default-debug-print" -debug-print Msg Data :- print Msg Data. - -% -- Errors, Debugging, Hacks -- - -pred ignore-failure! i:prop. -ignore-failure! P :- P, !. -ignore-failure! _. - -% [assert! C M] takes the first success of C or fails with message M -pred assert! i:prop, i:string. -assert! Cond Msg :- (Cond ; fatal-error-w-data Msg Cond), !. - -% [assert-ok! C M] like assert! but the last argument of the predicate must -% be a diagnostic that is printed after M in case it is not ok -pred assert-ok! i:(diagnostic -> prop), i:string. -assert-ok! Cond Msg :- Cond Diagnostic, !, (Diagnostic = ok ; Diagnostic = error S, fatal-error-w-data Msg S), !. -assert-ok! _ Msg :- fatal-error-w-data Msg "no diagnostic returned". - -% [spy P] traces the call to P, printing all success and the final failure -pred spy i:prop. -spy P :- trace.counter "run" NR, if (not(NR = 0)) (debug-print "run=" NR) true, - debug-print "----<<---- enter: " P, - P, - debug-print "---->>---- exit: " P. -spy P :- debug-print "---->>---- fail: " P, fail. - -% [spy! P] traces the first call to P without leaving a choice point -pred spy! i:prop. -spy! P :- trace.counter "run" NR, if (not(NR = 0)) (debug-print "run=" NR) true, - debug-print "----<<---- enter: " P, - P, - debug-print "---->>---- exit: " P, !. -spy! P :- debug-print "---->>---- fail: " P, fail. - -% to silence the type checker -pred unsafe-cast o:A, o:B. -unsafe-cast X X. - -% -- List processing -- - -pred length i:list A, o:int. -length [_|L] N :- length L N1, N is N1 + 1. -length [] 0. - -pred rev i:list A, o:list A. -rev L RL :- rev.aux L [] RL. -rev.aux [X|XS] ACC R :- rev.aux XS [X|ACC] R. -rev.aux [] L L. - -pred last i:list A, o:A. -last [] _ :- fatal-error "last on empty list". -last [X] X :- !. -last [_|XS] R :- last XS R. - -pred append i:list A, i:list A, o:list A. -append [X|XS] L [X|L1] :- append XS L L1 . -append [] L L . - -pred appendR o:list A, o:list A, o:list A. -appendR [X|XS] L [X|L1] :- appendR XS L L1 . -appendR [] L L . - -pred take i:int, i:list A, o:list A. -take 0 _ [] :- !. -take N [X|XS] [X|L] :- !, N1 is N - 1, take N1 XS L. -take _ _ _ :- fatal-error "take run out of list items". - -pred take-last i:int, i:list A, o:list A. -take-last N L R :- - length L M, - D is M - N, - drop D L R. - -pred drop i:int, i:list A, o:list A. -drop 0 L L :- !. -drop N [_|XS] L :- !, N1 is N - 1, drop N1 XS L. -drop _ _ _ :- fatal-error "drop run out of list items". - -pred drop-last i:int, i:list A, o:list A. -drop-last N L R :- - length L M, I is M - N, take I L R. - -pred split-at i:int, i:list A, o:list A, o:list A. -split-at 0 L [] L :- !. -split-at N [X|XS] [X|LN] LM :- !, N1 is N - 1, split-at N1 XS LN LM. -split-at _ _ _ _ :- fatal-error "split-at run out of list items". - -pred fold i:list B, i:A, i:(B -> A -> A -> prop), o:A. -fold [] A _ A. -fold [X|XS] A F R :- F X A A1, fold XS A1 F R. - -pred fold-right i:list B, i:A, i:(B -> A -> A -> prop), o:A. -fold-right [] A _ A. -fold-right [X|XS] A F R :- fold-right XS A F A', F X A' R. - -pred fold2 i:list C, i:list B, i:A, i:(C -> B -> A -> A -> prop), o:A. -fold2 [] [_|_] _ _ _ :- fatal-error "fold2 on lists of different length". -fold2 [_|_] [] _ _ _ :- fatal-error "fold2 on lists of different length". -fold2 [] [] A _ A. -fold2 [X|XS] [Y|YS] A F R :- F X Y A A1, fold2 XS YS A1 F R. - -pred map i:list A, i:(A -> B -> prop), o:list B. -map [] _ []. -map [X|XS] F [Y|YS] :- F X Y, map XS F YS. - -pred map-i i:list A, i:(int -> A -> B -> prop), o:list B. -map-i L F R :- map-i.aux L 0 F R. -map-i.aux [] _ _ []. -map-i.aux [X|XS] N F [Y|YS] :- F N X Y, M is N + 1, map-i.aux XS M F YS. - -pred map-filter i:list A, i:(A -> B -> prop), o:list B. -map-filter [] _ []. -map-filter [X|XS] F [Y|YS] :- F X Y, !, map-filter XS F YS. -map-filter [_|XS] F YS :- map-filter XS F YS. - -:index(1 1) -pred map2 i:list A, i:list B, i:(A -> B -> C -> prop), o:list C. -map2 [] [_|_] _ _ :- fatal-error "map2 on lists of different length". -map2 [_|_] [] _ _ :- fatal-error "map2 on lists of different length". -map2 [] [] _ []. -map2 [X|XS] [Y|YS] F [Z|ZS] :- F X Y Z, map2 XS YS F ZS. - -pred map2-filter i:list A, i:list B, i:(A -> B -> C -> prop), o:list C. -map2-filter [] [_|_] _ _ :- fatal-error "map2-filter on lists of different length". -map2-filter [_|_] [] _ _ :- fatal-error "map2-filter on lists of different length". -map2-filter [] [] _ []. -map2-filter [X|XS] [Y|YS] F [Z|ZS] :- F X Y Z, !, map2-filter XS YS F ZS. -map2-filter [_|XS] [_|YS] F ZS :- map2-filter XS YS F ZS. - -pred map-ok i:list A, i:(A -> B -> diagnostic -> prop), o:list A, o:diagnostic. -map-ok [X|L] P [Y|YS] S :- P X Y S0, if (S0 = ok) (map-ok L P YS S) (S = S0). -map-ok [] _ [] ok. - -pred fold-map i:list A, i:B, i:(A -> B -> C -> B -> prop), o:list C, o:B. -fold-map [] A _ [] A. -fold-map [X|XS] A F [Y|YS] A2 :- F X A Y A1, fold-map XS A1 F YS A2. - -pred omap i:option A, i:(A -> B -> prop), o:option B. -omap none _ none. -omap (some X) F (some Y) :- F X Y. - -% [nth N L X] picks in X the N-th element of L (L must be of length > N) -pred nth i:int, i:list A, o:A. -nth 0 [X|_ ] R :- !, X = R. -nth N [_|XS] R :- N > 0, !, N1 is N - 1, nth N1 XS R. -nth N _ _ :- N < 0, !, fatal-error "nth got a negative index". -nth _ _ _ :- fatal-error "nth run out of list items". - -% [lookup L K V] sees L as a map from K to V -pred lookup i:list (pair A B), i:A, o:B. -lookup [pr X Y|_] X Y. -lookup [_|LS] X Y :- lookup LS X Y. - -% [lookup! L K V] sees L as a map from K to V, stops at the first binding -pred lookup! i:list (pair A B), i:A, o:B. -lookup! [pr X Y|_] X Y :- !. -lookup! [_|LS] X Y :- lookup! LS X Y. - -% [mem! L X] succeeds once if X occurs inside L -pred mem! i:list A, o:A. -mem! [X|_] X :- !. -mem! [_|L] X :- mem! L X. - -% [mem L X] succeeds every time if X occurs inside L -pred mem i:list A, o:A. -mem [X|_] X. -mem [_|L] X :- mem L X. - -pred exists i:list A, i:(A -> prop). -exists [X|_] P :- P X. -exists [_|L] P :- exists L P. - -pred exists2 i:list A, i:list B, i:(A -> B -> prop). -exists2 [] [_|_] _ :- fatal-error "exists2 on lists of different length". -exists2 [_|_] [] _ :- fatal-error "exists2 on lists of different length". -exists2 [X|_] [Y|_] P :- P X Y. -exists2 [_|L] [_|M] P :- exists2 L M P. - -pred forall i:list A, i:(A -> prop). -forall [] _. -forall [X|L] P :- P X, forall L P. - -pred forall-ok i:list A, i:(A -> diagnostic -> prop), o:diagnostic. -forall-ok [X|L] P S :- P X S0, if (S0 = ok) (forall-ok L P S) (S = S0). -forall-ok [] _ ok. - -pred forall2 i:list A, i:list B, i:(A -> B -> prop). -forall2 [] [_|_] _ :- fatal-error "forall2 on lists of different length". -forall2 [_|_] [] _ :- fatal-error "forall2 on lists of different length". -forall2 [X|XS] [Y|YS] P :- P X Y, forall2 XS YS P. -forall2 [] [] _. - -pred filter i:list A, i:(A -> prop), o:list A. -filter [] _ []. -filter [X|L] P R :- if (P X) (R = X :: L1) (R = L1), filter L P L1. - -pred zip i:list A, i:list B, o:list (pair A B). -zip [_|_] [] _ :- fatal-error "zip on lists of different length". -zip [] [_|_] _ :- fatal-error "zip on lists of different length". -zip [X|LX] [Y|LY] [pr X Y|LR] :- zip LX LY LR. -zip [] [] []. - -pred unzip i:list (pair A B), o:list A, o:list B. -unzip [] [] []. -unzip [pr X Y|L] [X|LX] [Y|LY] :- unzip L LX LY. - -pred flatten i:list (list A), o:list A. -flatten [X|LS] R :- flatten LS LS', append X LS' R. -flatten [] []. - -pred null i:list A. -null []. - -pred iota i:int, o:list int. -iota N L :- iota.aux 0 N L. -iota.aux X X [] :- !. -iota.aux N X [N|R] :- M is N + 1, iota.aux M X R. - -% [intersperse X L R] R is [L0, X, ..., X, LN] -:index(_ 1) -pred intersperse i:A, i:list A, o:list A. -intersperse _ [] []. -intersperse _ [X] [X] :- !. -intersperse Sep [X|XS] [X,Sep|YS] :- intersperse Sep XS YS. - -% -- Misc -- - -pred flip i:(A -> B -> prop), i:B, i:A. -flip P X Y :- P Y X. - -pred time i:prop, o:float. -time P T :- gettimeofday Before, P, gettimeofday After, T is After - Before. - -pred do! i:list prop. -do! []. -do! [P|PS] :- P, !, do! PS. - -:index(_ 1) -pred do-ok! o:diagnostic, i:list (diagnostic -> prop). -do-ok! ok []. -do-ok! S [P|PS] :- P S0, !, if (S0 = ok) (do-ok! S PS) (S = S0). - -pred lift-ok i:prop, i:string, o:diagnostic. -lift-ok P Msg R :- (P, R = ok; R = error Msg). - -pred spy-do! i:list prop. -spy-do! L :- map L (x\y\y = spy x) L1, do! L1. - -pred while-ok-do! i:diagnostic, i:list (diagnostic -> prop), o:diagnostic. -while-ok-do! (error _ as E) _ E. -while-ok-do! ok [] ok. -while-ok-do! ok [P|PS] R :- P C, !, while-ok-do! C PS R. - -pred any->string i:A, o:string. -any->string X Y :- term_to_string X Y. - -pred max i:A, i:A, o:A. -max N M N :- N >= M, !. -max _ M M. - -% [findall P L] L is the list [P1,P2,P3..] where each Pi is a solution to P. -pred findall i:prop, o:list prop. -findall P L :- findall_solutions P L. - -} - -% [std.string.concat Separator Items Result] concatenates Items -% interspersing Separator -external pred std.string.concat i:string, i:list string, o:string. - -% CAVEAT: the type parameter of std.string.map must be a closed term - -kind std.string.map type -> type. - -% [std.string.map.empty M] The empty map -external pred std.string.map.empty o:std.string.map A. - -% [std.string.map.mem S M] Checks if S is bound in M -external pred std.string.map.mem i:string, i:std.string.map A. - -% [std.string.map.add S V M M1] M1 is M where V is bound to S -external pred std.string.map.add i:string, i:A, i:std.string.map A, - o:std.string.map A. - -% [std.string.map.remove S M M1] M1 is M where S is unbound -external pred std.string.map.remove i:string, i:std.string.map A, - o:std.string.map A. - -% [std.string.map.find S M V] V is the binding of S in M -external pred std.string.map.find i:string, i:std.string.map A, o:A. - -% [std.string.map.bindings M L] L is M transformed into an associative list -external pred std.string.map.bindings i:std.string.map A, - o:list (pair string A). - -% [std.string.map.filter M F M1] Filter M w.r.t. the predicate F -external pred std.string.map.filter i:std.string.map A, - i:string -> A -> prop, - o:std.string.map A. - -% [std.string.map.map M F M1] Map M w.r.t. the predicate F -external pred std.string.map.map i:std.string.map A, - i:string -> A -> B -> prop, - o:std.string.map B. - -% CAVEAT: the type parameter of std.int.map must be a closed term - -kind std.int.map type -> type. - -% [std.int.map.empty M] The empty map -external pred std.int.map.empty o:std.int.map A. - -% [std.int.map.mem S M] Checks if S is bound in M -external pred std.int.map.mem i:int, i:std.int.map A. - -% [std.int.map.add S V M M1] M1 is M where V is bound to S -external pred std.int.map.add i:int, i:A, i:std.int.map A, - o:std.int.map A. - -% [std.int.map.remove S M M1] M1 is M where S is unbound -external pred std.int.map.remove i:int, i:std.int.map A, o:std.int.map A. - -% [std.int.map.find S M V] V is the binding of S in M -external pred std.int.map.find i:int, i:std.int.map A, o:A. - -% [std.int.map.bindings M L] L is M transformed into an associative list -external pred std.int.map.bindings i:std.int.map A, o:list (pair int A). - -% [std.int.map.filter M F M1] Filter M w.r.t. the predicate F -external pred std.int.map.filter i:std.int.map A, i:int -> A -> prop, - o:std.int.map A. - -% [std.int.map.map M F M1] Map M w.r.t. the predicate F -external pred std.int.map.map i:std.int.map A, i:int -> A -> B -> prop, - o:std.int.map B. - -% CAVEAT: the type parameter of std.loc.map must be a closed term - -kind std.loc.map type -> type. - -% [std.loc.map.empty M] The empty map -external pred std.loc.map.empty o:std.loc.map A. - -% [std.loc.map.mem S M] Checks if S is bound in M -external pred std.loc.map.mem i:loc, i:std.loc.map A. - -% [std.loc.map.add S V M M1] M1 is M where V is bound to S -external pred std.loc.map.add i:loc, i:A, i:std.loc.map A, - o:std.loc.map A. - -% [std.loc.map.remove S M M1] M1 is M where S is unbound -external pred std.loc.map.remove i:loc, i:std.loc.map A, o:std.loc.map A. - -% [std.loc.map.find S M V] V is the binding of S in M -external pred std.loc.map.find i:loc, i:std.loc.map A, o:A. - -% [std.loc.map.bindings M L] L is M transformed into an associative list -external pred std.loc.map.bindings i:std.loc.map A, o:list (pair loc A). - -% [std.loc.map.filter M F M1] Filter M w.r.t. the predicate F -external pred std.loc.map.filter i:std.loc.map A, i:loc -> A -> prop, - o:std.loc.map A. - -% [std.loc.map.map M F M1] Map M w.r.t. the predicate F -external pred std.loc.map.map i:std.loc.map A, i:loc -> A -> B -> prop, - o:std.loc.map B. - -kind std.string.set type. - -% [std.string.set.empty A] The empty set -external pred std.string.set.empty o:std.string.set. - -% [std.string.set.mem Elem A] Checks if Elem is in a -external pred std.string.set.mem i:string, i:std.string.set. - -% [std.string.set.add Elem A B] B is A union {Elem} -external pred std.string.set.add i:string, i:std.string.set, - o:std.string.set. - -% [std.string.set.remove Elem A B] B is A \ {Elem} -external pred std.string.set.remove i:string, i:std.string.set, - o:std.string.set. - -% [std.string.set.union A B X] X is A union B -external pred std.string.set.union i:std.string.set, i:std.string.set, - o:std.string.set. - -% [std.string.set.inter A B X] X is A intersection B -external pred std.string.set.inter i:std.string.set, i:std.string.set, - o:std.string.set. - -% [std.string.set.diff A B X] X is A \ B -external pred std.string.set.diff i:std.string.set, i:std.string.set, - o:std.string.set. - -% [std.string.set.equal A B] tests A and B for equality -external pred std.string.set.equal i:std.string.set, i:std.string.set. - -% [std.string.set.subset A B] tests if A is a subset of B -external pred std.string.set.subset i:std.string.set, i:std.string.set. - -% [std.string.set.elements M L] L is M transformed into list -external pred std.string.set.elements i:std.string.set, o:list string. - -% [std.string.set.cardinal M N] N is the number of elements of M -external pred std.string.set.cardinal i:std.string.set, o:int. - -% [std.string.set.filter M F M1] Filter M w.r.t. the predicate F -external pred std.string.set.filter i:std.string.set, i:string -> prop, - o:std.string.set. - -% [std.string.set.map M F M1] Map M w.r.t. the predicate F -external pred std.string.set.map i:std.string.set, - i:string -> string -> prop, - o:std.string.set. - -kind std.int.set type. - -% [std.int.set.empty A] The empty set -external pred std.int.set.empty o:std.int.set. - -% [std.int.set.mem Elem A] Checks if Elem is in a -external pred std.int.set.mem i:int, i:std.int.set. - -% [std.int.set.add Elem A B] B is A union {Elem} -external pred std.int.set.add i:int, i:std.int.set, o:std.int.set. - -% [std.int.set.remove Elem A B] B is A \ {Elem} -external pred std.int.set.remove i:int, i:std.int.set, o:std.int.set. - -% [std.int.set.union A B X] X is A union B -external pred std.int.set.union i:std.int.set, i:std.int.set, - o:std.int.set. - -% [std.int.set.inter A B X] X is A intersection B -external pred std.int.set.inter i:std.int.set, i:std.int.set, - o:std.int.set. - -% [std.int.set.diff A B X] X is A \ B -external pred std.int.set.diff i:std.int.set, i:std.int.set, - o:std.int.set. - -% [std.int.set.equal A B] tests A and B for equality -external pred std.int.set.equal i:std.int.set, i:std.int.set. - -% [std.int.set.subset A B] tests if A is a subset of B -external pred std.int.set.subset i:std.int.set, i:std.int.set. - -% [std.int.set.elements M L] L is M transformed into list -external pred std.int.set.elements i:std.int.set, o:list int. - -% [std.int.set.cardinal M N] N is the number of elements of M -external pred std.int.set.cardinal i:std.int.set, o:int. - -% [std.int.set.filter M F M1] Filter M w.r.t. the predicate F -external pred std.int.set.filter i:std.int.set, i:int -> prop, - o:std.int.set. - -% [std.int.set.map M F M1] Map M w.r.t. the predicate F -external pred std.int.set.map i:std.int.set, i:int -> int -> prop, - o:std.int.set. - -kind std.loc.set type. - -% [std.loc.set.empty A] The empty set -external pred std.loc.set.empty o:std.loc.set. - -% [std.loc.set.mem Elem A] Checks if Elem is in a -external pred std.loc.set.mem i:loc, i:std.loc.set. - -% [std.loc.set.add Elem A B] B is A union {Elem} -external pred std.loc.set.add i:loc, i:std.loc.set, o:std.loc.set. - -% [std.loc.set.remove Elem A B] B is A \ {Elem} -external pred std.loc.set.remove i:loc, i:std.loc.set, o:std.loc.set. - -% [std.loc.set.union A B X] X is A union B -external pred std.loc.set.union i:std.loc.set, i:std.loc.set, - o:std.loc.set. - -% [std.loc.set.inter A B X] X is A intersection B -external pred std.loc.set.inter i:std.loc.set, i:std.loc.set, - o:std.loc.set. - -% [std.loc.set.diff A B X] X is A \ B -external pred std.loc.set.diff i:std.loc.set, i:std.loc.set, - o:std.loc.set. - -% [std.loc.set.equal A B] tests A and B for equality -external pred std.loc.set.equal i:std.loc.set, i:std.loc.set. - -% [std.loc.set.subset A B] tests if A is a subset of B -external pred std.loc.set.subset i:std.loc.set, i:std.loc.set. - -% [std.loc.set.elements M L] L is M transformed into list -external pred std.loc.set.elements i:std.loc.set, o:list loc. - -% [std.loc.set.cardinal M N] N is the number of elements of M -external pred std.loc.set.cardinal i:std.loc.set, o:int. - -% [std.loc.set.filter M F M1] Filter M w.r.t. the predicate F -external pred std.loc.set.filter i:std.loc.set, i:loc -> prop, - o:std.loc.set. - -% [std.loc.set.map M F M1] Map M w.r.t. the predicate F -external pred std.loc.set.map i:std.loc.set, i:loc -> loc -> prop, - o:std.loc.set. - -#line 0 "builtin_map.elpi" -kind std.map type -> type -> type. -type std.map std.map.private.map K V -> (K -> K -> cmp -> prop) -> std.map K V. - -namespace std.map { - -% [make Eq Ltn M] builds an empty map M where keys are compared using Eq and Ltn -pred make i:(K -> K -> cmp -> prop), o:std.map K V. -make Cmp (std.map private.empty Cmp). - -% [find K M V] looks in M for the value V associated to K -pred find i:K, i:std.map K V, o:V. -find K (std.map M Cmp) V :- private.find M Cmp K V. - -% [add K V M M1] M1 is M where K is bound to V -pred add i:K, i:V, i:std.map K V, o:std.map K V. -add K V (std.map M Cmp) (std.map M1 Cmp) :- private.add M Cmp K V M1. - -% [remove K M M1] M1 is M where K is unbound -pred remove i:K, i:std.map K V, o:std.map K V. -remove K (std.map M Cmp) (std.map M1 Cmp) :- private.remove M Cmp K M1. - -% [bindings M L] L is the key-value pairs in increasing order -pred bindings i:std.map K V, o:list (pair K V). -bindings (std.map M _) L :- private.bindings M [] L. - -namespace private { - -% Taken from OCaml's map.ml -kind map type -> type -> type. -type empty map K V. -type node map K V -> K -> V -> map K V -> int -> map K V. - -pred height i:map K V, o:int. -height empty 0. -height (node _ _ _ _ H) H. - -pred create i:map K V, i:K, i:V, i:map K V, o:map K V. -create L K V R (node L K V R H) :- H is {std.max {height L} {height R}} + 1. - -pred bal i:map K V, i:K, i:V, i:map K V, o:map K V. -bal L K V R T :- - height L HL, - height R HR, - HL2 is HL + 2, - HR2 is HR + 2, - bal.aux HL HR HL2 HR2 L K V R T. - -bal.aux HL _ _ HR2 (node LL LV LD LR _) X D R T :- - HL > HR2, {height LL} >= {height LR}, !, - create LL LV LD {create LR X D R} T. -bal.aux HL _ _ HR2 (node LL LV LD (node LRL LRV LRD LRR _) _) X D R T :- - HL > HR2, !, - create {create LL LV LD LRL} LRV LRD {create LRR X D R} T. -bal.aux _ HR HL2 _ L X D (node RL RV RD RR _) T :- - HR > HL2, {height RR} >= {height RL}, !, - create {create L X D RL} RV RD RR T. -bal.aux _ HR HL2 _ L X D (node (node RLL RLV RLD RLR _) RV RD RR _) T :- - HR > HL2, !, - create {create L X D RLL} RLV RLD {create RLR RV RD RR} T. -bal.aux _ _ _ _ L K V R T :- create L K V R T. - -pred add i:map K V, i:(K -> K -> cmp -> prop), i:K, i:V, o:map K V. -add empty _ K V T :- create empty K V empty T. -add (node _ X _ _ _ as M) Cmp X1 XD M1 :- Cmp X1 X E, add.aux E M Cmp X1 XD M1. -add.aux eq (node L _ _ R H) _ X XD T :- T = node L X XD R H. -add.aux lt (node L V D R _) Cmp X XD T :- bal {add L Cmp X XD} V D R T. -add.aux gt (node L V D R _) Cmp X XD T :- bal L V D {add R Cmp X XD} T. - -pred find i:map K V, i:(K -> K -> cmp -> prop), i:K, o:V. -find (node L K1 V1 R _) Cmp K V :- Cmp K K1 E, find.aux E Cmp L R V1 K V. -find.aux eq _ _ _ V _ V. -find.aux lt Cmp L _ _ K V :- find L Cmp K V. -find.aux gt Cmp _ R _ K V :- find R Cmp K V. - -pred remove-min-binding i:map K V, o:map K V. -remove-min-binding (node empty _ _ R _) R :- !. -remove-min-binding (node L V D R _) X :- bal {remove-min-binding L} V D R X. - -pred min-binding i:map K V, o:K, o:V. -min-binding (node empty V D _ _) V D :- !. -min-binding (node L _ _ _ _) V D :- min-binding L V D. - -pred merge i:map K V, i:map K V, o:map K V. -merge empty X X :- !. -merge X empty X :- !. -merge M1 M2 R :- - min-binding M2 X D, - bal M1 X D {remove-min-binding M2} R. - -pred remove i:map K V, i:(K -> K -> cmp -> prop), i:K, o:map K V. -remove empty _ _ empty :- !. -remove (node L V D R _) Cmp X M :- Cmp X V E, remove.aux E Cmp L R V D X M. -remove.aux eq _ L R _ _ _ M :- merge L R M. -remove.aux lt Cmp L R V D X M :- bal {remove L Cmp X} V D R M. -remove.aux gt Cmp L R V D X M :- bal L V D {remove R Cmp X} M. - -pred bindings i:map K V, i:list (pair K V), o:list (pair K V). -bindings empty X X. -bindings (node L V D R _) X X1 :- - bindings L [pr V D|{bindings R X}] X1. - - -} % std.map.private -} % std.map - - -#line 0 "builtin_set.elpi" -kind std.set type -> type. -type std.set std.set.private.set E -> (E -> E -> cmp -> prop) -> std.set E. - -namespace std.set { - -% [make Eq Ltn M] builds an empty set M where keys are compared using Eq and Ltn -pred make i:(E -> E -> cmp -> prop), o:std.set E. -make Cmp (std.set private.empty Cmp). - -% [mem E M] looks if E is in M -pred mem i:E, i:std.set E. -mem E (std.set M Cmp):- private.mem M Cmp E. - -% [add E M M1] M1 is M + {E} -pred add i:E, i:std.set E, o:std.set E. -add E (std.set M Cmp) (std.set M1 Cmp) :- private.add M Cmp E M1. - -% [remove E M M1] M1 is M - {E} -pred remove i:E, i:std.set E, o:std.set E. -remove E (std.set M Cmp) (std.set M1 Cmp) :- private.remove M Cmp E M1. - -% [cardinal S N] N is the number of elements of S -pred cardinal i:std.set E, o:int. -cardinal (std.set M _) N :- private.cardinal M N. - -pred elements i:std.set E, o:list E. -elements (std.set M _) L :- private.elements M [] L. - -namespace private { - -% Taken from OCaml's set.ml -kind set type -> type. -type empty set E. -type node set E -> E -> set E -> int -> set E. - -pred height i:set E, o:int. -height empty 0. -height (node _ _ _ H) H. - -pred create i:set E, i:E, i:set E, o:set E. -create L E R (node L E R H) :- H is {std.max {height L} {height R}} + 1. - -pred bal i:set E, i:E, i:set E, o:set E. -bal L E R T :- - height L HL, - height R HR, - HL2 is HL + 2, - HR2 is HR + 2, - bal.aux HL HR HL2 HR2 L E R T. - -bal.aux HL _ _ HR2 (node LL LV LR _) X R T :- - HL > HR2, {height LL} >= {height LR}, !, - create LL LV {create LR X R} T. -bal.aux HL _ _ HR2 (node LL LV (node LRL LRV LRR _) _) X R T :- - HL > HR2, !, - create {create LL LV LRL} LRV {create LRR X R} T. -bal.aux _ HR HL2 _ L X (node RL RV RR _) T :- - HR > HL2, {height RR} >= {height RL}, !, - create {create L X RL} RV RR T. -bal.aux _ HR HL2 _ L X (node (node RLL RLV RLR _) RV RR _) T :- - HR > HL2, !, - create {create L X RLL} RLV {create RLR RV RR} T. -bal.aux _ _ _ _ L E R T :- create L E R T. - -pred add i:set E, i:(E -> E -> cmp -> prop), i:E, o:set E. -add empty _ E T :- create empty E empty T. -add (node L X R H) Cmp X1 S :- Cmp X1 X E, add.aux E Cmp L R X X1 H S. -add.aux eq _ L R X _ H (node L X R H). -add.aux lt Cmp L R E X _ T :- bal {add L Cmp X} E R T. -add.aux gt Cmp L R E X _ T :- bal L E {add R Cmp X} T. - -pred mem i:set E, i:(E -> E -> cmp -> prop), i:E. -mem (node L K R _) Cmp E :- Cmp E K O, mem.aux O Cmp L R E. -mem.aux eq _ _ _ _. -mem.aux lt Cmp L _ E :- mem L Cmp E. -mem.aux gt Cmp _ R E :- mem R Cmp E. - -pred remove-min-binding i:set E, o:set E. -remove-min-binding (node empty _ R _) R :- !. -remove-min-binding (node L E R _) X :- bal {remove-min-binding L} E R X. - -pred min-binding i:set E, o:E. -min-binding (node empty E _ _) E :- !. -min-binding (node L _ _ _) E :- min-binding L E. - -pred merge i:set E, i:set E, o:set E. -merge empty X X :- !. -merge X empty X :- !. -merge M1 M2 R :- - min-binding M2 X, - bal M1 X {remove-min-binding M2} R. - -pred remove i:set E, i:(E -> E -> cmp -> prop), i:E, o:set E. -remove empty _ _ empty. -remove (node L E R _) Cmp X M :- Cmp X E O, remove.aux O Cmp L R E X M. -remove.aux eq _ L R _ _ M :- merge L R M. -remove.aux lt Cmp L R E X M :- bal {remove L Cmp X} E R M. -remove.aux gt Cmp L R E X M :- bal L E {remove R Cmp X} M. - -pred cardinal i:set E, o:int. -cardinal empty 0. -cardinal (node L _ R _) N :- N is {cardinal L} + 1 + {cardinal R}. - -pred elements i:set E, i:list E, o:list E. -elements empty X X. -elements (node L E R _) Acc X :- - elements L [E|{elements R Acc}] X. - -} % std.set.private -} % std.set - - -% == I/O builtins ===================================== - -% -- I/O -- - -typeabbrev in_stream (ctype "in_stream"). - -type std_in in_stream. - -typeabbrev out_stream (ctype "out_stream"). - -type std_out out_stream. -type std_err out_stream. - -% [open_in FileName InStream] opens FileName for input -external pred open_in i:string, o:in_stream. - -% [open_out FileName OutStream] opens FileName for output -external pred open_out i:string, o:out_stream. - -% [open_append FileName OutStream] opens FileName for output in append mode -external pred open_append i:string, o:out_stream. - -% [close_in InStream] closes input stream InStream -external pred close_in i:in_stream. - -% [close_out OutStream] closes output stream OutStream -external pred close_out i:out_stream. - -% [output OutStream Data] writes Data to OutStream -external pred output i:out_stream, i:string. - -% [flush OutStream] flush all output not yet finalized to OutStream -external pred flush i:out_stream. - -% [input InStream Bytes Data] reads Bytes from InStream -external pred input i:in_stream, i:int, o:string. - -% [input_line InStream Line] reads a full line from InStream -external pred input_line i:in_stream, o:string. - -% [eof InStream] checks if no more data can be read from InStream -external pred eof i:in_stream. - -% -- System -- - -% [gettimeofday T] sets T to the number of seconds elapsed since 1/1/1970 -external pred gettimeofday o:float. - -% [getenv VarName Value] Like Sys.getenv -external pred getenv i:string, o:option string. - -% [system Command RetVal] executes Command and sets RetVal to the exit code -external pred system i:string, o:int. - -% -- Unix -- - -% gathers the standard file descriptors or a process -kind unix.process type. -type unix.process out_stream -> in_stream -> in_stream -> unix.process. - -% [unix.process.open Executable Arguments Environment P Diagnostic] OCaml's -% Unix.open_process_args_full. -% Note that the first argument is the executable name (as in argv[0]). -% If Executable is omitted it defaults to the first element of -% Arguments. -% Environment can be left unspecified, defaults to the current process -% environment. -% This API only works reliably since OCaml 4.12. -external pred unix.process.open i:string, i:list string, i:list string, - o:unix.process, o:diagnostic. - -% [unix.process.close P Diagnostic] OCaml's Unix.close_process_full -external pred unix.process.close i:unix.process, o:diagnostic. - -% -- Debugging -- - -% [term_to_string T S] prints T to S -external pred term_to_string i:any, o:string. - -% == Elpi runtime builtins ===================================== - -% [trace.counter Name Value] reads the Value of a trace point Name -external pred trace.counter i:string, o:int. - -% [gc.get MinorHeapSize MajorHeapIncrement SpaceOverhead Verbose MaxOverhead -% StackLimit AllocationPolicy WindowSize] Reads the current settings of the -% garbage collector. See also OCaml's Gc.control type documentation. -external pred gc.get o:int, o:int, o:int, o:int, o:int, o:int, o:int, - o:int. - -% [gc.set MinorHeapSize MajorHeapIncrement SpaceOverhead Verbose MaxOverhead -% StackLimit AllocationPolicy WindowSize] Writes the current settings of the -% garbage collector. Any parameter left unspecificed (eg _) is not changed. -% See also OCaml's Gc.control type documentation. -external pred gc.set i:int, i:int, i:int, i:int, i:int, i:int, i:int, - i:int. - -% [gc.minor] See OCaml's Gc.minor documentation. -external pred gc.minor . - -% [gc.major] See OCaml's Gc.major documentation. -external pred gc.major . - -% [gc.full] See OCaml's Gc.full_major documentation. -external pred gc.full . - -% [gc.compact] See OCaml's Gc.compact documentation. -external pred gc.compact . - -% [gc.stat MinorWords PromotedWords MajorWords MinorCollections -% MajorCollections HeapWords HeapChunks LiveWords LiveBlocks FreeWords -% FreeBlocks LargestFree Fragments Compactions TopHeapWords StackSize] See -% OCaml's Gc.stat documentation. -external pred gc.stat o:float, o:float, o:float, o:int, o:int, o:int, - o:int, o:int, o:int, o:int, o:int, o:int, o:int, - o:int, o:int, o:int. - -% [gc.quick-stat MinorWords PromotedWords MajorWords MinorCollections -% MajorCollections HeapWords HeapChunks Compactions TopHeapWords StackSize] -% See OCaml's Gc.quick_stat documentation. -external pred gc.quick-stat o:float, o:float, o:float, o:int, o:int, - o:int, o:int, o:int, o:int, o:int. - -% == Lambda Prolog builtins ===================================== - -% -- Extra I/O -- - -% [open_string DataIn InStream] opens DataIn as an input stream -external pred open_string i:string, o:in_stream. - -% [lookahead InStream NextChar] peeks one byte from InStream -external pred lookahead i:in_stream, o:string. - -% -- Hacks -- - -% [string_to_term S T] parses a term T from S -external pred string_to_term i:string, o:any. - -% [readterm InStream T] reads T from InStream, ends with \n -external pred readterm i:in_stream, o:any. - -pred printterm i:out_stream, i:A. - -printterm S T :- term_to_string T T1, output S T1. - -pred read o:A. - -read S :- flush std_out, input_line std_in X, string_to_term X S. - - - - diff --git a/elpi-builtin.elpi b/elpi-builtin.elpi new file mode 120000 index 000000000..2d9796c9c --- /dev/null +++ b/elpi-builtin.elpi @@ -0,0 +1 @@ +builtin-doc/elpi-builtin.elpi \ No newline at end of file diff --git a/elpi/dune b/elpi/dune new file mode 100644 index 000000000..7c74d7fbc --- /dev/null +++ b/elpi/dune @@ -0,0 +1,20 @@ +(coq.theory + (name elpi_elpi) ; FIXME + (package coq-elpi)) + +(rule + (target dummy.v) + (deps + (glob_files *.elpi)) + (action + (with-stdout-to %{target} + (progn + (echo "Require Import String.\nOpen Scope string_scope.\nLocal Definition _hash := \"\n") + (run coq_elpi_shafile %{deps}) + (echo "\".\n"))))) + +(install + (files + (glob_files (*.elpi with_prefix coq/user-contrib/elpi_elpi/))) + (section lib_root) + (package coq-elpi)) diff --git a/etc/dune b/etc/dune new file mode 100644 index 000000000..1b197edfc --- /dev/null +++ b/etc/dune @@ -0,0 +1,5 @@ +(executable + (name shafile) + (public_name coq_elpi_shafile) + (modules shafile) + (package coq-elpi)) \ No newline at end of file diff --git a/etc/shafile.ml b/etc/shafile.ml new file mode 100644 index 000000000..27f66aae0 --- /dev/null +++ b/etc/shafile.ml @@ -0,0 +1,3 @@ +let () = + Sys.argv |> Array.iter (fun file -> + Printf.printf "%s: %s\n" file @@ Digest.to_hex @@ Digest.file file) \ No newline at end of file diff --git a/examples/dune b/examples/dune new file mode 100644 index 000000000..9a7bee3cd --- /dev/null +++ b/examples/dune @@ -0,0 +1,7 @@ +(coq.theory + (package coq-elpi) + (name elpi_examples) + (plugins coq-elpi.elpi) + (theories elpi)) + +; (include_subdirs qualified) diff --git a/examples/example_abs_evars.v b/examples/example_abs_evars.v deleted file mode 100644 index 96fb4e4c3..000000000 --- a/examples/example_abs_evars.v +++ /dev/null @@ -1,117 +0,0 @@ -From elpi Require Import elpi. - -(** Closing a term with holes with binders *) - -(* - -The operation consists in replacing all occurrences of the same hole -in a term by a bound variable. - -We first traverse the term and count how many distinct hole are there -and replace them by a placeholder to be later abstracted. -Once we know how many binders we need, we generate the spine of binders -and replace the placeholders by the bound variables. - -This example is interesting because it uses the constraint store -to attach data to holes, in particular if the hole has been seen before, -and to attach to each hole a unique number. - -*) - -Elpi Tactic abs_evars. -Elpi Accumulate lp:{{ - -% we add a new constructor to terms to represent terms to be abstracted -type abs int -> term. - -% bind back abstracted subterms -pred bind i:int, i:int, i:term, o:term. -bind I M T T1 :- M > I, !, - T1 = {{ forall x, lp:(B x) }}, - N is I + 1, - pi x\ % we allocate the fresh symbol for (abs M) - (copy (abs N) x :- !) => % we schedule the replacement (abs M) -> x - bind N M T (B x). -bind M M T T1 :- copy T T1. % we perform all the replacements - -% for a term with M holes, returns a term with M variables to fill these holes -% the clause see is only generated for a term if it hasn't been seen before -% the term might need to be typechecked first or main generates extra holes for the -% type of the parameters -pred abs-evars i:term, o:term, o:int. -abs-evars T1 T3 M :- std.do! [ - % we put (abs N) in place of each occurrence of the same hole - (pi T Ty N N' M \ fold-map T N (abs M) M :- var T, not (seen? T _), !, coq.typecheck T Ty ok, fold-map Ty N _ N', M is N' + 1, seen! T M) => - (pi T N M \ fold-map T N (abs M) N :- var T, seen? T M, !) => - fold-map T1 0 T2 M, - % we abstract M holes (M abs nodes) - bind 0 M T2 T3, - % cleanup constraint store - purge-seen!, -]. - -% all constraints are also on _ so that they share -% a variable with the constraint to purge the store - -% we query if the hole was seen before, and if so -% we fetch its number -pred seen? i:term, o:int. -seen? X Y :- declare_constraint (seen? X Y) [X,_]. - -% we declare it is now seen and label it with a number -pred seen! i:term, i:int. -seen! X Y :- declare_constraint (seen! X Y) [X,_]. - -% to empty the store -pred purge-seen!. -purge-seen! :- declare_constraint purge-seen! [_]. - -constraint seen? seen! purge-seen! { - % a succesful query, give the label back via M - rule (seen! X N) \ (seen? X M) <=> (M = N). - % an unsuccesful query - rule \ (seen? X _) <=> false. - - rule purge-seen! \ (seen! _ _). - rule \ purge-seen!. -} - -% if we pass an argument this is what we use to refine the goal -solve (goal _ _ _ _ [trm T] as G) GL :- - std.assert-ok! (coq.elaborate-ty-skeleton T _ T1) "illtyped", - std.assert! (abs-evars T1 ClosedT1 _) "closure fails", - refine ClosedT1 G GL. - -% if we pass no argument, then we abstract the goal. -% the first subgoal is a proof of the abstracted goal, while -% the other goals are for the abstracted premises -solve (goal _ _ T _ [] as G) GL :- - std.assert! (abs-evars T ClosedT N) "closure fails", - coq.mk-app {{ (fun x : lp:ClosedT => x) _ }} {coq.mk-n-holes N} R, - refine R G GL. - -}}. -Elpi Typecheck. -Elpi Export abs_evars. - -Fail Lemma test : forall x, x = x. -Lemma test : abs_evars (forall x, x = x). -intros t x; reflexivity. -Abort. - -Lemma test : abs_evars (forall x y, x = y). -intros t x y; symmetry. -Abort. - -Lemma test : True. -assert (abs_evars (tt = _)) as H. - intro x; destruct x; reflexivity. -Abort. - -Lemma test : exists x, x = tt. -econstructor. -(* it is silly, but shows the code above performs the abstraction *) -elpi abs_evars. - now intros []. -exact tt. -Qed. diff --git a/examples/example_abs_evars.v b/examples/example_abs_evars.v new file mode 120000 index 000000000..b7e706393 --- /dev/null +++ b/examples/example_abs_evars.v @@ -0,0 +1 @@ +../tests/example_abs_evars.t/test.v \ No newline at end of file diff --git a/examples/example_curry_howard_tactics.v b/examples/example_curry_howard_tactics.v deleted file mode 100644 index 7e984143b..000000000 --- a/examples/example_curry_howard_tactics.v +++ /dev/null @@ -1,90 +0,0 @@ -From elpi Require Import elpi. - -(* Tactics - - The entry point of a tactic is called solve - and the goal is made of a proof context, a type - to inhabit and the corresponding evar to assign *) - -Elpi Tactic id. -Elpi Accumulate lp:{{ - solve (goal Ctx Ev Ty _ _) _ :- - coq.say "goal" Ev "is\n" Ctx "\n-------\n" Ty. -}}. -Elpi Typecheck. - - -Lemma l0 x y z (H : x < y) : y < z -> x < z. -Proof. -elpi id. -Abort. - -(* Things are wired up in such a way that assigning a - "wrong" value to Ev fails *) - -Elpi Tactic silly. -Elpi Accumulate lp:{{ - solve (goal _ Ev _ _ _) _ :- Ev = {{true}}. - solve (goal _ Ev _ _ _) _ :- Ev = {{3}}. -}}. -Elpi Typecheck. - -Lemma l1 : nat. -Proof. -elpi silly. -Show Proof. -Qed. - -(* Now we write "intro" in Curry-Howard style *) - -Elpi Tactic intro. -Elpi Accumulate lp:{{ - solve (goal _ _ _ _ [str S] as G) GS :- - coq.string->name S N, - refine (fun N Src_ Tgt_) G GS. -}}. -Elpi Typecheck. - -Lemma l2 x y z (H : x < y) : y < z -> x < z. -Proof. -elpi intro H1. -Abort. - -(* Now let's write a little automation *) - -Elpi Tactic auto. -Elpi Accumulate lp:{{ - shorten coq.ltac.{ open , or , repeat }. - - pred intro i:name, i:goal, o:list sealed-goal. - intro S G GS :- refine (fun S Src_ Tgt_) G GS. - - % Ex falso - pred exf i:goal, o:list sealed-goal. - exf (goal Ctx _ Ty _ _ as G) [] :- - std.exists Ctx (x\ sigma w\ x = decl V w {{False}}), - refine {{ match lp:V in False return lp:Ty with end }} G []. - - % Constructor - pred kon i:goal, o:list sealed-goal. - kon (goal _ _ Ty _ _ as G) GS :- - coq.safe-dest-app Ty (global (indt GR)) _, - coq.env.indt GR _ _ _ _ Ks Kt, - std.exists2 Ks Kt (k\ t\ - coq.saturate t (global (indc k)) P, - refine P G GS). - - % entry point; we assert no goals are left - solve G [] :- - repeat (or [open exf, open kon, open (intro `H`)]) (seal G) []. - -}}. -Elpi Typecheck. - -Lemma l3 : forall P : Prop, (False -> P) /\ (False \/ True). -Proof. -elpi auto. -Qed. - - - diff --git a/examples/example_curry_howard_tactics.v b/examples/example_curry_howard_tactics.v new file mode 120000 index 000000000..626135a46 --- /dev/null +++ b/examples/example_curry_howard_tactics.v @@ -0,0 +1 @@ +../tests/example_curry_howard_tactics.t/test.v \ No newline at end of file diff --git a/examples/example_data_base.v b/examples/example_data_base.v deleted file mode 100644 index dbe9a11d8..000000000 --- a/examples/example_data_base.v +++ /dev/null @@ -1,93 +0,0 @@ -From elpi Require Import elpi. - -(** Data bases are accumulated by name, hence can be shared among multiple - commands or across successive executions of the same command. - - Let's start with a db containing international phone prefixes *) - -Elpi Db phonebook.db lp:{{ - pred phone_prefix o:string, o:int. - phone_prefix "USA" 1. -}}. - -Elpi Command print_db. -Elpi Accumulate Db phonebook.db. -Elpi Accumulate lp:{{ - main [] :- std.findall (phone_prefix S_ N_) L, !, coq.say "The Db contains" L. - main [str S] :- coq.say "Phone prefix for" S "is" {phone_prefix S}, !. - main [str S] :- coq.error "No prefix for" S. -}}. -Elpi Typecheck. - -Elpi print_db. -Elpi print_db USA. -Fail Elpi print_db Italy. - -Elpi Command add_db. -Elpi Accumulate Db phonebook.db. -Elpi Accumulate lp:{{ - main [str S, int N] :- - coq.elpi.accumulate _ "phonebook.db" (clause _ _ (phone_prefix S N)). -}}. -Elpi Typecheck. - -Elpi add_db France 33. -Elpi add_db Italy 39. -Elpi print_db. -Elpi print_db France. - -(** Data bases don't need to be that simple, they can contain - arbitrary clauses, in particular conditional ones. *) - -Elpi Db food.db lp:{{ - - pred sweet o:string. - sweet "apricot". - - pred tasty o:string. - tasty "salmon". - -}}. -Elpi Command add_recipy. -Elpi Accumulate Db food.db. -Elpi Accumulate lp:{{ - pred test-sweetness i:argument, o:prop. - test-sweetness (str X) (sweet X). - - pred test-tastiness i:argument, o:prop. - test-tastiness (str X) (tasty X). - - main [str Name|Ingredients] :- - std.map Ingredients test-sweetness SweetConditions, - % trick: ":-" accepts a list of propositions on the RHS - coq.elpi.accumulate _ "food.db" (clause _ _ (sweet Name :- SweetConditions)), - - std.map Ingredients test-tastiness TastyConditions, - std.forall TastyConditions (i\ - coq.elpi.accumulate _ "food.db" (clause _ _ (tasty Name :- i))). -}}. -Elpi Typecheck. - -Elpi Command is_sweet. -Elpi Accumulate Db food.db. -Elpi Accumulate lp:{{ - main [str Name] :- if (sweet Name) (coq.say "sweet!") (coq.say "brr"). -}}. -Elpi Typecheck. - -Elpi Command is_tasty. -Elpi Accumulate Db food.db. -Elpi Accumulate lp:{{ - main [str Name] :- if (tasty Name) (coq.say "yummy!") (coq.say "bohf"). -}}. -Elpi Typecheck. - -Elpi add_recipy "pie" "potato" "salmon". -Elpi add_recipy "jam" "apricot". -Elpi add_recipy "tart" "jam". - -Elpi is_sweet "tart". -Elpi is_sweet "pie". -Elpi is_tasty "pie". - - diff --git a/examples/example_data_base.v b/examples/example_data_base.v new file mode 120000 index 000000000..7cfdcb948 --- /dev/null +++ b/examples/example_data_base.v @@ -0,0 +1 @@ +../tests/example_data_base.t/test.v \ No newline at end of file diff --git a/examples/example_fuzzer.v b/examples/example_fuzzer.v deleted file mode 100644 index 0c4b010e4..000000000 --- a/examples/example_fuzzer.v +++ /dev/null @@ -1,99 +0,0 @@ -From elpi Require Import elpi. - -(** Intrinsically typed data type and semantics, from software foundations. - - We devise a command to fuzz the semantics by flipping some operators. - We do it by locally checking that the fuzzing produces welltyped terms, - reducing a bit the nondeterminism of the fuzzer. -*) - -Inductive ty := B | N. - -Inductive Exp : ty -> Type := -| NUM : nat -> Exp N -| BOOL : bool -> Exp B -| PLUS : Exp N -> Exp N -> Exp N -| AND : Exp B -> Exp B -> Exp B -| OR : Exp B -> Exp B-> Exp B -| EQ : Exp N -> Exp N -> Exp B. - -Inductive Val : ty -> Set := - | iNv : nat -> Val N - | iBv : bool -> Val B. - -Inductive eval : forall {T: ty}, Exp T -> Val T -> Prop := - | E_Num n : - eval (NUM n) (iNv n) - | E_Bool b : - eval (BOOL b) (iBv b) - | E_Plus e1 e2 n1 n2 : - eval e1 (iNv n1) -> - eval e2 (iNv n2) -> - eval (PLUS e1 e2) (iNv (n1 + n2)) - | E_AND e1 e2 b1 b2 : - eval e1 (iBv b1) -> - eval e2 (iBv b2) -> - eval (AND e1 e2) (iBv (b1 && b2)) - | E_OR e1 e2 b1 b2 : - eval e1 (iBv b1) -> - eval e2 (iBv b2) -> - eval (OR e1 e2) (iBv (b1 || b2)) - | E_EQ e1 e2 n1 n2 : - eval e1 (iNv n1) -> - eval e2 (iNv n2) -> - eval (EQ e1 e2) (iBv (Nat.eqb n1 n2)). - -Elpi Command fuzz. -Elpi Accumulate lp:{{ - -pred fuzz i:term, o:term. - -% fuzzin rule: we look for a Coq term (?Op ?A ?B) and we turn it in (AND ?A ?B) -% only if the new term is well typed. -fuzz {{ lp:Op lp:A lp:B }} Fuzzed :- - coq.say "DEBUG: attempt at fuzzing binary op:" Op, - fuzz A A1, fuzz B B1, - Fuzzed = {{ AND lp:A1 lp:B1 }}, - coq.typecheck Fuzzed _ ok, % we don't care about the type, only that it is ok - coq.say "DEBUG: fuzzed!". - -% rule for the dependent function space -fuzz (prod N S T) (prod N S1 T1) :- - fuzz S S1, - % we load the context with types for x and y, as well as the fact that - % we fuzz x to y - pi x y\ decl x N S => decl y N S1 => fuzz x y => fuzz (T x) (T1 y). - -% rule for application -fuzz (app L) (app L1) :- std.map L fuzz L1. - -% rule for global constants -fuzz (global X) (global X). - -% TODO: we should have clauses for all other type formers... - -pred rename-constructors i:constructor, o:pair constructor string. -rename-constructors C (pr C C1) :- - coq.gref->id (indc C) S, - C1 is S ^ "1". - -main [str IN, str OUT ] :- - % locate the inductive - coq.locate IN (indt I), - % fetch all its data, in particulat the types of the constructors - coq.env.indt I B NP NPU A KN KT, - % fuzz all constructor types - std.map KT fuzz KT1, - % we rename them, otherwise Coq complains the names are already used - std.map KN rename-constructors KN1, - % declare the new inductive - coq.build-indt-decl (pr I OUT) B NP NPU A KN1 KT1 Decl, - coq.env.add-indt Decl _. - -}}. -Elpi Typecheck. - -Elpi fuzz eval eval1. - -(* let's print our new, broken, semantics ;-) *) -Print eval1. \ No newline at end of file diff --git a/examples/example_fuzzer.v b/examples/example_fuzzer.v new file mode 120000 index 000000000..7e19a6c60 --- /dev/null +++ b/examples/example_fuzzer.v @@ -0,0 +1 @@ +../tests/example_fuzzer.t/test.v \ No newline at end of file diff --git a/examples/example_generalize.v b/examples/example_generalize.v deleted file mode 100644 index 158f9baa5..000000000 --- a/examples/example_generalize.v +++ /dev/null @@ -1,39 +0,0 @@ -From elpi Require Import elpi. - -(** Abstract a term over something, like the generalize tactic *) - -Elpi Command generalize. -Elpi Accumulate lp:{{ - -% we add a new constructor to terms to represent terms to be abstracted -type abs int -> term. - -% example rule, abstracts all 1s. We place it at the beginning of fold-map, see -% coq-lib.elpi for the full definition of fold-map -:before "fold-map:start" -fold-map {{ 1 }} N (abs M) M :- !, M is N + 1. - -% bind back abstracted subterms -pred bind i:int, i:term, o:term. -bind M T T1 :- M > 0, - T1 = {{ fun x => lp:(B x) }}, % we build a Coq "fun .. => " - N is M - 1, - pi x\ % we allocate the fresh symbol for (abs M) - (copy (abs M) x :- !) => % we schedule the replacement (abs M) -> x - bind N T (B x). -bind 0 T T1 :- copy T T1. % we perform all the replacements - -main [trm T] :- std.do! [ - fold-map T 0 T1 M, - bind M T1 T2, - coq.say {coq.term->string T} "===>" {coq.term->string T2}, -]. - - -}}. -Elpi Typecheck. - -Elpi generalize (3 + 7). -(* prints: - (3 + 7) ===> (fun (x : ?e) (x0 : ?e0) => S (S x0) + S (S (S (S (S (S x)))))) -*) diff --git a/examples/example_generalize.v b/examples/example_generalize.v new file mode 120000 index 000000000..f438b6c09 --- /dev/null +++ b/examples/example_generalize.v @@ -0,0 +1 @@ +../tests/example_generalize.t/test.v \ No newline at end of file diff --git a/examples/example_import_projections.v b/examples/example_import_projections.v deleted file mode 100644 index 5f44e339f..000000000 --- a/examples/example_import_projections.v +++ /dev/null @@ -1,73 +0,0 @@ -From elpi Require Import elpi. - -(* "import" a record instance by naming it's applied projections *) - -Elpi Command import.projections. -Elpi Accumulate lp:{{ -main [str S] :- - coq.locate S GR, - coq.env.typeof GR Ty, - main-import-projections (global GR) Ty. -main [trm TSkel] :- - % input terms are not elaborated yet - std.assert-ok! (coq.elaborate-skeleton TSkel Ty T) "input term illtyped", - main-import-projections T Ty. - -pred main-import-projections i:term, i:term. -main-import-projections T Ty :- - std.assert! (coq.safe-dest-app Ty (global (indt I)) Args) "not an inductive term", - std.assert! (coq.env.record? I PrimProjs) "not a record", - coq.env.indt I _ _ NParams _ _ _, - std.assert! (std.length Args NParams) "the record is not fully appplied", - coq.env.projections I Ps, % get the projections generated by Coq - if (PrimProjs = tt) - (std.forall Ps (declare-abbrev {std.append {coq.mk-n-holes NParams} [T]})) - (std.forall Ps (declare-abbrev {std.append Args [T]})). - -pred declare-abbrev i:list term, i:option constant. -declare-abbrev _ none. -declare-abbrev Args (some Proj) :- - coq.gref->id (const Proj) ID, % get the short name of the projection - OnlyParsing = tt, - coq.mk-app (global (const Proj)) Args T, % handles the case Args = [] - @local! => coq.notation.add-abbreviation ID 0 T OnlyParsing _. -}}. -Elpi Typecheck. -Elpi Export import.projections. (* make the command available *) - -(**************************** usage examples *********************************) - -Record r T (t : T) := Build { - p1 : nat; - p2 : t = t; - _ : p2 = refl_equal; -}. - -Section test. -Variable x : r nat 3. -import.projections x. -Print p2. (* Notation p2 := (readme.p2 nat 3 x) *) -Check p1 : nat. (* check p1 is already applied to x *) -End test. - -Fail Check p1 : nat. (* the abbreviation is gone *) -Check p1 : forall (T : Type) (t : T), r T t -> nat. (* p1 points again to the original projection *) - -Module test. -import.projections (Build bool false 3 (refl_equal _) (refl_equal _)). -Check refl_equal _ : p1 = 3. (* check the value of p1 is 3 *) -End test. - -Set Primitive Projections. -Unset Auto Template Polymorphism. -Record r1 (A : Type) : Type := { - f1 : A; - f2 : nat; -}. - -Section test2. -Variable x : r1 bool. -import.projections x. -Unset Printing Primitive Projection Parameters. -Check f1. (* there is an _, hence it is the primitive projection *) -End test2. diff --git a/examples/example_import_projections.v b/examples/example_import_projections.v new file mode 120000 index 000000000..b884dffc5 --- /dev/null +++ b/examples/example_import_projections.v @@ -0,0 +1 @@ +../tests/example_import_projections.t/test.v \ No newline at end of file diff --git a/examples/example_record_expansion.v b/examples/example_record_expansion.v deleted file mode 100644 index 64e192b3b..000000000 --- a/examples/example_record_expansion.v +++ /dev/null @@ -1,203 +0,0 @@ -From elpi Require Import elpi. - -(** - This file sketches a procedure to translate a term abstracted over - a specific record to a term abstracted over the components of that record. - - Example: - - Record r := mk { proj1 : T1; proj2 : T2 }. - Definition f (x : r) := Body(proj1 x,proj2 x). - - Is expanded to: - - Definition f1 v1 v2 := Body(v1,v2). - - And recursively, if g uses f, then g1 must use f1... - - The idea is to take "f", replace "(x : r)" with as many abstractions as - needed in order to write "mk v1 v2", then replace "x" with "mk v1 v2", finally - fire iota reductions such as "proj1 (mk v1 v2) = v1" to obtain "f1". - - Then record a global replacement "f x = f1 v2 v2" whenever "x = mk v1 v2". - -*) - -Elpi Db record.expand.db lp:{{ - % This data base will contain all the expansions performed previously. - % For example, if f was expandded to f1 we would have this clause: - - % copy (app[f, R | L]) (app[f1, V1, V2 | L1]) :- - % copy R (app[k, V1, V2]), std.map L copy L1. - -}}. - -Elpi Command record.expand. -Elpi Accumulate Db record.expand.db. -Elpi Accumulate lp:{{ - -% This builds a clause to replace "proji (k y1..yn)" by "yi" -pred build-iotared-clause i:term, i:(pair constant term), o:prop. -build-iotared-clause T (pr Proj Var) - (pi L AppVar\ copy(app [global (const Proj),T|L]) AppVar :- coq.mk-app Var L AppVar). - -% The core algorithm ---------------------------------------------------------- - -% It is idiomatic in λProlog to perform a single recursion over the data and -% perform multiple tasks while going. Here we both obtain the expanded term -% and the clause that records that expansion. Indeed the binders introduced -% in the new term (standing for the record fialds) and the quantifications -% introduced in the clause are very similar. - -% missing in std -pred cons_assoc_opt i:option A, i:B, i:list (pair A B), o:list (pair A B). -cons_assoc_opt none _ X X. -cons_assoc_opt (some A) B X [pr A B|X]. - -% a package of data that we need to carry but rarely fully access -kind info type. -type info - inductive % the record to expand - -> gref % the term being expanded - -> gref % the term being expanded and its expanded name - -> list (option constant) % canonical projections - -> constructor % record constructor - -> term % record constructor type - -> info. - -% This predicate turns the OldBo in "fun x : r => OldBo" into -% "fun v1 v2 => NewBo". It is fueled by "KTY" (corresponding to the type -% of the record constructor). In parallel it consumes the list of projections, -% so that it can record that the i-th projection should be replaced by -% the variable standing for the i-th record field (accumulator called Iota) -pred expand-abstraction - i:info, - i:term, % the varibale binding the record in the input term - - % fuel - i:term, % the type of the record constructor - i:list (option constant), % projections - - i:term, o:term, % the Old and New body - - i:term, % constructor applied to all arguments treated so far - i:list (pair constant term), % iota rules for reductions so far - - % used by expand-spine, accumulated here - i:list term, i:list term, % variables for the head of the clause (LHS and RHS) - i:list prop, o:prop. % accumulator for the premises of the clause, and the clause - -expand-abstraction Info Rec (prod N S F) [P|PS] OldBo (fun N S Bo) KArgs Iota AccL AccR Premises (pi x\ Clause x) :- - pi x\ - expand-abstraction Info Rec - (F x) PS OldBo (Bo x) {coq.mk-app KArgs [x]} {cons_assoc_opt P x Iota} AccL [x|AccR] Premises (Clause x). - -expand-abstraction Info Rec (let N S B F) [P|PS] OldBo (let N S B Bo) KArgs Iota AccL AccR Premises Clause :- - pi x\ % a let in is not a real argument to KArgs, but may need a "iota" redex, since the projection could exist - expand-abstraction Info Rec - (F x) PS OldBo (Bo x) KArgs {cons_assoc_opt P x Iota} AccL AccR Premises Clause. - -expand-abstraction Info Rec _ [] OldBo Result ExpandedRecord Iota AccL AccR Premises Clause :- - % generate all substitutions - std.map Iota (build-iotared-clause ExpandedRecord) IotaClauses, - ExpansionClause = copy Rec ExpandedRecord, - % eta expand the record to obtain a new body (that typechecks) - ExpansionClause => copy OldBo NewBo, - % continue, but schedule iota reductions (pre-existing projections became iota redexes) - IotaClauses => - expand-spine Info NewBo Result AccL AccR [ExpansionClause|Premises] Clause. - -% This predicate travrses the spine of lambdas. When it finds an abstraction -% on the record R is calls expand-abstraction. Finally it copies the term, -% applying all substitutions accumulated while descending the spine. -pred expand-spine - i:info, - i:term, o:term, % input and output term - i:list term, i:list term, % variables for the LHS and RHS of the clause head - i:list prop, o:prop. % premises and final clause - -% if we find a lambda over the record R we expand -expand-spine (info R _ _ Projs K KTY as Info) (fun _ (global (indt R)) Bo) Result AccL AccR Premises (pi r\ Clause r) :- !, - pi r\ expand-abstraction Info r KTY Projs (Bo r) Result (global (indc K)) [] [r|AccL] AccR Premises (Clause r). - -% otherwise we traverse the spine -expand-spine Info (fun Name Ty Bo) (fun Name Ty1 Bo1) AccL AccR Premises (pi x y\ Clause x y) :- !, - copy Ty Ty1, - pi x y\ copy x y => expand-spine Info (Bo x) (Bo1 y) [x|AccL] [y|AccR] [copy x y|Premises] (Clause x y). -expand-spine Info (let Name Ty V Bo) (let Name Ty1 V1 Bo1) AccL AccR Premises (pi x y\ Clause x y) :- !, - copy Ty Ty1, - copy V V1, - pi x y\ copy x y => expand-spine Info (Bo x) (Bo1 y) [x|AccL] [y|AccR] [copy x y|Premises] (Clause x y). - -% at the end of the spine we fire the iota redexes and complete the clause -expand-spine (info _ GR NGR _ _ _) X Y AccL AccR Premises Clause :- - copy X Y, - % we build "app[f,x1..xn|rest]" - (pi rest1\ coq.mk-app (global GR) {std.append {std.rev AccL} rest1} (L rest1)), - (pi rest2\ coq.mk-app (global NGR) {std.append {std.rev AccR} rest2} (R rest2)), - % we can now build the clause "copy (app[f,L1..Ln|Rest1]) (app[f1,R1..Rn|Rest2])" - % here we quantify only the tails, the other variables were quantified during - % expand-* - Clause = (pi rest1 rest2\ copy (L rest1) (R rest2) :- [!, std.map rest1 copy rest2 | Premises]). - -% The entry point of the main algorithm, just fetchs some data and passes initial -% values for the accumulators. -pred expand i:inductive, i:gref, i:gref, i:term, o:term, o:prop. -expand R GR NGR X Y Clause :- - std.assert! (coq.env.indt R tt 0 0 _ [K] [KTY]) "record is too complex for this example", - coq.env.projections R Projs, - expand-spine (info R GR NGR Projs K KTY) X Y [] [] [] Clause. - -% This simply dispatches between global references ---------------------------- - -% The only cleverness is that "expand" also builds the clause to be added to -% the data base, and that clause has to mention the name of the constant to be -% generated. Since we don't know it yet (Coq tells us in response to coq.env.add-const) -% we postulate a name for that constant "nc" and later replace it with the real one "NC" -pred expand-gref i:inductive, i:gref, i:string, o:prop. -expand-gref Record (const C) Name Clause :- !, - std.assert! (coq.env.const C (some Bo) _) "only transparent constants can be expanded", - (pi nc\ expand Record (const C) nc Bo NewBo (NClause nc)), - std.assert-ok! (coq.typecheck NewBo _) "illtyped", - coq.env.add-const Name NewBo _ _ NC, - Clause = NClause (const NC). - -expand-gref _ (indt _) _ _ :- coq.error "Not implemented yet". - -expand-gref _ (indc _) _ _ :- coq.error "It makes no sense to expand a constructor alone, expand the inductive instead". - -% Entry point ----------------------------------------------------------------- -main [str R, str In, str Prefix] :- !, - std.assert! (coq.locate R (indt Record)) "The first argument must be a record name", - std.assert! (coq.locate In GR) "The second argument must be a global term", - NewName is Prefix ^ {coq.gref->id GR}, - - expand-gref Record GR NewName Clause, - - % We want our clauses to take precensence over the structural ones of "copy" - coq.elpi.accumulate _ "record.expand.db" (clause _ (before "copy:start") Clause). - -main _ :- coq.error "usage: Elpi record.expand record_name global_term prefix". -}}. -Elpi Typecheck. - -Record r := { T :> Type; X := T; op : T -> X -> bool }. - -Definition f b (t : r) (q := negb b) := fix rec (l1 l2 : list t) := - match l1, l2 with - | nil, nil => b - | cons x xs, cons y ys => andb (op _ x y) (rec xs ys) - | _, _ => q - end. - -Elpi record.expand r f "expanded_". -Print f. -Print expanded_f. - -(* so that we can see the new "copy" clause *) -Elpi Print record.expand. - -Definition g t l s h := (forall x y, op t x y = false) /\ f true t l s = h. - -Elpi record.expand r g "expanded_". -Print expanded_g. diff --git a/examples/example_record_expansion.v b/examples/example_record_expansion.v new file mode 120000 index 000000000..99d1ea699 --- /dev/null +++ b/examples/example_record_expansion.v @@ -0,0 +1 @@ +../tests/example_record_expansion.t/test.v \ No newline at end of file diff --git a/examples/example_record_to_sigma.v b/examples/example_record_to_sigma.v deleted file mode 100644 index ac968ea9e..000000000 --- a/examples/example_record_to_sigma.v +++ /dev/null @@ -1,67 +0,0 @@ -From elpi Require Import elpi. - -(* Define a command to turn records into nested sigma types, suggested - by M. Maggesi for the UniMath library *) -Elpi Command UM.expand. -Elpi Accumulate lp:{{ - -% From a record declaration to an iterated sigma type -pred wrap-fields-ty i:record-decl, o:term. -wrap-fields-ty (field _ _ Ty _\ end-record) Ty. -wrap-fields-ty (field _ Proj Ty Fields) {{ sigT lp:F }} :- - coq.string->name Proj Name, - F = fun Name Ty Bo, - pi x\ decl x Name Ty => wrap-fields-ty (Fields x) (Bo x). - -% From a record declaration to a function building the iterated pairs -% [wrap-fields-bo Rec Acc SigmaTypeDef SigmaTypeName Builder BuilderType] -% Builder = fun arg1 .. argn => existT arg1 (existT arg2 (.. argn) ..) -% Acc gathers arg1 .. argn while building the fun -% SigmaTypeDef is used to fill in the implicit arguments of existT -% SigmaTypeName is used for BuilderType = forall arg1 .. argn, SigmaTypeName -pred wrap-fields-bo i:record-decl, i:list term, i:term, i:term, o:term, o:term. -wrap-fields-bo end-record Acc SigTy Sig T Sig :- - std.rev Acc Args, - wrap-fields-bo.aux Args SigTy T. -wrap-fields-bo (field _ Proj Ty Fields) Acc SigTy Sig (fun Name Ty Bo) (prod Name Ty Tgt) :- - coq.string->name Proj Name, - pi x\ decl x Name Ty => wrap-fields-bo (Fields x) [x|Acc] SigTy Sig (Bo x) (Tgt x). - -wrap-fields-bo.aux [Last] _ Last. -wrap-fields-bo.aux [X|XS] {{ sigT lp:F }} {{ existT lp:F lp:X lp:Rest }} :- - F = fun _ _ G, - wrap-fields-bo.aux XS (G X) Rest. - -% We declare the type and its constructor. -% Missing features: -% - parameters are not supported -% - projections are not synthesized -main [indt-decl (record Name _Sort Kname Fields)] :- - wrap-fields-ty Fields T, - std.assert-ok! (coq.typecheck T Ty) "oops, wrap-fields-ty is bugged", - coq.env.add-const Name T Ty _ C, - wrap-fields-bo Fields [] T (global (const C)) K KTy, - std.assert-ok! (coq.typecheck K KTy) "oops, wrap-fields-bo is bugged", - coq.env.add-const Kname K KTy _ _. - -}}. -Elpi Typecheck. -Elpi Export UM.expand. - -(* From now on UM.expand is a regular command taking as the only argument - a record declaration. *) - -UM.expand Record foo := mk_foo { - f1 : Type; - f2 : f1 -> Type; - f3 : forall t : f1, f2 t -> bool -}. - -Print foo. -(* foo = {f1 : Type & {f2 : f1 -> Type & forall t : f1, f2 t -> bool}} : Type *) - -Print mk_foo. -(* mk_foo = fun (f1 : Type) (f2 : f1 -> Type) (f3 : forall t : f1, f2 t -> bool) => - existT (fun f4 : Type => {f5 : f4 -> Type & forall t : f4, f5 t -> bool}) f1 - (existT (fun f4 : f1 -> Type => forall t : f1, f4 t -> bool) f2 f3) - : forall (f1 : Type) (f2 : f1 -> Type), (forall t : f1, f2 t -> bool) -> foo *) diff --git a/examples/example_record_to_sigma.v b/examples/example_record_to_sigma.v new file mode 120000 index 000000000..510ef6815 --- /dev/null +++ b/examples/example_record_to_sigma.v @@ -0,0 +1 @@ +../tests/example_record_to_sigma.t/test.v \ No newline at end of file diff --git a/examples/example_reduction_surgery.v b/examples/example_reduction_surgery.v deleted file mode 100644 index 94ac3b0b6..000000000 --- a/examples/example_reduction_surgery.v +++ /dev/null @@ -1,42 +0,0 @@ -(** - This file mocks up a reduction tactic unfolding only constants - from a given module. -*) - -From elpi Require Import elpi. - -Elpi Tactic reduce. -Elpi Accumulate lp:{{ - -pred gref->redflag i:gref, o:coq.redflag. -gref->redflag (const C) (coq.redflags.const C). - -solve (goal _ _ Ty _ [str M] as G) GS :- - coq.locate-module M MP, - coq.env.module MP GREFS, - std.map-filter GREFS (x\r\x = gref r, r = (const _)) CONSTANTS, - std.map CONSTANTS (gr\r\ coq.env.transitive-dependencies gr _ r) DEPS, - std.fold DEPS {coq.gref.set.empty} coq.gref.set.union ALLDEPS, - std.append CONSTANTS {coq.gref.set.elements ALLDEPS} All, - std.map-filter All gref->redflag DELTAFLAGS, - coq.redflags.add coq.redflags.nored - [ coq.redflags.beta, coq.redflags.fix, coq.redflags.match | DELTAFLAGS ] - F, - @redflags! F => coq.reduction.cbv.norm Ty Ty1, - refine {{ _ : lp:Ty1 }} G GS. % to leave a vmcast one needs to call ltac1 - -}}. -Elpi Typecheck. - - -Module ToRed. -Definition x := 1. -Definition y := 1. -Definition alias := plus. -End ToRed. - -Goal ToRed.x + ToRed.y = let z := 1 in S z. -elpi reduce "ToRed". -match goal with |- 2 = let z := 1 in S z => trivial end. -Show Proof. -Abort. diff --git a/examples/example_reduction_surgery.v b/examples/example_reduction_surgery.v new file mode 120000 index 000000000..f99c5b15f --- /dev/null +++ b/examples/example_reduction_surgery.v @@ -0,0 +1 @@ +../tests/example_reduction_surgery.t/test.v \ No newline at end of file diff --git a/examples/example_reflexive_tactic.v b/examples/example_reflexive_tactic.v deleted file mode 100644 index b2ca18694..000000000 --- a/examples/example_reflexive_tactic.v +++ /dev/null @@ -1,293 +0,0 @@ - -(** - This file builds a reflexive tactic solving equalities in a monoid. - - We use elpi to: - - reify an expression into a syntax tree - - query a Db of known monoids - - call a few ltac primitives in order to apply the corrctness theorem - -*) - -From elpi Require elpi. -Require Arith ZArith Psatz List ssreflect. - -Import elpi. -Import Arith ZArith Psatz List ssreflect. - -(* This module contains the reflexive normalizer and its correctness proof *) -Module MonoidTheory. - -(* The syntax of terms *) -Inductive lang := -| var (i : nat) (* i-th variable in the context *) -| zero : lang (* Neutral element *) -| add (x y : lang). (* binary operation *) - -(* Interpretation to T *) -Fixpoint interp T (e : T) (op : T -> T -> T) (gamma : list T) (t : lang) : T := - match t with - | var v => nth v gamma e - | zero => e - | add x y => op (interp T e op gamma x) (interp T e op gamma y) - end. - - - (* normalization of parentheses and units *) - Fixpoint normAx t1 acc := - match t1 with - | add t1 t2 => normAx t1 (normAx t2 acc) - | _ => add t1 acc - end. - Fixpoint normA t := - match t with - | add s1 s2 => normAx s1 (normA s2) - | _ => t - end. - Fixpoint norm1 t := - match t with - | var _ => t - | zero => t - | add t1 t2 => - match norm1 t1 with - | zero => norm1 t2 - | t1 => - match norm1 t2 with - | zero => t1 - | t2 => add t1 t2 - end - end - end. - Definition norm t := normA (norm1 t). - - (* Correctness theorem. This is not the point of this demo, please don't - look at the proofs ;-) *) - Section assoc_reflection_proofs. - Variable T : Type. - Variable unit : T. - Variable op : T -> T -> T. - Hypothesis op_assoc : forall a b c, op a (op b c) = op (op a b) c. - Hypothesis unit_l : forall a, op unit a = a. - Hypothesis unit_r : forall a, op a unit = a. - -Lemma normAxA t1 t2 : normAx t1 (normA t2) = normA (add t1 t2). -Proof. by []. Qed. - -Lemma normAx_add {t1 t2 s} : normAx t1 t2 = s -> exists s1 s2, s = add s1 s2. -Proof. -elim: t1 t2 s => /= [i||w1 H1 w2 H2] t2 s <-; try by do 2 eexists; reflexivity. -by case E: (normAx _ _); case/H1: E => s1 [s2 ->]; do 2 eexists; reflexivity. -Qed. - -Lemma norm1_zero {l t} : norm1 t = zero -> interp T unit op l t = unit. -Proof. -by elim: t => [||s1 + s2] //=; case E1: (norm1 s1); case E2: (norm1 s2) => //= -> // ->. -Qed. - -Lemma norm_zero {l t} : norm t = zero -> interp T unit op l t = unit. -Proof. -rewrite /norm; case E: (norm1 t) => [||x y] //; first by rewrite (norm1_zero E). -by move/normAx_add=> [] ? []. -Qed. - -Lemma norm1_var {l t j} : norm1 t = var j -> interp T unit op l t = nth j l unit. -Proof. -elim: t => [i [->]||s1 + s2] //=; case E1: (norm1 s1); case E2: (norm1 s2) => //=. - by rewrite (norm1_zero E2) unit_r => + _ H => ->. -by rewrite (norm1_zero E1) unit_l => _ + H => ->. -Qed. - -Lemma norm_var {l t j} : norm t = var j -> interp T unit op l t = nth j l unit. -Proof. -rewrite /norm; case E: (norm1 t); rewrite /= ?(norm1_var E) //; first by move=> [->]. -by move/normAx_add=> [] ? []. -Qed. - -Lemma norm1_add {l t s1 s2} : norm1 t = add s1 s2 -> interp T unit op l t = op (interp T unit op l s1) (interp T unit op l s2). -Proof. -elim: t s1 s2 => [||w1 + w2 + s1 s2] //=. -by case E1: (norm1 w1); case E2: (norm1 w2) => //= ++ [<- <-] /=; - do 2! [ move=> /(_ _ _ (refl_equal _)) -> | move=> _]; - rewrite ?(norm1_zero E1) ?(norm1_zero E2) ?(norm1_var E1) ?(norm1_var E2). -Qed. - -Lemma normAxP {l t1 t2} : interp T unit op l (normAx t1 t2) = op (interp T unit op l t1) (interp T unit op l t2). -Proof. by elim: t1 t2 => [||s1 Hs1 s2 Hs2] t2 //=; rewrite Hs1 Hs2 !op_assoc. Qed. - -Lemma normAP {l} t : interp T unit op l (normA t) = interp T unit op l t. -Proof. by elim: t => //= x Hx y Hy; rewrite normAxP Hy. Qed. - -Lemma norm_add {l t s1 s2} : norm t = add s1 s2 -> interp T unit op l t = op (interp T unit op l s1) (interp T unit op l s2). -Proof. -rewrite /norm; case E: (norm1 t) => [||x y]; rewrite //= (norm1_add E). -elim: x y s1 s2 {E} => //= [>[<- <- //=]|>[<- <-]|x + y + w s1 s2]; rewrite ?normAP //= ?unit_l //. -by rewrite normAxA -!op_assoc => ++ E => /(_ _ _ _ E) ->. -Qed. - -Lemma normP_ l t1 t2 : norm t1 = norm t2 -> interp T unit op l t1 = interp T unit op l t2. -Proof. -case E: (norm t2) => [?||??] => [/norm_var|/norm_zero|/norm_add] ->. - by rewrite (norm_var E). - by rewrite (norm_zero E). -by rewrite (norm_add E). -Qed. - -End assoc_reflection_proofs. -End MonoidTheory. - - - -(* Finally, let's build the tactic *) - -Import MonoidTheory. - -(* This is the correctness theorem of our normalizer *) -Definition normP {T e op gamma t1 t2} p1 p2 p3 H := @normP_ T e op p1 p2 p3 gamma t1 t2 H. -About normP. -Open Scope Z_scope. - -Goal forall x y z t, (x + y) + (z + 0 + t) = x + (y + z) + t. -Proof. -intros. - -change (interp Z Z.zero Z.add (x::y::z::t::nil) - (add (add (var 0) (var 1)) (add (add (var 2) zero) (var 3))) - = - interp Z Z.zero Z.add (x::y::z::t::nil) - (add (add (var 0) (add (var 1) (var 2))) (var 3))). - -apply: normP Z.add_assoc Z.add_0_l Z.add_0_r _. - -reflexivity. -Qed. - -(** Now, let's implement a tactic that does for us: - - the change step (reification) - - apply the correctness lemma -*) - -(* This is for later *) -Elpi Db monoid.db lp:{{ - pred is_monoid - i:term, % type - o:term, % zero - o:term, % op - o:term, % assoc - o:term, % unit_l - o:term. % unit_r -}}. - -Elpi Tactic monoid. -Elpi Accumulate Db monoid.db. -Elpi Accumulate lp:{{ - -% [mem L X N] asserts that X is at position N in L. -% The list is open-ended, that is it terminates with an Elpi unification -% variable, so that the list can be extended with new elements if needed. -% e.g. mem (3 :: L) 4 N ---> L = 4 :: L1, N = 1 -% Note: we build a Coq list, since we have to generate that anyway. We could -% use an Elpi list or any other data structure here, but then we would need -% to convert back anyway. -pred mem o:term, o:term, o:term. -mem {{ lp:X :: _ }} X {{ O }} :- !. -mem {{ _ :: lp:XS }} X {{ S lp:N }} :- mem XS X N. - -% Give that [mem] works with open ended lists we need a way to close it (assign -% nil to the tail) at the very end of reification. -pred close o:term. -close {{ nil }} :- !. -close {{ _ :: lp:XS }} :- close XS. - -% [quote Zero Op T AstT L] recognizes Zero and Op in T and generates the -% corresponding AstT using the "context" L for variables standing for -% terms that are not Zero nor Op -pred quote i:term, i:term, i:term, o:term, o:term. -quote Zero Op {{ lp:Op lp:T1 lp:T2 }} {{ add lp:R1 lp:R2 }} L :- !, - quote Zero Op T1 R1 L, - quote Zero Op T2 R2 L. -quote Zero _ Zero {{ zero }} _ :- !. -quote _ _ T {{ var lp:R }} L :- mem L T R. - -% This preliminary version of the tactic takes as arguments the monoid signature -% and changes the goal [A = B] into [interp L AstA = interp L AstB] -solve (goal _ _ {{ @eq lp:T lp:A lp:B }} _ [trm Zero, trm Op] as G) GS :- - quote Zero Op A AstA L, - quote Zero Op B AstB L, - close L, - % We are very low level here, we assign a term directly to the goal handler - % while one could use ltac primitives (as we do later) - Ty = {{ (interp lp:T lp:Zero lp:Op lp:L lp:AstA) - = (interp lp:T lp:Zero lp:Op lp:L lp:AstB) }}, - % This implements the "change" tactic - refine {{ (_ : lp:Ty) }} G GS. - -:name "error" -solve _ _ :- coq.error "Not an equality / no signature provided". - -}}. -Elpi Typecheck. -Tactic Notation "monoid" constr(zero) constr(add) := elpi monoid (zero) (add). - -(** Let's test the tactic *) -Goal forall x y z t, (x + y) + (z + 0 + t) = x + (y + z) + t. -Proof. - intros. - monoid 0 Z.add. - (* OK, the goal was reified for us, we can use normP now *) - apply: normP Z.add_assoc Z.add_0_l Z.add_0_r _. - reflexivity. -Qed. - -(** Now let's register in the Db the monoid for Z *) -Elpi Accumulate monoid.db lp:{{ - - is_monoid {{ Z }} - {{ 0 }} {{ Z.add }} - {{ Z.add_assoc }} {{ Z.add_0_l }} {{ Z.add_0_r }}. - -}}. - -(** Now let's improve the tactic. This time we don't expect the signature but - rather look it up in the Db. *) -Ltac my_compute := vm_compute. - -Elpi Accumulate monoid lp:{{ - -:before "error" -solve (goal _ _ {{ @eq lp:T lp:A lp:B }} _ [] as G) GL :- - is_monoid T Zero Op Assoc Ul Ur, - quote Zero Op A AstA L, - quote Zero Op B AstB L, - close L, - % This time we use higher level combinators, closer to the standard ltac1 ones - refine {{ @normP lp:T lp:Zero lp:Op lp:L lp:AstA lp:AstB lp:Assoc lp:Ul lp:Ur _ }} G [SubG], - coq.ltac.thenl [ - coq.ltac "my_compute", % https://github.com/coq/coq/issues/10769 - coq.ltac "reflexivity", - ] SubG GL. - -}}. -Elpi Typecheck. -Tactic Notation "monoid" := elpi monoid. - -(** Let's test it once more *) -Goal forall x y z t, (x + y) + (z + 0 + t) = x + (y + z) + t. -Proof. - intros. - monoid. - Show Proof. -Qed. - -Elpi Accumulate monoid.db lp:{{ - - is_monoid {{ Z }} - {{ 1 }} {{ Z.mul }} - {{ Z.mul_assoc }} {{ Z.mul_1_l }} {{ Z.mul_1_r }}. - -}}. - -Goal forall x y z t, (x * y) * (1 * (z + t)) = x * y * (z + t). -Proof. - intros. - monoid. -Qed. diff --git a/examples/example_reflexive_tactic.v b/examples/example_reflexive_tactic.v new file mode 120000 index 000000000..b83a8b52c --- /dev/null +++ b/examples/example_reflexive_tactic.v @@ -0,0 +1 @@ +../tests/example_reflexive_tactic.t/test.v \ No newline at end of file diff --git a/examples/tutorial_coq_elpi_HOAS.v b/examples/tutorial_coq_elpi_HOAS.v deleted file mode 100644 index 1c92d9462..000000000 --- a/examples/tutorial_coq_elpi_HOAS.v +++ /dev/null @@ -1,780 +0,0 @@ -(*| - -Tutorial on the HOAS for Coq terms -********************************** - -:author: Enrico Tassi - -.. include:: ../etc/tutorial_style.rst - -.. - Elpi is an extension language that comes as a library - to be embedded into host applications such as Coq. - - Elpi is a variant of λProlog enriched with constraints. - λProlog is a programming language designed to make it easy - to manipulate abstract syntax trees containing binders. - Elpi extends λProlog with programming constructs that are - designed to make it easy to manipulate abstract syntax trees - containing metavariables (also called unification variables, or - evars in the Coq jargon). - - This software, "coq-elpi", is a Coq plugin embedding Elpi and - exposing to the extension language Coq spefic data types (e.g. terms) - and API (e.g. to declare a new inductive type). - - In order to get proper syntax highlighting using VSCode please install the - "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in - Edit -> Preferences -> Colors. - - -This tutorial focuses on the integration of Elpi within Coq, in particular -it describes how Coq terms are exposed to Elpi programs and how Coq APIs can -be called. - -This tutorial assumes the reader is familiar with Elpi and HOAS; if it is not -the case, please take a look at the -`Elpi tutorial `_ -first. - -.. contents:: - -================ -HOAS for Gallina -================ - -|*) - -From elpi Require Import elpi. (* .none *) - -Elpi Command tutorial_HOAS. (* .none *) - -(*| - -The full syntax of Coq terms can be found in -`coq-builtin.elpi `_ -together with a detailed documentation of the encoding of contexts and the -APIs one can use to interact with Coq. This tutorial, and the two more -that focus on commands and tactics, are a gentle introduction to all that. - -We defer to later quotations and antiquotations: syntactic features that -let one write terms in Coq's native syntax. Here we focus on the abstract -syntax tree of Coq terms. - ------------------------ -Constructor :e:`global` ------------------------ - -Let's start with the :type:`gref` data type (for global rerence). - -.. code:: elpi - - type const constant -> gref. - type indt inductive -> gref. - type indc constructor -> gref. - -:type:`constant`, :type:`inductive` and :type:`constructor` are Coq specific -data types that are opaque to Elpi. Still the :type:`gref` data type lets you -see what these names point to (a constant, and inductive type or a -constructor). - -The :builtin:`coq.locate` API resolves a string to a :type:`gref`. - -|*) - -Elpi Query lp:{{ - - coq.locate "nat" GRnat, - coq.locate "S" GRs, - coq.locate "plus" GRplus - -}}. - -(*| - -The :e:`coq.env.*` family of APIs lets one access the -environment of well typed Coq terms that have a global name. - -|*) - -Definition x := 2. - -Elpi Query lp:{{ - - coq.locate "x" GR, - - % all global references have a type - coq.env.typeof GR Ty, - - % destruct GR to obtain its constant part C - GR = const C, - - % constants may have a body, do have a type - coq.env.const C (some Bo) TyC - -}}. - -(*| - -An expression like :e:`indt «nat»` is not a Coq term (or better a type) yet. - -The :constructor:`global` term constructor turns a :type:`gref` into an -actual :type:`term`. - -.. code:: elpi - - type global gref -> term. - ----------------------------------- -Constructors :e:`app` and :e:`fun` ----------------------------------- - -The :constructor:`app` term constructor takes a list of terms and builds -the (n-ary) application. The first term is the head, while the others -are the arguments. - -For example :e:`app [global (indc «S»), global (indc «O»)]` is -the representation of `1`. - -.. code:: elpi - - type app list term -> term. - -Let's move to binders! - -|*) - -Definition f := fun x : nat => x. - -Elpi Query lp:{{ - - coq.locate "f" (const C), - coq.env.const C (some Bo) _ - -}}. - -(*| - -The :constructor:`fun` constructor carries a pretty printing hint ```x```, -the type of the bound variable `nat` and a function describing the body: - -.. code:: elpi - - type fun name -> term -> (term -> term) -> term. - -.. note:: :type:`name` is just for pretty printing: in spite of carrying - a value in the Coq world, it has no content in Elpi (like the unit type) - - Elpi terms of type :type:`name` are just identifiers - written between ````` (backticks). - - .. coq:: - - Elpi Query lp:{{ - - fun `foo` T B = fun `bar` T B % names don't matter - - }}. - - API such as :builtin:`coq.name-suffix` lets one craft a family of - names starting from one, eg ``coq.name-suffix `H` 1 N`` sets :e:`N` - to ```H1```. - ------------------------------------- -Constructors :e:`fix` and :e:`match` ------------------------------------- - -The other binders :constructor:`prod` (Coq's `forall`, AKA `Π`) and :constructor:`let` are similar, -so let's rather focus on :constructor:`fix` here. - -|*) - -Elpi Query lp:{{ - - coq.locate "plus" (const C), - coq.env.const C (some Bo) _ - -}}. - -(*| - -The :constructor:`fix` constructor carries a pretty printing hint, -the number of the recursive argument (starting at :e:`0`), the type -of the recursive function and finally the body where the recursive -call is represented via a bound variable - -.. code:: elpi - - type fix name -> int -> term -> (term -> term) -> term. - -A :constructor:`match` constructor carries the term being inspected, -the return clause -and a list of branches. Each branch is a Coq function expecting in input -the arguments of the corresponding constructor. The order follows the -order of the constructors in the inductive type declaration. - -.. code:: elpi - - type match term -> term -> list term -> term. - -The return clause is represented as a Coq function expecting in input -the indexes of the inductive type, the inspected term and generating the -type of the branches. - -|*) - -Definition m (h : 0 = 1 ) P : P 0 -> P 1 := - match h as e in eq _ x return P 0 -> P x - with eq_refl => fun (p : P 0) => p end. - -Elpi Query lp:{{ - -coq.locate "m" (const C), -coq.env.const C (some (fun _ _ h\ fun _ _ p\ match _ (RT h p) _)) _, -coq.say "The return type of m is:" RT - -}}. - - -(*| - ---------------------- -Constructor :e:`sort` ---------------------- - -The last term constructor worth discussing is :constructor:`sort`. - -.. code:: elpi - - type sort universe -> term. - type prop universe. - type typ univ -> universe. - -The opaque type :type:`univ` is a universe level variable. Elpi holds a store of -constraints among these variables and provides APIs named :e:`coq.univ.*` to -impose constraints. - -|*) - -Elpi Query lp:{{ - - coq.sort.sup U U1, - coq.say U "<" U1, - % This constraint can't be allowed in the store! - not(coq.sort.leq U1 U) - -}}. - -(*| - -.. note:: the user is not expected to declare universe constraints by hand - - The type checking primitives update the store of constraints - automatically and put Coq universe variables in place of Elpi's unification - variables (:e:`U` and :e:`V` below). - -Let's play a bit more with universe constraints using the -:builtin:`coq.typecheck` API: - -|*) - -Elpi Query lp:{{ - - ID = (fun `x` (sort (typ U)) x\ x), - A = (sort (typ U)), % the same U as before - B = (sort (typ V)), - coq.say "(id b) is:" (app [ID, B]), - - % error, since U : U is not valid - coq.typecheck (app [ID, A]) T (error ErrMsg), - coq.say "(id a) is illtyped:" ErrMsg, - - % ok, since V : U is possible - coq.typecheck (app [ID, B]) T ok, - - % remark: U and V are now Coq's univ with constraints - coq.say "after typing (id b) is:" (app [ID, B]) ":" T, - coq.univ.print - -}}. - -(*| - -The :stdtype:`diagnostic` data type is used by :builtin:`coq.typecheck` to -tell if the term is well typed. The constructor :e:`ok` signals success, while -:e:`error` carries an error message. In case of success universe constraints -are added to the store. - -============================= -Quotations and Antiquotations -============================= - -Writing Gallina terms as we did so far is surely possible but very verbose -and unhandy. Elpi provides a system of quotations and antiquotations to -let one take advantage of the Coq parser to write terms. - -The antiquotation, from Coq to Elpi, is written `lp:{{ ... }}` and we have -been using it since the beginning of the tutorial. The quotation from -Elpi to Coq is written :e:`{{:coq ... }}` or also just :e:`{{ ... }}` since -the `:coq` is the default quotation (Coq has no default quotation, hence you always need -to write `lp:` there). - -|*) - -Elpi Query lp:{{ - - % the ":coq" flag is optional - coq.say {{:coq 1 + 2 }} "=" {{ 1 + 2 }} - -}}. - -(*| - -Of course quotations can nest. - -|*) - -Elpi Query lp:{{ - - coq.locate "S" S, - coq.say {{ 1 + lp:{{ app[global S, {{ 0 }} ] }} }} -% elpi.... coq.. elpi........... coq elpi coq - -}}. - -(*| - -One rule governs bound variables: - -.. important:: - - if a variable is bound in a language, Coq or Elpi, - then the variable is only visible in that language (not in the other one). - -The following example is horrible but proves this point. In real code -you are encouraged to pick appropriate names for your variables, avoiding -gratuitous (visual) clashes. - -|*) - -Elpi Query lp:{{ - - coq.say (fun `x` {{nat}} x\ {{ fun x : nat => x + lp:{{ x }} }}) -% e c c e -}}. - -(*| - -A commodity quotation without parentheses let's one quote identifiers -omitting the curly braces. -That is `lp:{{ ident }}` can be written just `lp:ident`. - -|*) - - -Elpi Query lp:{{ - - coq.say (fun `x` {{nat}} x\ {{ fun x : nat => x + lp:x }}) -% e c c e -}}. - -(*| - -It is quite frequent to put Coq variables in the scope of an Elpi -unification variable, and this can be done by simply writing -`lp:(X a b)` which is a shorhand for `lp:{{ X {{ a }} {{ b }} }}`. - -.. warning:: writing `lp:X a b` (without parentheses) would result in a - Coq application, not an Elpi one - -Let's play a bit with these shorthands: - -|*) - -Elpi Query lp:{{ - - X = (x\y\ {{ lp:y + lp:x }}), % x and y live in Elpi - - coq.say {{ fun a b : nat => lp:(X a b) }} % a and b live in Coq - -}}. - -(*| - -Another commodity quotation lets one access the coqlib -feature introduced in Coq 8.10. - -Coqlib gives you an indirection between your code and the actual name -of constants. - -|*) - -Register Coq.Init.Datatypes.nat as my.N. -Register Coq.Init.Logic.eq as my.eq. - -Elpi Query lp:{{ - - coq.say {{ fun a b : lib:my.N => lib:@my.eq lib:my.N a b }} - -}}. - -(*| - -.. note:: The (optional) `@` in `lib:@some.name` disables implicit arguments. - -The `{{:gref .. }}` quotation lets one build the gref data type, instead of the -term one. It supports `lib:` as well. - -|*) - -Elpi Query lp:{{ - - coq.say {{:gref nat }}, - coq.say {{:gref lib:my.N }}. - -}}. - -(*| - -The last thing to keep in mind when using quotations is that implicit -arguments are inserted (according to the `Arguments` setting in Coq) -but not synthesized automatically. - -It is the job of the type checker or elaborator to synthesize them. -We shall see more on this in the section on `holes`_. - -|*) - -Elpi Query lp:{{ - - T = (fun `ax` {{nat}} a\ {{ fun b : nat => lp:a = b }}), - coq.say "before:" T, - coq.typecheck T _ ok, - coq.say "after:" T - -}}. - -(*| - -=========== -The context -=========== - -The context of Elpi (the hypothetical program made of rules loaded -via :e:`=>`) is taken into account by the Coq APIs. In particular every time -a bound variable is crossed, the programmer *must* load in the context a -rule attaching to that variable a type. There are a few facilities to -do that, but let's first see what happens if one forgets it. - -|*) - -Fail Elpi Query lp:{{ - - T = {{ fun x : nat => x + 1 }}, - coq.typecheck T _ ok, - T = fun _ _ Bo, - pi x\ - coq.typecheck (Bo x) _ _ - -}}. (* .fails *) - -(*| - -This fatal error says that :e:`x` in :e:`(Bo x)` is unknown to Coq. -It is -a variable postulated in Elpi, but it's type, `nat`, was lost. There -is nothing wrong per se in using :e:`pi x\ ` as we did if we don't call Coq -APIs under it. But if we do, we have to record the type of :e:`x` somewhere. - -In some sense Elpi's way of traversing a binder is similar to a Zipper. -The context of Elpi must record the part of the Zipper context that is -relevant for binders. - -The two predicates :builtin:`decl` and :builtin:`def` are used -for that purpose: - -.. code:: elpi - - pred decl i:term, o:name, o:term. % Var Name Ty - pred def i:term, o:name, o:term, o:term. % Var Name Ty Bo - -where :e:`def` is used to cross a :e:`let`. - -|*) - -Elpi Query lp:{{ - - T = {{ fun x : nat => x + 1 }}, - coq.typecheck T _ ok, - T = fun N Ty Bo, - pi x\ - decl x N Ty => - coq.typecheck (Bo x) _ ok - -}}. - -(*| - -In order to ease this task, Coq-Elpi provides a few commodity macros such as -`@pi-decl`: - -.. code:: elpi - - macro @pi-decl N T F :- pi x\ decl x N T => F x. - -.. note:: the precedence of lambda abstraction :e:`x\ ` lets you write the - following code without parentheses for :e:`F`. - -|*) - -Elpi Query lp:{{ - - T = {{ fun x : nat => x + 1 }}, - coq.typecheck T _ ok, - T = fun N Ty Bo, - @pi-decl N Ty x\ - coq.typecheck (Bo x) _ ok - -}}. - -(*| - -.. tip:: :e:`@pi-decl N Ty x\ ` takes arguments in the same order of :constructor:`fun` and - :constructor:`prod`, while - :e:`@pi-def N Ty Bo x\ ` takes arguments in the same order of :constructor:`let`. - -.. _holes: - -========================== -Holes (implicit arguments) -========================== - -An "Evar" (Coq slang for existentially quantified meta variable) is -represented as a Elpi unification variable and a typing constraint. - -|*) - -Elpi Query lp:{{ - - T = {{ _ }}, - coq.say "raw T =" T, - coq.sigma.print, - coq.say "--------------------------------", - coq.typecheck T {{ nat }} ok, - coq.sigma.print - -}}. - -(*| - -Before the call to :builtin:`coq.typecheck`, :builtin:`coq.sigma.print` -prints nothing interesting, while after the call it also prints the following -syntactic constraint: - -.. mquote:: .s(Elpi).msg(suspended on X1) - :language: elpi - -which indicates that the hole :e:`X1` is linked to a Coq evar -and is expected to have type `nat`. - -Now the bijective mapping from Coq evars to Elpi's unification variables -is not empty anymore: - -.. mquote:: .s(Elpi).msg{Coq-Elpi mapping:*[?]X11 <-> X1*} - :language: text - -Note that Coq's evar identifiers are of the form `?X`, while the Elpi ones -have no leading `?`. The Coq Evar map says that `?X11` has type `nat`: - -.. mquote:: .s(Elpi).msg{EVARS:*[?]X11==[[] |- nat[]]*} - :language: text - -The intuition is that Coq's Evar map (AKA sigma or evd), which assigns -typing judgement to evars, is represented with Elpi constraints which carry -the same piece of info. - -Naked Elpi unification variables, when passed to Coq's API, are -automatically linked to a Coq evar. We postpone the explanation of the -difference "raw" and "elab" unification variables to the chapter about -tactics, here the second copy of :e:`X1` in the evar constraint plays -no role. - -Now, what about the typing context? - -|*) - -Elpi Query lp:{{ - - T = {{ fun x : nat => x + _ }}, - coq.say "raw T =" T, - T = fun N Ty Bo, - @pi-decl N Ty x\ - coq.typecheck (Bo x) {{ nat }} ok, - coq.sigma.print. - -}}. - -(*| - -In the value of raw :e:`T` we can see that the hole in `x + _`, which occurs under the -binder :e:`c0\ `, is represented by an Elpi unification variable :e:`X1 c0`, that -means that :e:`X1` sees :e:`c0` (:e:`c0` is in the scope of :e:`X1`). - -The constraint is this time a bit more complex. Let's dissect it: - -.. mquote:: .s(Elpi).msg(suspended on X1) - :language: elpi - -Here `{...}` is the set of names (not necessarily minimized) used in the -constraint, while `?-` separates the assumptions (the context) from the -conclusion (the suspended goal). - -The mapping between Coq and Elpi is: - -.. mquote:: .s(Elpi).msg{Coq-Elpi mapping:*[?]X13 <-> X1*} - :language: text - -where `?X13` can be found in Coq's sigma: - -.. mquote:: .s(Elpi).msg{EVARS:*[?]X13==[[]x |- nat[]]*} - :language: text - -As expected both Elpi's constraint and Coq's evar map record a context -with a variable :e:`x` (of type `nat`) which is in the scope of the hole. - -Unless one is writing a tactic, Elpi's constraints are just used to -represent the evar map. When a term is assigned to a variable -the corresponding constraint is dropped. When one is writing a tactic, -things are wired up so that assigning a term to an Elpi variable -representing an evar resumes a type checking goal to ensure the term has -the expected type. -We will explain this in detail in the tutorial about tactics. - ----------------------------- -Outside the pattern fragment ----------------------------- - -This encoding of evars is such that the programmer does not need to care -much about them: no need to carry around an assignment/typing map like the -Evar map, no need to declared new variables there, etc. The programmer -can freely call Coq API passing an Elpi term containing holes. - -There is one limitation, though. The rest of this tutorial describes it -and introduces a few APIs and options to deal with it. - -The limitation is that the automatic declaration and mapping -does not work in all situations. In particular it only works for Elpi -unification variables which are in the pattern fragment, which mean -that they are applied only to distinct names (bound variables). - -This is the case for all the `{{ _ }}` one writes inside quotations, for -example, but it is not hard to craft a term outside this fragment. -In particular we can use Elpi's substitution (function application) to -put an arbitrary term in place of a bound variable. - -|*) - -Fail Elpi Query lp:{{ - - T = {{ fun x : nat => x + _ }}, - % remark the hole sees x - T = fun N Ty Bo, - % 1 is the offending term we put in place of x - Bo1 = Bo {{ 1 }}, - % Bo1 is outside the pattern fragment - coq.say "Bo1 (not in pattern fragment) =" Bo1, - % boom - coq.typecheck Bo1 {{ nat }} ok. - -}}. (* .fails *) - -(*| - -This snippet fails hard, with the following message: - -.. mquote:: .s(Elpi).msg(Flexible term outside) - :language: elpi - -Indeed :e:`Bo1` contains a term outside the pattern fragment, -the second argument of `plus`, which is obtained by replacing -:e:`c0` with `{{ 1 }}` in :e:`X0 c0`. - -While programming Coq extensions in Elpi, it may happen that we want to -use a Coq term as a syntax tree (with holes) and we need to apply -substitutions to it but we don't really care about the scope of holes. -We would like these holes to stay `{{ _ }}` (a fresh hole which sees the -entire context of bound variables). In some sense, we would like `{{ _ }}` -to be a special dummy constant, to be turned into an actual hole on the -fly when needed. - -This use case is perfectly legitimate and is supported by all APIs taking -terms in input thanks to the :macro:`@holes!` option. - -|*) - -Elpi Query lp:{{ - - T = {{ fun x : nat => x + _ }}, - T = fun N Ty Bo, - Bo1 = Bo {{ 1 }}, - coq.say "Bo1 before =" Bo1, - % by loading this rule in the context, we set - % the option for the APIs called under it - @holes! => coq.typecheck Bo1 {{ nat }} ok, - coq.say "Bo1 after =" Bo1. - -}}. - -(*| - -Note that after the call to :builtin:`coq.typecheck`, :e:`X0` is assigned the -term :e:`_\ X1`, that means that the offending argument has been pruned -(discarded). - -.. note:: All APIs taking a term support the :macro:`@holes!` option. - -In addition to the :macro:`@holes!` option, there is a class of APIs which can -deal with terms outside the pattern fragment. These APIs take in input a term -*skeleton*. A skeleton is not modified in place, as :builtin:`coq.typecheck` -does with its first argument, but is rather elaborated to a term related to it. - -In some sense APIs taking a skeleton are more powerful, because they can -modify the structure of the term, eg. insert a coercions, but are less -precise, in the sense that the relation between the input and the output -terms is not straightforward (it's not unification). - -|*) - -Coercion nat2bool n := match n with O => false | _ => true end. -Open Scope bool_scope. - -Elpi Query lp:{{ - - T = {{ fun x : nat => x && _ }}, - T = fun N Ty Bo, - Bo1 = Bo {{ 1 }}, - coq.elaborate-skeleton Bo1 {{ bool }} Bo2 ok - -}}. - -(*| - -Here :e:`Bo2` is obtained by taking :e:`Bo1`, considering all -unification variables as holes and all `{{ Type }}` levels as fresh -(the are none in this example), and running Coq's elaborator on it. - -The result is a term with a similar structure (skeleton), but a coercion -is inserted to make :e:`x` fit as a boolean value, and a fresh hole :e:`X1` is -put in place of the term :e:`X0 (app [global (indc «S»), global (indc «O»)])` -which is left untouched. - -Skeletons and their APIs are described in more details in the tutorial -on commands. - -That is all for this tutorial. You can continue by reading the tutorial -about -`commands `_ -or the one about -`tactics `_. - -|*) diff --git a/examples/tutorial_coq_elpi_HOAS.v b/examples/tutorial_coq_elpi_HOAS.v new file mode 120000 index 000000000..2e25254c3 --- /dev/null +++ b/examples/tutorial_coq_elpi_HOAS.v @@ -0,0 +1 @@ +../tests/tutorial_coq_elpi_HOAS.t/test.v \ No newline at end of file diff --git a/examples/tutorial_coq_elpi_command.v b/examples/tutorial_coq_elpi_command.v deleted file mode 100644 index 42256a037..000000000 --- a/examples/tutorial_coq_elpi_command.v +++ /dev/null @@ -1,963 +0,0 @@ -(*| - -Tutorial on Coq commands -************************ - -:author: Enrico Tassi - -.. include:: ../etc/tutorial_style.rst - -.. - Elpi is an extension language that comes as a library - to be embedded into host applications such as Coq. - - Elpi is a variant of λProlog enriched with constraints. - λProlog is a programming language designed to make it easy - to manipulate abstract syntax trees containing binders. - Elpi extends λProlog with programming constructs that are - designed to make it easy to manipulate abstract syntax trees - containing metavariables (also called unification variables, or - evars in the Coq jargon). - - This software, "coq-elpi", is a Coq plugin embedding Elpi and - exposing to the extension language Coq spefic data types (e.g. terms) - and API (e.g. to declare a new inductive type). - - In order to get proper syntax highlighting using VSCode please install the - "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in - Edit -> Preferences -> Colors. - -This tutorial assumes the reader is familiar with Elpi and the HOAS -representation of Coq terms; if it is not the case, please take a look at -these other tutorials first: -`Elpi tutorial `_ -and -`Coq HOAS tutorial `_. - -.. contents:: - -================= -Defining commands -================= - -Let's create a simple command, called "hello", which prints :e:`"Hello"` -followed by the arguments we pass to it: - -|*) -From elpi Require Import elpi. - -Elpi Command hello. -Elpi Accumulate lp:{{ - - % main is, well, the entry point - main Arguments :- coq.say "Hello" Arguments. - -}}. -Elpi Typecheck. - -(*| - -The program declaration is made of 3 parts. - -The first one `Elpi Command hello.` sets the current program to hello. -Since it is declared as a `Command` some code is loaded automatically: - -* APIs (eg :builtin:`coq.say`) and data types (eg Coq :type:`term` s) are loaded from - `coq-builtin.elpi `_ -* some utilities, like :lib:`copy` or :libred:`whd1` are loaded from - `elpi-command-template.elpi `_ - - -The second one `Elpi Accumulate ...` loads some extra code. -The `Elpi Accumulate ...` family of commands lets one accumulate code -taken from: - -* verbatim text `Elpi Accumulate lp:{{ code }}` -* source files `Elpi Accumulate File path` -* data bases (Db) `Elpi Accumulate Db name` - -Accumulating code via inline text or file is equivalent, the AST of `code` -is stored in the .vo file (the external file does not need to be installed). -We postpone the description of data bases to a dedicated section. - -Once all the code is accumulated `Elpi Typecheck` verifies that the -code does not contain the most frequent kind of mistakes. This command -considers some mistakes minor and only warns about them. You can -pass `-w +elpi.typecheck` to `coqc` to turn these warnings into errors. - -We can now run our program! - -|*) - -Elpi hello "world!". - -(*| - -You should see the following output (hover the bubble next to the -code if you are reading this online): - -.. mquote:: .s(Elpi hello).msg(str world) - :language: text - -The string `"world!"` we passed to the command is received by the code -as :e:`(str "world!")`. - -.. note:: :builtin:`coq.say` won't print quotes around strings - -================= -Command arguments -================= - -Let's pass different kind of arguments to `hello`: - -|*) - -Elpi hello 46. -Elpi hello there. - -(*| - -This time we passed to the command a number and an identifier. -Identifiers are received as strings, and can contain dots, but no spaces. - -|*) - -Elpi hello my friend. -Elpi hello this.is.a.qualified.name. - -(*| - -Indeed the first invocation passes two arguments, of type string, while -the second a single one, again a string containing dots. - -There are a few more types of arguments a command can receive: - -* terms, delimited by `(` and `)` -* toplevel declarations, like `Inductive ..`, `Definition ..`, etc.. - which are introduced by their characterizing keyword. - -Let's try with a term. - -|*) - -Elpi hello (0 = 1). - -(*| - -Since Coq-Elpi 1.15, terms are received in elaborated form, meaning -that the elaborator of Coq is used to pre-process them. -In the example above the type argument to `eq` has -been synthesized to be `nat`. - -|*) - -Elpi hello Definition test := 0 = 1. -Elpi hello Record test := { f1 : nat; f2 : f1 = 1 }. - -(*| - -Global declarations are received in elaborated form as well. -In the case of `Definition test` the optional body (would be -:e:`none` for an `Axiom` declaration) is present -while the omitted type is inferred (to be `Prop`). - -In the case of the `Record` declaration remark that each field has a few -attributes, like being a coercions (the `:>` in Coq's syntax). Also note that -the type of the record (which was omitted) defaults to `Type`. -Finally note that the type of the second field -sees :e:`c0` (the value of the first field). - -See the :type:`argument` data type -for a detailed decription of all the arguments a command can receive. - ------------------------- -Processing raw arguments ------------------------- - -It is sometimes useful to receive arguments in raw format, -so that no elaboration has been performed. -This can be achieved by using the -`#[arguments(raw)]` attributed when the command is declared. - -Then, thre are two ways to process term arguments: -typechecking and elaboration. - -|*) - -#[arguments(raw)] Elpi Command check_arg. -Elpi Accumulate lp:{{ - - main [trm T] :- - std.assert-ok! (coq.typecheck T Ty) "argument illtyped", - coq.say "The type of" T "is" Ty. - -}}. -Elpi Typecheck. - -Elpi check_arg (1 = 0). -Fail Elpi check_arg (1 = true). (* .fails *) - -(*| - -The command `check_arg` receives a term :e:`T` and type checks it, then it -prints the term and its type. - -The :builtin:`coq.typecheck` API has 3 arguments: a term, its type and a -:stdtype:`diagnostic` which can either be :e:`ok` or :e:`(error Message)`. -The :stdlib:`assert-ok!` combinator checks if the diagnostic is :e:`ok`, -and if not it prints the error message and bails out. - -The first invocation succeeds while the second one fails and prints -the type checking error (given by Coq) following the string passed to -:e:`std.assert-ok!`. - -|*) - -Coercion bool2nat (b : bool) := if b then 1 else 0. -Fail Elpi check_arg (1 = true). (* .fails *) -Check (1 = true). - -(*| - -The command still fails even if we told Coq how to inject booleans values -into the natural numbers. Indeed the `Check` commands works. - -The call to :builtin:`coq.typecheck` modifies the term in place, it can assign -implicit arguments (like the type parameter of `eq`) but it cannot modify the -structure of the term. To do so, one has to use the -:builtin:`coq.elaborate-skeleton` API. - -|*) - -#[arguments(raw)] -Elpi Command elaborate_arg. -Elpi Accumulate lp:{{ - - main [trm T] :- - std.assert-ok! (coq.elaborate-skeleton T Ty T1) "illtyped arg", - coq.say "T=" T, - coq.say "T1=" T1, - coq.say "Ty=" Ty. - -}}. -Elpi Typecheck. - -Elpi elaborate_arg (1 = true). - -(*| - -Remark how :e:`T` is not touched by the call to this API, and how :e:`T1` -is a copy of :e:`T` where the hole after `eq` is synthesized and the value -`true` injected to `nat` by using `bool2nat`. - -It is also possible to manipulate term arguments before typechecking -them, but note that all the considerations on holes in the tutorial about -the HOAS representation of Coq terms apply here. An example of tool -taking advantage of this possibility is Hierarchy Builder: the declarations -it receives would not typecheck in the current context, but do once the -context is temporarily augmented with ad-hoc canonical structure instances. - -======== -Examples -======== - -------------------- -Synthesizing a term -------------------- - -Synthesizing a term typically involves reading an existing declaration -and writing a new one. The relevant APIs are in the `coq.env.*` namespace -and are named after the global refence they manipulate, eg :builtin:`coq.env.const` -for reading and :builtin:`coq.env.add-const` for writing. - -Here we implement a little command that given an inductive type name -generates a term of type `nat` whose value is the number of constructors -of the given inductive type. - -|*) - -Elpi Command constructors_num. - -Elpi Accumulate lp:{{ - -pred int->nat i:int, o:term. -int->nat 0 {{ 0 }}. -int->nat N {{ S lp:X }} :- M is N - 1, int->nat M X. - -main [str IndName, str Name] :- - std.assert! (coq.locate IndName (indt GR)) "not an inductive type", - coq.env.indt GR _ _ _ _ Kn _, % the names of the constructors - std.length Kn N, % count them - int->nat N Nnat, % turn the integer into a nat - coq.env.add-const Name Nnat _ _ _. % save it - -}}. -Elpi Typecheck. - -Elpi constructors_num bool nK_bool. -Print nK_bool. - -Elpi constructors_num False nK_False. -Print nK_False. - -Fail Elpi constructors_num plus nK_plus. (* .fails *) -Fail Elpi constructors_num not_there bla. (* .fails *) - -(*| - -The command starts by locating the first argument and asserting it points to -an inductive type. This line is idiomatic: :builtin:`coq.locate` aborts if -the string cannot be located, and if it relates it to a :e:`gref` which is not -:e:`indt` (for example :e:`const plus`) :stdlib:`assert!` aborts with the given -error message. - -:builtin:`coq.env.indt` lets one access all the details of an inductive type, -here we just use the list of constructors. -The twin API :builtin:`coq.env.indt-decl` lets -one access the declaration of the inductive in HOAS form, which might be -easier to manipulate in other situations, like the next example. - -Then the program crafts a natural number and declares a constant for it. - ------------------------- -Abstracting an inductive ------------------------- - -For the sake of introducing :lib:`copy`, the swiss army knife of λProlog, we -write a command which takes an inductive type declaration and builds a new -one abstracting the former one on a given term. The new inductive has a -parameter in place of the occurrences of that term. - -|*) - -Elpi Command abstract. - -Elpi Accumulate lp:{{ - - % a renaming function which adds a ' to an ident (a string) - pred prime i:id, o:id. - prime S S1 :- S1 is S ^ "'". - - main [str Ind, trm Param] :- - - % the term to be abstracted out, P of type PTy - std.assert-ok! - (coq.elaborate-skeleton Param PTy P) - "illtyped parameter", - - % fetch the old declaration - std.assert! (coq.locate Ind (indt I)) "not an inductive type", - coq.env.indt-decl I Decl, - - % let's start to craft the new declaration by putting a - % parameter A which has the type of P - NewDecl = parameter "A" explicit PTy Decl', - - % let's make a copy, capturing all occurrences of P with a - % (which stands for the parameter) - (pi a\ copy P a => copy-indt-decl Decl (Decl' a)), - - % to avoid name clashes, we rename the type and its constructors - % (we don't need to rename the parameters) - coq.rename-indt-decl (=) prime prime NewDecl DeclRenamed, - - % we type check the inductive declaration, since abstracting - % random terms may lead to illtyped declarations (type theory - % is hard) - std.assert-ok! - (coq.typecheck-indt-decl DeclRenamed) - "can't be abstracted", - - coq.env.add-indt DeclRenamed _. - -}}. -Elpi Typecheck. - -Inductive tree := leaf | node : tree -> option nat -> tree -> tree. - -Elpi abstract tree (option nat). -Print tree'. - -(*| - -As expected `tree'` has a parameter `A`. - -Now let's focus on :lib:`copy`. The standard -coq library (loaded by the command template) contains a definition of copy -for terms and declarations. - -An excerpt: - -.. code:: elpi - - copy X X :- name X. % checks X is a bound variable - copy (global _ as C) C. - copy (fun N T F) (fun N T1 F1) :- - copy T T1, pi x\ copy (F x) (F1 x). - copy (app L) (app L1) :- std.map L copy L1. - -:e:`copy` implements the identity: it builds, recursively, a copy of the first -term into the second argument. Unless one loads in the context a new rule, -which takes precedence over the identity ones. Here we load: - -.. code:: elpi - - copy P a - -which, at run time, looks like - -.. code:: elpi - - copy (app [global (indt «option»), global (indt «nat»)]) c0 - -and that rule masks the one for `app` when the sub-term being copied is -exactly `option nat`. The API :lib:`copy-indt-decl` copies an inductive -declaration and calls `copy` on all the terms it contains (e.g. the -type of the constructors). - -The :lib:`copy` predicate is very flexible, but sometimes one needs to collect -some data along the way. The sibling API :lib:`fold-map` lets one do that. - -An excerpt: - -.. code:: elpi - - fold-map (fun N T F) A (fun N T1 F1) A2 :- - fold-map T A T1 A1, pi x\ fold-map (F x) A1 (F1 x) A2. - -For example one can use :lib:`fold-map` to collect into a list all the occurrences -of inductive type constructors in a given term, then use the list to postulate -the right number of binders for them, and finally use :lib:`copy` to capture them. - - -==================================== -Using DBs to store data across calls -==================================== - -A Db can be created with the command: - -|*) - -Elpi Db name.db lp:{{ some code. }}. - -(*| - -and a Db can be later extended via `Elpi Accumulate`. -As a convention, we like Db names to end in a .db suffix. - -A Db is pretty much like a regular program but can be *shared* among -other programs and is accumulated *by name*. -Since is a Db is accumulated *when a program runs* the *current -contents of the Db are used*. -Moreover the Db can be extended by Elpi programs themselves -thanks to the API :builtin:`coq.elpi.accumulate`, enabling code to save a state -which is then visible at subsequent runs. - -The initial contents of a Db, `some code` in the example -above, is usually just the type declaration for the predicates part of the Db, -and maybe a few default rules. -Let's define a Db. - -|*) - -Elpi Db age.db lp:{{ - - % A typical Db is made of one main predicate - pred age o:string, o:int. - - % the Db is empty for now, we put a rule giving a - % descriptive error and we name that rule "age.fail". - :name "age.fail" - age Name _ :- coq.error "I don't know who" Name "is!". - -}}. - -(*| - -Elpi rules can be given a name via the :e:`:name` attribute. Named rules -serve as anchor-points for new rules when added to the Db. - -Let's define a `Command` that makes use of a Db. - -|*) - -Elpi Command age. -Elpi Accumulate Db age.db. (* we accumulate the Db *) -Elpi Accumulate lp:{{ - - main [str Name] :- - age Name A, - coq.say Name "is" A "years old". - -}}. -Elpi Typecheck. - -Fail Elpi age bob. (* .fails *) - -(*| - -Let's put some data in the Db. Given that the Db contains a catch-all rule, -we need the new ones to be put before it. - -|*) - -Elpi Accumulate age.db lp:{{ - - :before "age.fail" % we place this rule before the catch all - age "bob" 24. - -}}. - -Elpi age bob. - -(*| - -Extending data bases this way is fine, but requires the user of our command -to be familiar with Elpi's syntax, which is not very nice. Instead, -we can write a new program that uses the :builtin:`coq.elpi.accumulate` API -to extend the Db. - -|*) - -Elpi Command set_age. -Elpi Accumulate Db age.db. -Elpi Accumulate lp:{{ - main [str Name, int Age] :- - TheNewRule = age Name Age, - coq.elpi.accumulate _ "age.db" - (clause _ (before "age.fail") TheNewRule). - -}}. -Elpi Typecheck. - -Elpi set_age "alice" 21. -Elpi age "alice". - -(*| - -Additions to a Db are a Coq object, a bit like a Notation or a Type Class -instance: these object live inside a Coq module (or a Coq file) and become -active when that module is Imported. - -Deciding to which Coq module these -extra rules belong is important and :builtin:`coq.elpi.accumulate` provides -a few options to tune that. Here we passed :e:`_`, that uses the default -setting. See the :type:`scope` and :type:`clause` data types for more info. - -.. _inspecting: - ---------------- -Inspecting a Db ---------------- - -So far we did query a Db but sometimes one needs to inspect the whole -contents. - -|*) - -Elpi Command print_all_ages. -Elpi Accumulate Db age.db. -Elpi Accumulate lp:{{ - - :before "age.fail" - age _ _ :- !, fail. % softly - - main [] :- - std.findall (age _ _) Rules, - std.forall Rules print-rule. - - pred print-rule i:prop. - print-rule (age P N) :- coq.say P "is" N "years old". - -}}. -Elpi Typecheck. -Elpi print_all_ages. - -(*| - -The :stdlib:`std.findall` predicate gathers in a list all solutions to -a query, while :stdlib:`std.forall` iterates a predicate over a list. -It is important to notice that :builtin:`coq.error` is a fatal error which -aborts an Elpi program. Here we shadow the catch all clause with a regular -failure so that :stdlib:`std.findall` can complete to list all the results. - -=================== -Polishing a command -=================== - -The details do make the difference, some times. - ----------- -Attributes ----------- - -Elpi programs can be prefixed with attributes, like `#[local]`. -Attributes are not passed as arguments but rather as a rule in the context, -a bit like the option :e:`@holes!` we have seen before. - -|*) - -Elpi Command attr. -Elpi Accumulate lp:{{ - - main _ :- - attributes A, % we fetch the list of attributes from the context - coq.say A. - -}}. - -#[this, more(stuff="33")] Elpi attr. - -(*| - -The first attribute, :e:`elpi.loc` is always present and corresponds to the -location in the source file of the command. Then we find an attribute for -:e:`"this"` holding the emptry string and an attribute for :e:`"more.stuff"` holding -the string :e:`"33"`. - -Attributes are usually validated (parsed) and turned into regular options -using :lib-common:`coq.parse-attributes` and a description of their types using -the :libtype-common:`attribute-type` data type: - -|*) - -Elpi Command parse_attr. -Elpi Accumulate lp:{{ - - pred some-code. - some-code :- - get-option "more.stuff" N, get-option "this" B, coq.say N B. - - main _ :- - attributes A, - coq.parse-attributes A [ - att "this" bool, - att "more.stuff" int, - ] Opts, - coq.say "options=" Opts, - Opts => some-code. - -}}. - -#[this, more(stuff="33")] Elpi parse_attr. -Fail #[unknown] Elpi parse_attr. (* .fails *) - -(*| - -Note that :e:`get-option` links a string with a datum of type :e:`any`, which means -no type checking is performed on it. It is recommended to wrap calls to -get-option into other predicates typed in a more precise way. Eg: - -.. code:: elpi - - pred get-my-option o:int. - get-my-option I :- get-option "my-option-name" I. - ------------------------------ -Extending the command grammar ------------------------------ - -Elpi programs can be exported as regular Coq commands, so that the -final user does not need to type `Elpi` to invoke them. - -|*) - -Elpi Command Say. -Elpi Accumulate lp:{{ main [str S] :- coq.say S. }}. -Elpi Typecheck. - -Elpi Export Say. (* extend the Coq command grammar *) - -Say "That is all folks!". - -(*| - -Not yet... - -Coq offers no equivalent of `Tactic Notation` for commands. -Still Elpi commands accept any symbol or keyword as strings. -It is up to the programmer to catch and report parse errors. - -|*) - -Elpi Command Go. -Elpi Accumulate lp:{{ - main [str Src, str "=>", str Tgt, str "/", str F] :- !, - coq.say "going from" Src "to" Tgt "via" F. - main _ :- - coq.error "Parse error! Use: go => / ". -}}. -Elpi Typecheck. -Elpi Export Go. - -Go source => target / plane. -Fail Go nowhere. (* .fails *) - -(*| - ----------------- -Reporting errors ----------------- - -Last, (good) Elpi programs should fail reporting intellegible error messages, -as the previous one. - -|*) - -Elpi Command bad. -Elpi Accumulate lp:{{ main []. }}. -Elpi Typecheck. -Elpi Export bad. - -Fail bad 1. (* .fails *) - -(*| - -If they just fail, they produce the following generic -error: - -.. mquote:: .s(bad 1).msg(inconvenience) - :language: text - -You should use the :builtin:`coq.error` API or the :stdlib:`assert!` one -to abort a program. There is a dedicated :builtin:`coq.ltac.fail` API to abort -tactics. - -Warnings can be reported using the :builtin:`coq.warning` which lets you -pick a name and category. In turn these can be used to disable or make fatal -your warnings (as any other Coq warning). - -===================== -Parsing and Execution -===================== - -Since version 8.18 Coq has separate parsing and execution phases, -respectively called synterp and interp. - -Since Coq has an extensible grammar the parsing phase is not entirely -performed by the parser: after parsing one sentence Coq evaluates its -synterp action. The synterp actions of a command like `Import A.` are -the subset of its effect which affect parsing, like enabling a notation. -Later, during the execution phase, Coq evaluates its -interp actions, which include effects like putting lemma in scope or -enabling type class instances etc. Synterp actions are quick, if only because -they don't really manipulate Coq terms, hence no type checking and the like. - -Being able to parse an entire document quickly -is important for developing reactive -user interfaces, but requires some extra work when defining new commands, -in particular to identify their synterp. -Each command defined with Coq-Elpi is split into two programs, -one running during the parsing phase and the other one during the execution -phase. Each API that affects the parser, i.e. APIs dealing with modules -and sections like begin/end-module or import/export, is available to both the -synterp and the interp program under the same name, but its actual effect is -limited to what concerns the current phase. Hence all these APIs have to be -called at *both* synterp and interp time and *in the same order*. - -At synterp time the data types and the APIs are restricted, in particular -Coq terms are not available. When a command argument contains a term, that -term is replaced by `_` at synterp time. In the following example, the synterp -program can see the name of the definition and the fact that a body was given, -but not the value of the body. - -|*) - - -Elpi Command hello_synterp. -#[synterp] Elpi Accumulate lp:{{ - main [const-decl Name Body _] :- coq.say "synterp" Name ":=" Body. -}}. -Elpi Accumulate lp:{{ - main [const-decl Name Body _] :- coq.say "interp" Name ":=" Body. -}}. -Elpi Typecheck. - -Elpi hello_synterp Definition x := 2. - -(*| - -This simple command has no real synterp action, one could safely remove -the synterp code. On the contrary when a command performs actions affecting -the parser then it must come equipped with some synterp code performing -the corresponding actions. - -|*) - -Module Notations. -Notation "x '>>' y" := (x > y) (at level 40). -Definition w := 3. -End Notations. - -Elpi Command import_module. -Elpi Accumulate lp:{{ - main [str M] :- - coq.locate-module M MP, - coq.env.import-module MP, - coq.locate "w" (const GR), - coq.env.const GR (some {{ 3 }}) _. -}}. -Elpi Typecheck. - -Fail Elpi import_module Notations. (* .fails .in .messages *) - -(* oops, we forgot to declare code for the synterp phase. Here it is *) -#[synterp] Elpi Accumulate lp:{{ - main [str M] :- - coq.locate-module M MP, - coq.env.import-module MP. -}}. -Elpi Typecheck. - -Elpi import_module Notations. - -(*| - -Elpi reports a descriptive error message if actions affecting the parser are -not declared in the synterp code of the command. - -.. mquote:: .s(Elpi import_module Notations).msg{*Interp*actions*must*match*synterp*actions*} - :language: text - -Thanks to the synterp code, Coq can parse the document without even looking -at the interp code. - -Sometimes it is necessary to pass data from the synterp code to the interp one. -Passing data can be done in two ways. the former is by using the :e:`main-synterp` -and :e:`main-interp` entry points. - -.. code:: elpi - - pred main-synterp i:list argument, o:any. - pred main-interp i:list argument, i:any. - -Unlike :e:`main` the former outputs a datum while the latter receives it -in input. In the following command we create a (empty) module with a random -name. Even if the name is random, the two phases need to agree on it, hence -we pass the name from one to the other. - -|*) - -Elpi Command mk_random_module. -#[synterp] Elpi Accumulate lp:{{ - main-synterp [] M :- - random.self_init, - random.int 99 N, - M is "Module" ^ {std.any->string N}, - coq.env.begin-module M none, - coq.env.end-module _. -}}. -Elpi Accumulate lp:{{ - main-interp [] M :- - coq.env.begin-module M none, - coq.env.end-module MP, - coq.say "The module is" MP. -}}. -Elpi Typecheck. - -Elpi mk_random_module. - -(*| - -If the only data to be passed to the interp phase is the list of -synterp actions, then a few APIs can come in handy. -The synterp phase has access to the API :builtin-synterp:`coq.synterp-actions` -that lists the actions performed so far. The interp phase can use -:lib:`coq.replay-synterp-action` and :builtin:`coq.next-synterp-action` to -replay an action or peek the next one to be performed. - -An excerpt of the :type:`synterp-action`. - -.. code:: elpi - - % Action executed during the parsing phase (aka synterp) - kind synterp-action type. - type begin-module id -> synterp-action. - type end-module modpath -> synterp-action. - -The following command creates a stack of modules and puts in there -the given definition. The synterp phase saves the actions when the top of the -stack is reached, and passes them to the interp phase that replays them before -putting a definition inside. Finally the interp phase replays all the missing -actions. - -|*) - -Elpi Command put_inside. -#[synterp] Elpi Accumulate lp:{{ - main-synterp [int N, A] ActionsUpToNow :- N > 0, M is N - 1, - coq.env.begin-module "Box" none, - main-synterp [int M, A] ActionsUpToNow, - coq.env.end-module _. - main-synterp [int 0, _] ActionsUpToNow :- - coq.synterp-actions ActionsUpToNow. -}}. -Elpi Accumulate lp:{{ - main-interp [int _, const-decl Name (some BO) _] Before :- - std.forall Before coq.replay-synterp-action, - coq.env.add-const Name BO _ _ _, - replay-missing. - pred replay-missing. - replay-missing :- - coq.replay-synterp-action {coq.next-synterp-action}, - replay-missing. - replay-missing. -}}. - -Elpi Typecheck. - -Elpi put_inside 4 Definition foo (n : nat) := n + 2. - -Print Box.Box.Box.Box.foo. - -(*| - -This last example delegates to the synterp phase the creation of an arbitrary -complex module structure, a structure the interp phase does not need to be aware -of. The data passed to the interp phase is sufficient to replicate it without -too much effort. - -Finally, as regular commands, data bases can be used to store a state which -is available at subsequent calls. Data bases used in the two phases live -in different name spaces, and are only available to the corresponding phase. -The `#[synterp]` attribute tells `Elpi Db` to create a data base for the -synterp phase. Here a simple command saving a state in the synterp phase. - -|*) - -#[synterp] Elpi Db counter.db lp:{{ pred tick. }}. - -Elpi Command mk_next_module. -#[synterp] Elpi Accumulate Db counter.db. -#[synterp] Elpi Accumulate lp:{{ - main [] :- - std.findall tick L, - std.length L N, - M is "NextModule" ^ {std.any->string N}, - coq.env.begin-module M none, - coq.env.end-module _, - coq.elpi.accumulate _ "counter.db" (clause _ _ tick). -}}. -Elpi Accumulate lp:{{ - main [] :- replay-missing. - pred replay-missing. - replay-missing :- - coq.replay-synterp-action {coq.next-synterp-action}, - replay-missing. - replay-missing. -}}. -Elpi Typecheck. - -Elpi mk_next_module. -Elpi mk_next_module. -Elpi mk_next_module. - -Print Module NextModule2. - -(*| - -This is really the end, unless you want to learn more about writing -`tactics `_ -in Elpi, in that case look at that tutorial ;-) - -|*) diff --git a/examples/tutorial_coq_elpi_command.v b/examples/tutorial_coq_elpi_command.v new file mode 120000 index 000000000..b8d0b2ee6 --- /dev/null +++ b/examples/tutorial_coq_elpi_command.v @@ -0,0 +1 @@ +../tests/tutorial_coq_elpi_command.t/test.v \ No newline at end of file diff --git a/examples/tutorial_coq_elpi_tactic.v b/examples/tutorial_coq_elpi_tactic.v deleted file mode 100644 index ec1e31767..000000000 --- a/examples/tutorial_coq_elpi_tactic.v +++ /dev/null @@ -1,1056 +0,0 @@ -(*| - -Tutorial on Coq tactics -*********************** - -:author: Enrico Tassi - -.. include:: ../etc/tutorial_style.rst - -.. - Elpi is an extension language that comes as a library - to be embedded into host applications such as Coq. - - Elpi is a variant of λProlog enriched with constraints. - λProlog is a programming language designed to make it easy - to manipulate abstract syntax trees containing binders. - Elpi extends λProlog with programming constructs that are - designed to make it easy to manipulate abstract syntax trees - containing metavariables (also called unification variables, or - evars in the Coq jargon). - - This software, "coq-elpi", is a Coq plugin embedding Elpi and - exposing to the extension language Coq spefic data types (e.g. terms) - and API (e.g. to declare a new inductive type). - - In order to get proper syntax highlighting using VSCode please install the - "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in - Edit -> Preferences -> Colors. - - -This tutorial focuses on the implementation of Coq tactics. - -This tutorial assumes the reader is familiar with Elpi and the HOAS -representation of Coq terms; if it is not the case, please take a look at -these other tutorials first: -`Elpi tutorial `_ -and `Coq HOAS tutorial `_. - -.. contents:: - -================ -Defining tactics -================ - -In Coq a proof is just a term, and an incomplete proof is just a term -with holes standing for the open goals. - -When a proof starts there is just one hole (one goal) and its type -is the statement one wants to prove. Then proof construction makes -progress by instantiation: a term possibly containing holes is -grafted to the hole corresponding to the current goal. What a tactic -does behind the scenes is to synthesize this partial term. - -Let's define a simple tactic that prints the current goal. - -|*) - -From elpi Require Import elpi. - -Elpi Tactic show. -Elpi Accumulate lp:{{ - - solve (goal Ctx _Trigger Type Proof _) _ :- - coq.say "Goal:" Ctx "|-" Proof ":" Type. - -}}. -Elpi Typecheck. - -(*| - -The tactic declaration is made of 3 parts. - -The first one `Elpi Tactic show.` sets the current program to `show`. -Since it is declared as a `Tactic` some code is loaded automatically: - -* APIs (eg :builtin:`coq.say`) and data types (eg Coq :type:`term` s) are loaded from - `coq-builtin.elpi `_ -* some utilities, like :lib:`copy` or :libred:`whd1` are loaded from - `elpi-command-template.elpi `_ - - -The second one `Elpi Accumulate ...` loads some extra code. -The `Elpi Accumulate ...` family of commands lets one accumulate code -taken from: - -* verbatim text `Elpi Accumulate lp:{{ code }}` -* source files `Elpi Accumulate File path` -* data bases (Db) `Elpi Accumulate Db name` - -Accumulating code via inline text or file is equivalent, the AST of `code` -is stored in the .vo file (the external file does not need to be installed). -We invite the reader to look up the description of data bases in the tutorial -about commands. - -Once all the code is accumulated `Elpi Typecheck` verifies that the -code does not contain the most frequent kind of mistakes. This command -considers some mistakes minor and only warns about them. You can -pass `-w +elpi.typecheck` to `coqc` to turn these warnings into errors. - -The entry point for tactics is called :builtin:`solve` which maps a :type:`goal` -into a list of :type:`sealed-goal` (representing subgoals). - -Tactics written in Elpi can be invoked by prefixing its name with `elpi`. - -|*) - -Lemma tutorial x y : x + 1 = y. -elpi show. (* .in .messages *) -Abort. - -(*| - -In the Elpi code up there :e:`Proof` is the hole for the current goal, -:e:`Type` the statement to be proved and :e:`Ctx` the proof context (the list of -hypotheses). Since we don't assign :e:`Proof` the tactic makes no progess. -Elpi prints somethinglike this: - -.. mquote:: .s(elpi).msg{Goal:*X0 c0 c1*} - :language: text - -The first line is the proof context: -proof variables are bound Elpi variables (here :e:`c0` and :e:`c1`), the context -is a list of predicates holding on them (their type in Coq). For example: - -.. code:: - - decl c0 `x` (global (indt «nat»)) - -asserts that :e:`c0` (pretty printed as `x`) has type `nat`. - -Then we see that the value of :e:`Proof` is :e:`X0 c0 c1`. This means that the -proof of the current goal is represented by Elpi's variable :e:`X0` and that -the variable has :e:`c0` and :e:`c1` in scope (the proof term can use them). - -Finally we see the type of the goal `x + 1 = y`. - -The :e:`_Trigger` component, which we did not print, is a variable that, when -assigned, trigger the elaboration of its value against the type of the goal -and obtains a value for :e:`Proof` this way. - -Keeping in mind that the :builtin:`solve` predicate relates one goal to a list of -subgoals, we implement our first tactic which blindly tries to solve the goal. - -|*) - -Elpi Tactic blind. -Elpi Accumulate lp:{{ - solve (goal _ Trigger _ _ _) [] :- Trigger = {{0}}. - solve (goal _ Trigger _ _ _) [] :- Trigger = {{I}}. -}}. -Elpi Typecheck. - -Lemma test_blind : True * nat. -Proof. (* .in *) -split. -- elpi blind. -- elpi blind. -Show Proof. (* .in .messages *) -Qed. - -(*| - -Since the assignment of a term to :e:`Trigger` triggers its elaboration against -the expected type (the goal statement), assigning the wrong proof term -results in a failure which in turn results in the other rule being tried. - -For now, this is all about the low level mechanics of tactics which is -developed further in the section `The-proof-engine`_. - -We now focus on how to better integrate tactics written in Elpi with Ltac. - ---------------------- -Integration with Ltac ---------------------- - -For a simple tactic like `blind` the list of subgoals is easy to write, since -it is empty, but in general one should collect all the holes in -the value of :e:`Proof` (the checked proof term) and build goals out of them. - -There is a family of APIs named after :libtac:`refine`, the mother of all -tactics, in -`elpi-ltac.elpi `_ -which does this job for you. - -Usually a tactic builds a (possibly partial) term and calls -:libtac:`refine` on it. - -Let's rewrite the `blind` tactic using this schema. - -|*) - - -Elpi Tactic blind2. -Elpi Accumulate lp:{{ - solve G GL :- refine {{0}} G GL. - solve G GL :- refine {{I}} G GL. -}}. -Elpi Typecheck. - -Lemma test_blind2 : True * nat. -Proof. (* .in *) -split. -- elpi blind2. -- elpi blind2. -Qed. - -(*| - -This schema works even if the term is partial, that is if it contains holes -corresponding to missing sub proofs. - -Let's write a tactic which opens a few subgoals, for example -let's implement the `split` tactic. - -.. important:: - - Elpi's equality (that is, unification) on Coq terms corresponds to - alpha equivalence, we can use that to make our tactic less blind. - -The head of a rule for the solve predicate is *matched* against the -goal. This operation cannot assign unification variables in the goal, only -variables in the rule's head. -As a consequence the following rule for `solve` is only used when -the statement features an explicit conjunction. - -|*) - -About conj. (* remak the implicit arguments *) - -Elpi Tactic split. -Elpi Accumulate lp:{{ - solve (goal _ _ {{ _ /\ _ }} _ _ as G) GL :- !, - % conj has 4 arguments, but two are implicits - % (_ are added for them and are inferred from the goal) - refine {{ conj _ _ }} G GL. - - solve _ _ :- - % This signals a failure in the Ltac model. A failure - % in Elpi, that is no more cluases to try, is a fatal - % error that cannot be catch by Ltac combinators like repeat. - coq.ltac.fail _ "not a conjunction". -}}. -Elpi Typecheck. - -Lemma test_split : exists t : Prop, True /\ True /\ t. -Proof. (* .in *) -eexists. -repeat elpi split. (* The failure is catched by Ltac's repeat *) -(* Remark that the last goal is left untouched, since - it did not match the pattern {{ _ /\ _ }}. *) -all: elpi blind. -Show Proof. (* .in .messages *) -Qed. - -(*| - -The tactic `split` succeeds twice, stopping on the two identical goals `True` and -the one which is an evar of type `Prop`. - -We then invoke `blind` on all goals. In the third case the type checking -constraint triggered by assigning `{{0}}` to `Trigger` fails because -its type `nat` is not of sort `Prop`, so it backtracks and picks `{{I}}`. - -Another common way to build an Elpi tactic is to synthesize a term and -then call some Ltac piece of code finishing the work. - -The API :libtac:`coq.ltac.call` invokes some Ltac piece -of code passing to it the desired -arguments. Then it builds the list of subgoals. - -Here we pass an integer, which in turn is passed to `fail`, and a term, -which is turn is passed to `apply`. - -|*) - -Ltac helper_split2 n t := fail n || apply t. - -Elpi Tactic split2. -Elpi Accumulate lp:{{ - solve (goal _ _ {{ _ /\ _ }} _ _ as G) GL :- - coq.ltac.call "helper_split2" [int 0, trm {{ conj }}] G GL. - solve _ _ :- - coq.ltac.fail _ "not a conjunction". -}}. -Elpi Typecheck. - -Lemma test_split2 : exists t : Prop, True /\ True /\ t. -Proof. (* .in *) -eexists. -repeat elpi split2. -all: elpi blind. -Qed. - -(*| - -============================= -Arguments and Tactic Notation -============================= - -Elpi tactics can receive arguments. Arguments are received as a list, which -is the last argument of the goal constructor. This suggests that arguments -are attached to the current goal being observed, but we will dive into -this detail later on. - -|*) - -Elpi Tactic print_args. -Elpi Accumulate lp:{{ - solve (goal _ _ _ _ Args) _ :- coq.say Args. -}}. -Elpi Typecheck. - -Lemma test_print_args : True. (* .in *) -elpi print_args 1 x "a b" (1 = 0). (* .in .messages *) -Abort. - -(*| - -The convention is that numbers like `1` are passed as :e:`int 1`, -identifiers or strings are passed as :e:`str "arg"` and terms -have to be put between parentheses. - -.. important:: terms are received in raw format, eg before elaboration - - Indeed the type argument to `eq` is a variable. - One can use APIs like :builtin:`coq.elaborate-skeleton` to infer holes like - :e:`X0`. - -See the :type:`argument` data type -for a detailed decription of all the arguments a tactic can receive. - -Now let's write a tactic which behaves pretty much like the :libtac:`refine` -one from Coq, but prints what it does using the API :builtin:`coq.term->string`. - -|*) - -Elpi Tactic refine. -Elpi Accumulate lp:{{ - solve (goal _ _ Ty _ [trm S] as G) GL :- - % check S elaborates to T of type Ty (the goal) - coq.elaborate-skeleton S Ty T ok, - - coq.say "Using" {coq.term->string T} - "of type" {coq.term->string Ty}, - - % since T is already checked, we don't check it again - refine.no_check T G GL. - - solve (goal _ _ _ _ [trm S]) _ :- - Msg is {coq.term->string S} ^ " does not fit", - coq.ltac.fail _ Msg. -}}. -Elpi Typecheck. - -Lemma test_refine (P Q : Prop) (H : P -> Q) : Q. -Proof. (* .in *) -Fail elpi refine (H). (* .fails *) -elpi refine (H _). -Abort. - -(*| - --------------------------------- -Ltac arguments to Elpi arguments --------------------------------- - -It is customary to use the Tactic Notation command to attach a nicer syntax -to Elpi tactics. - -In particular `elpi tacname` accepts as arguments the following `bridges -for Ltac values `_ : - -* `ltac_string:(v)` (for `v` of type `string` or `ident`) -* `ltac_int:(v)` (for `v` of type `int` or `integer`) -* `ltac_term:(v)` (for `v` of type `constr` or `open_constr` or `uconstr` or `hyp`) -* `ltac_(string|int|term)_list:(v)` (for `v` of type `list` of ...) - -Note that the Ltac type associates some semantics to the action of passing -the arguments. For example `hyp` will accept an identifier only if it is -an hypotheses of the context. While `uconstr` does not type check the term, -which is the recommended way to pass terms to an Elpi tactic (since it is -likely to be typed anyway by the Elpi tactic). - -|*) - -Tactic Notation "use" uconstr(t) := - elpi refine ltac_term:(t). - -Tactic Notation "use" hyp(t) := - elpi refine ltac_term:(t). - -Lemma test_use (P Q : Prop) (H : P -> Q) (p : P) : Q. -Proof. (* .in *) -use (H _). -Fail use q. (* .fails .in .messages *) -use p. -Qed. - -Tactic Notation "print" uconstr_list_sep(l, ",") := - elpi print_args ltac_term_list:(l). - -Lemma test_print (P Q : Prop) (H : P -> Q) (p : P) : Q. -print P, p, (H p). (* .in .messages *) -Abort. - -(*| - -======== -Failure -======== - -The :builtin:`coq.error` aborts the execution of both -Elpi and any enclosing LTac context. This failure cannot be catched -by LTac. - -On the contrary the :builtin:`coq.ltac.fail` builtin can be used to -abort the execution of Elpi code in such a way that LTac can catch it. -This API takes an integer akin to LTac's fail depth together with -the error message to be displayed to the user. - -Library functions of the `assert!` family call, by default, :builtin:`coq.error`. -The flag `@ltacfail! N` can be set to alter this behavior and turn erros into -calls to `coq.ltac.fail N`. - -|*) - -Elpi Tactic abort. -Elpi Accumulate lp:{{ - solve _ _ :- coq.error "uncatchable". -}}. - -Goal True. -Fail elpi abort || idtac. -Abort. - -Elpi Tactic fail. -Elpi Accumulate lp:{{ - solve (goal _ _ _ _ [int N]) _ :- coq.ltac.fail N "catchable". -}}. - -Goal True. -elpi fail 0 || idtac. -Fail elpi fail 1 || idtac. -Abort. - - -(*| - -======== -Examples -======== - -------------------------------- -Let's code `assumption` in Elpi -------------------------------- - -`assumption` is a very simple tactic: we look up in the proof -context for an hypothesis which unifies with the goal. -Recall that `Ctx` is made of :builtin:`decl` and :builtin:`def` -(here, for simplicity, we ignore the latter case). - -|*) - -Elpi Tactic assumption. -Elpi Accumulate lp:{{ - solve (goal Ctx _ Ty _ _ as G) GL :- - % H is the name for hyp, Ty is the goal - std.mem Ctx (decl H _ Ty), - refine H G GL. - solve _ _ :- - coq.ltac.fail _ "no such hypothesis". -}}. -Elpi Typecheck. - -Lemma test_assumption (P Q : Prop) (p : P) (q : Q) : P /\ id Q. -Proof. (* .in *) -split. -elpi assumption. -Fail elpi assumption. (* .fails *) -Abort. - -(*| - -As we hinted before, Elpi's equality is alpha equivalence. In the second -goal the assumption has type `Q` but the goal has type `id Q` which is -convertible (unifiable, for Coq's unification) to `Q`. - -Let's improve our tactic looking for an assumption which is unifiable with -the goal, an not just alpha convertible. The :builtin:`coq.unify-leq` -calls Coq's unification for types (on which cumulativity applies, hence the -`-leq` suffix). The :stdlib:`std.mem` utility, thanks to backtracking, -eventually finds an hypothesis that satisfies the following predicate -(ie unifies with the goal). - -|*) - -Elpi Tactic assumption2. -Elpi Accumulate lp:{{ - solve (goal Ctx _ Ty _ _ as G) GL :- - % std.mem is backtracking (std.mem! would stop at the first hit) - std.mem Ctx (decl H _ Ty'), coq.unify-leq Ty' Ty ok, - refine H G GL. - solve _ _ :- - coq.ltac.fail _ "no such hypothesis". -}}. -Elpi Typecheck. - -Lemma test_assumption2 (P Q : Prop) (p : P) (q : Q) : P /\ id Q. -Proof. (* .in *) -split. -all: elpi assumption2. -Qed. - -(*| - -:libtac:`refine` does unify the type of goal with the type of the term, -hence we can simplify the code further. We obtain a -tactic very similar to our initial `blind` tactic, which picks -candidates from the context rather than from the program itself. - -|*) - -Elpi Tactic assumption3. -Elpi Accumulate lp:{{ - solve (goal Ctx _ _ _ _ as G) GL :- - std.mem Ctx (decl H _ _), - refine H G GL. - solve _ _ :- - coq.ltac.fail _ "no such hypothesis". -}}. -Elpi Typecheck. - -Lemma test_assumption3 (P Q : Prop) (p : P) (q : Q) : P /\ id Q. -Proof. (* .in *) -split. -all: elpi assumption3. -Qed. - -(*| - ------------------------- -Let's code `set` in Elpi ------------------------- - -The `set` tactic takes a term, possibly with holes, and -makes a let-in out of it. - -It gives us the occasion to explain the :lib:`copy` utility. - -|*) - -Elpi Tactic find. -Elpi Accumulate lp:{{ - -solve (goal _ _ T _ [trm X]) _ :- - pi x\ - copy X x => copy T (Tabs x), - if (occurs x (Tabs x)) - (coq.say "found" {coq.term->string X}) - (coq.ltac.fail _ "not found"). -}}. -Elpi Typecheck. - -Lemma test_find (P Q : Prop) : (P /\ P) \/ (P /\ Q). -Proof. (* .in *) -elpi find (P). -Fail elpi find (Q /\ _). (* .fails .in .messages *) -elpi find (P /\ _). -Abort. - -(*| - -This first approximation only prints the term it found, or better the first -intance of the given term. - -Now lets focus on :lib:`copy`. An excerpt: - -.. code:: elpi - - copy X X :- name X. % checks X is a bound variable - copy (global _ as C) C. - copy (fun N T F) (fun N T1 F1). - copy T T1, pi x\ copy (F x) (F1 x). - copy (app L) (app L1) :- !, std.map L copy L1. - -Copy implements the identity: it builds, recursively, a copy of the first -term into the second argument. Unless one loads in the context a new rule, -which takes precedence over the identity ones. Here we load: - -.. code:: elpi - - copy X x - -which, at run time, looks like - -.. code:: elpi - - copy (app [global (indt «andn»), sort prop, sort prop, c0, X0 c0 c1]) c2 - -and that rule masks the one for :constructor:`app` when the -sub-term being copied matches `(P /\ _)`. The first time this rule -is used :e:`X0` is assigned, making the rule represent the term `(P /\ P)`. - -Now let's refine the tactic to build a let-in, and complain if the -desired name is already taken. - -|*) - -Elpi Tactic set. -Elpi Accumulate lp:{{ - -solve (goal _ _ T _ [str ID, trm X] as G) GL :- - pi x\ - copy X x => copy T (Tabs x), - if (occurs x (Tabs x)) - (if (coq.ltac.id-free? ID G) true - (coq.warn ID "is already taken, Elpi will make a name up"), - coq.id->name ID Name, - Hole x = {{ _ : lp:{{ Tabs x }} }}, % a hole with a type - refine (let Name _ X x\ Hole x) G GL) - (coq.ltac.fail _ "not found"). - -}}. -Elpi Typecheck. - -Lemma test_set (P Q : Prop) : (P /\ P) \/ (P /\ Q). -Proof. (* .in *) -elpi set "x" (P). -unfold x. -Fail elpi set "x" (Q /\ _). (* .fails .in .messages *) -elpi set "x" (P /\ _). -Abort. - -(*| - -For more examples of (basic) tactics written in Elpi see the -`eltac app `_. - - -.. _The-proof-engine: - -================ -The proof engine -================ - -In this section we dive into the details of the proof engine, that is -how goals are represented in Elpi and how things are wired up behind the scenes. - -Let's inspect the proof state a bit deeper: - -|*) - -Elpi Tactic show_more. -Elpi Accumulate lp:{{ - - solve (goal Ctx _Trigger Type Proof _) _ :- - coq.say "Goal:" Ctx "|-" Proof ":" Type, - coq.say "Proof state:", - coq.sigma.print. - -}}. -Elpi Typecheck. - -Lemma test_show_more x : x + 1 = 0. -elpi show_more. (* .in .messages *) -Abort. - -(*| - -In addition to the goal we print the Elpi and Coq proof state, -plus the link between them. -The proof state is the collection of goals together with their types. - -On the Elpi side this state is represented by constraints for the :e:`evar` -predicate. - -.. mquote:: .s(elpi show_more).msg{*c0*evar (X1 c0)*suspended on X1, X0*} - :language: text - -One can recognize the set of bound variables `{c0}`, the hypothetical -context of rules about these variable (that also corresponds to the proof -context), and finally the suspended goal :e:`evar (X1 c0) .. (X0 c0)`. - -The set of constraints on `evar` represents the Coq data structure called -sigma (sometimes also called evd or evar_map) that is used to -represent the proof state in Coq. It is printed just afterwards: - -.. mquote:: .s(elpi show_more).msg{EVARS:*[?]X57*x + 1 = 0*} - :language: text - -.. mquote:: .s(elpi show_more).msg{Coq-Elpi mapping:*RAW:*[?]X57 <-> *X1*ELAB:*[?]X57 <-> *X0*} - :language: text - -Here `?X57` is a Coq evar linked with Elpi's :e:`X0` and :e:`X1`. -:e:`X1` represents the goal (the trigger) while :e:`X0` represent the proof. -The meaning of the :e:`evar` Elpi predicate linking the two is that the term -assigned to the trigger :e:`X1` has to be elaborated to the final proof term -:e:`X0`, that should be a well typed term of type `x + 1 = 0`. -This means that when an Elpi tactic assigns a value to :e:`X1` some procedure to -turn that value into :e:`X0` is triggered. That procedure is called -elaboration and it is currently implemented by calling the -:builtin:`coq.elaborate-skeleton` API. - -Given this set up, it is impossible to use a term of the wrong type as a -Proof. Let's rewrite the `split` tactic without using :libtac:`refine`. - -|*) - -Elpi Tactic split_ll. -Elpi Accumulate lp:{{ - solve (goal Ctx Trigger {{ lp:A /\ lp:B }} Proof []) GL :- !, - Trigger = {{ conj _ _ }}, % triggers elaboration, filling Proof - Proof = {{ conj lp:Pa lp:Pb }}, - GL = [seal G1, seal G2], - G1 = goal Ctx _ A Pa [], - G2 = goal Ctx _ B Pb []. - solve _ _ :- - coq.ltac.fail _ "not a conjunction". -}}. -Elpi Typecheck. - -Lemma test_split_ll : exists t : Prop, True /\ True /\ t. -Proof. (* .in *) -eexists. -repeat elpi split_ll. -all: elpi blind. -Qed. - -(*| - -Crafting by hand the list of subgoal is not easy. -In particular here we did not set up the new trigger for :e:`Pa` and :e:`Pb`, -nor seal the goals appropriately (we did not bind proof variables). - -The :builtin:`coq.ltac.collect-goals` API helps us doing this. - -|*) - -Elpi Tactic split_ll_bis. -Elpi Accumulate lp:{{ - solve (goal Ctx Trigger {{ lp:A /\ lp:B }} Proof []) GL :- !, - % this triggers the elaboration - Trigger = {{ conj _ _ }}, - % we only take main goals - coq.ltac.collect-goals Proof GL _ShelvedGL. - solve _ _ :- - coq.ltac.fail _ "not a conjunction". -}}. -Elpi Typecheck. - -Lemma test_split_ll_bis : exists t : Prop, True /\ True /\ t. -Proof. (* .in *) -eexists. -repeat elpi split_ll_bis. -all: elpi blind. -Qed. - -(*| - -At the light of that, :libtac:`refine` is simply: - -.. code:: elpi - - refine T (goal _ RawEv _ Ev _) GS :- - RawEv = T, coq.ltac.collect-goals Ev GS _. - -Now that we know the low level plumbing, we can use :libtac:`refine` ;-) - -The only detail we still have to explain is what exactly a -:type:`sealed-goal` is. A sealed goal wraps into a single object all -the proof variables and the assumptions about them, making this object easy -(or better, sound) to pass around. - ------------------- -multi-goal tactics ------------------- - -Since Coq 8.4 tactics can see more than one goal (multi-goal tactics). -You can access this feature by using `all:` goal selector: - -* if the tactic is a regular one, it will be used on each goal independently -* if the tactic is a multi-goal one, it will receive all goals - -In Elpi you can implement a multi-goal tactic by providing a rule for -the :builtin:`msolve` predicate. Since such a tactic will need to manipulate -multiple goals, potentially living in different proof context, it receives -a list of :type:`sealed-goal`, a data type which seals a goal and -its proof context. - -|*) - -Elpi Tactic ngoals. -Elpi Accumulate lp:{{ - - msolve GL _ :- - coq.say "#goals =" {std.length GL}, - coq.say GL. - -}}. -Elpi Typecheck. - -Lemma test_undup (P Q : Prop) : P /\ Q. -Proof. (* .in *) -split. -all: elpi ngoals. -Abort. - -(*| - -This simple tactic prints the number of goals it receives, as well as -the list itself. We see something like: - -.. mquote:: .s(elpi ngoals).msg{*goals =*} - :language: text - -.. mquote:: .s(elpi ngoals).msg{*nabla*} - :language: elpi - -:constructor:`nabla` binds all proof variables, then :constructor:`seal` -holds a regular goal, which in turn carries the proof context. - -In order to operate inside a goal one can use the :libtac:`coq.ltac.open` utility, -which postulates all proof variables using :e:`pi x\ ` and loads the proof -context using :e:`=>`. - -Operating on multiple goals at the same time is doable, but not easy. -In particular the two proof context have to be related in some way. - -The following simple multi goal tactic shrinks the list of goals by -removing duplicates. As one can see, there is much room for improvement -in the :e:`same-ctx` predicate. - -|*) - -Elpi Tactic undup. -Elpi Accumulate lp:{{ - - pred same-goal i:sealed-goal, i:sealed-goal. - same-goal (nabla G1) (nabla G2) :- - % TODO: proof variables could be permuted - pi x\ same-goal (G1 x) (G2 x). - same-goal (seal (goal Ctx1 _ Ty1 P1 _) as G1) - (seal (goal Ctx2 _ Ty2 P2 _) as G2) :- - same-ctx Ctx1 Ctx2, - % this is an elpi builtin, aka same_term, which does not - % unify but rather compare two terms without assigning variables - Ty1 == Ty2, - P1 = P2. - - pred same-ctx i:goal-ctx, i:goal-ctx. - same-ctx [] []. - same-ctx [decl V _ T1|C1] [decl V _ T2|C2] :- - % TODO: we could compare up to permutation... - % TODO: we could try to relate def and decl - T1 == T2, - same-ctx C1 C2. - - pred undup i:sealed-goal, i:list sealed-goal, o:list sealed-goal. - undup _ [] []. - undup G [G1|GN] GN :- same-goal G G1. - undup G [G1|GN] [G1|GL] :- undup G GN GL. - - msolve [G1|GS] [G1|GL] :- - % TODO: we could find all duplicates, not just - % copies of the first goal... - undup G1 GS GL. - -}}. -Elpi Typecheck. - -Lemma test_undup (P Q : Prop) (p : P) (q : Q) : P /\ Q /\ P. -Proof. (* .in *) -repeat split. -Show Proof. (* .in .messages *) -all: elpi undup. -Show Proof. (* .in .messages *) -- apply p. -- apply q. -Qed. - -(*| - -The two calls to show proof display, respectively: - -.. mquote:: .s(Show Proof).msg{*conj [?]Goal (conj [?]Goal0 [?]Goal1)*} - :language: text - -.. mquote:: .s(Show Proof).msg{*conj [?]Goal (conj [?]Goal0 [?]Goal)*} - :language: text - -the proof term is the same but for the fact that after the tactic the first -and last missing subterm (incomplete proof tree branch) are represented by -the same hole `?Goal0`. Indeed by solving one, we can also solve the other. - -------------- -LCF tacticals -------------- - -On the notion of sealed-goal it is easy to define the usual LCF combinators, -also known as Ltac tacticals. Tacticals usually take in input one or more -tactic, here the precise type definition: - -.. code:: elpi - - typeabbrev tactic (sealed-goal -> (list sealed-goal -> prop)). - -A few tacticals can be fond in the -`elpi-ltac.elpi file `_. -For example this is the code of :libtac:`try`: - -.. code:: elpi - - pred try i:tactic, i:sealed-goal, o:list sealed-goal. - try T G GS :- T G GS. - try _ G [G]. - ------------------------------- -Setting arguments for a tactic ------------------------------- - -As we hinted before, tactic arguments are attached to the goal since -they can mention proof variables. So the Ltac code: - -.. code:: coq - - intro H; apply H. - -has to be seen as 3 steps, starting from a goal `G`: - -* introduction of `H`, obtaining `G1` -* setting the argument `H`, obtaining `G2` -* calling apply, obtaining `G3` - -|*) - -Elpi Tactic argpass. -Elpi Accumulate lp:{{ - -% this directive lets you use short names -shorten coq.ltac.{ open, thenl, all }. - -type intro open-tactic. % goal -> list sealed-goal -intro G GL :- refine {{ fun H => _ }} G GL. - -type set-arg-n-hyp int -> open-tactic. -set-arg-n-hyp N (goal Ctx _ _ _ _ as G) [SG1] :- - std.nth N Ctx (decl X _ _), - coq.ltac.set-goal-arguments [trm X] G (seal G) SG1. - -type apply open-tactic. -apply (goal _ _ _ _ [trm T] as G) GL :- refine T G GL. - -msolve SG GL :- - all (thenl [ open intro, - open (set-arg-n-hyp 0), - open apply ]) SG GL. - -}}. -Elpi Typecheck. - -Lemma test_argpass (P : Prop) : P -> P. -Proof. (* .in *) -elpi argpass. -Qed. - -(*| - -Of course the tactic playing the role of `intro` could communicate back -a datum to be passed to what follows - -.. code:: elpi - - thenl [ open (tac1 Datum), open (tac2 Datum) ] - -but the binder structure of :type:`sealed-goal` would prevent :e:`Datum` -to mention proof variables, that would otherwise escape the sealing. - -The utility :libtac:`set-goal-arguments`: - -.. code:: elpi - - coq.ltac.set-goal-arguments Args G G1 G1wArgs - -tries to move :e:`Args` from the context of :e:`G` to the one of :e:`G1`. -Relating the two proof contexts is not obvious: you may need to write your -own procedure if the two contexts are very distant. - -================ -Tactics in terms -================ - -Elpi tactics can be used inside terms via the usual `ltac:(...)` -quotation, but can also be exported to the term grammar. - -Here we write a simple tactic for default values, which -optionally takes a bound to the search depth. - -|*) - -Elpi Tactic default. -Elpi Accumulate lp:{{ - - pred default i:term, i:int, o:term. - - default _ 0 _ :- coq.ltac.fail _ "max search depth reached". - default {{ nat }} _ {{ 46 }}. - default {{ bool }} _ {{ false }}. - default {{ list lp:A }} Max {{ cons lp:D nil }} :- - Max' is Max - 1, default A Max' D. - - solve (goal _ _ T _ [] as G) GL :- - default T 9999 P, - refine P G GL. - -}}. -Elpi Typecheck. -Elpi Export default. - -Definition foo : nat := default. -Print foo. - -Definition bar : list bool := default. -Print bar. - -(*| - -The grammar entries for Elpi tactics in terms take an arbitrary -number of arguments with the limitation that they are all terms: -you can't pass a string or an integer as one would normally do. - -Here we use Coq's primitive integers to pass the search depth -(in a compact way). - -|*) - -Elpi Accumulate default lp:{{ - solve (goal _ _ T _ [trm (primitive (uint63 Max))] as G) GL :- - coq.uint63->int Max MaxI, - default T MaxI P, - refine P G GL. -}}. -Elpi Typecheck. - -From Coq Require Import Uint63. -Open Scope uint63_scope. - -Fail Definition baz : list nat := default 1. (* .fails *) - -Definition baz : list nat := default 2. -Print baz. - -(*| - -That is all folks! - -|*) diff --git a/examples/tutorial_coq_elpi_tactic.v b/examples/tutorial_coq_elpi_tactic.v new file mode 120000 index 000000000..35ebdb8c8 --- /dev/null +++ b/examples/tutorial_coq_elpi_tactic.v @@ -0,0 +1 @@ +../tests/tutorial_coq_elpi_tactic.t/test.v \ No newline at end of file diff --git a/examples/tutorial_elpi_lang.v b/examples/tutorial_elpi_lang.v deleted file mode 100644 index 2fcb6b2b1..000000000 --- a/examples/tutorial_elpi_lang.v +++ /dev/null @@ -1,1564 +0,0 @@ -(*| - -Tutorial on the Elpi programming language -***************************************** - -:author: Enrico Tassi - -.. include:: ../etc/tutorial_style.rst - -.. - Elpi is an extension language that comes as a library - to be embedded into host applications such as Coq. - - Elpi is a variant of λProlog enriched with constraints. - λProlog is a programming language designed to make it easy - to manipulate abstract syntax trees containing binders. - Elpi extends λProlog with modes and constraints in order - to make it easy to manipulate abstract syntax trees - containing metavariables (also called unification variables, or - evars in the Coq jargon). - - This software, "coq-elpi", is a Coq plugin embedding Elpi and - exposing to the extension language Coq specific data types (e.g. terms) - and API (e.g. to declare a new inductive type). - - In order to get proper syntax highlighting using VSCode please install the - "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in - Edit -> Preferences -> Colors. - -This little tutorial does not talk about Coq, but rather focuses on -Elpi as a programming language. It assumes no previous knowledge of -Prolog, λProlog or Elpi. Coq is used as an environment for stepping trough -the tutorial one paragraph at a time. The text between `lp:{{` and `}}` is -Elpi code, while the rest are Coq directives to drive the Elpi interpreter. - -.. contents:: - -|*) - -From elpi Require Import elpi. (* .none *) - -(*| - -================= -Logic programming -================= - -Elpi is a dialect of λProlog enriched with constraints. We start by introducing -the first order fragment of λProlog, i.e. the terms will not contain binders. -Later we cover terms with binders and constraints. - -Our first program is called `tutorial`. -We begin by declaring the signature of our terms. -Here we declare that :e:`person` is a type, and that -:e:`mallory`, :e:`bob` and :e:`alice` are terms of that type. - -|*) - -Elpi Program tutorial lp:{{ - - kind person type. - type mallory, bob, alice person. - -}}. - -(*| - -An Elpi program is made of rules that declare -when predicates hold and that are accumulated one after the -other. Rules are also called clauses in Prolog's slang, so we may use both -terms interchangeably. - -The next code snippet accumulates on top -of the current `tutorial` program a predicate declaration for :e:`age` -and three rules representing our knowledge about our terms. - -|*) - -Elpi Accumulate lp:{{ - - pred age o:person, o:int. - - age mallory 23. - age bob 23. - age alice 20. - -}}. - -(*| - -The predicate :e:`age` has two arguments, the former is a person while -the latter is an integer. The label :e:`o:` (standing for output) -is a mode declaration, which we will explain later (ignore it for now). - -.. note:: :stdtype:`int` is the built-in data type of integers - - Integers come with usual arithmetic operators, see the :stdlib:`calc` built-in. - -In order to run our program we have to write a query, -i.e. a predicate expression containing variables such as: - -.. code:: elpi - - age alice A - -The execution of the program is expected to assign a value to :e:`A`, which -represents the age of :e:`alice`. - -.. important:: - - Syntactic conventions: - - * variables are identifiers starting with a capital letter, eg - :e:`A`, :e:`B`, :e:`FooBar`, :e:`Foo_bar`, :e:`X1` - * constants (for individuals or predicates) are identifiers - starting with a lowercase letter, eg - :e:`foo`, :e:`bar`, :e:`this_that`, :e:`camelCase`, - :e:`dash-allowed`, :e:`qmark_too?`, :e:`arrows->and.dots.as<-well` - -A query can be composed of many predicate expressions separated by :e:`,` -that stands for conjunction: we want to get an answer to all the -predicate expressions. - -|*) - -Elpi Query lp:{{ - - age alice A, coq.say "The age of alice is" A - -}}. - -(*| - -:builtin:`coq.say` is a built-in predicate provided by Coq-Elpi which -prints its arguments. -You can look at the output buffer of Coq to see the value for :e:`A` or hover -or toggle the little bubble after `}}.` if you are reading the tutorial with a -web browser. - -.. note:: :stdtype:`string` is a built-in data type - - Strings are delimited by double quotes and ``\`` is the escape symbol. - -The predicate :e:`age` represents a *relation* (in contrast to a function) -and it computes both ways: we can ask Elpi which person :e:`P` is 23 years old. - -|*) - -Elpi Query lp:{{ - - age P 23, coq.say P "is 23 years old" - -}}. - -(*| - ------------ -Unification ------------ - -Operationally the query :e:`age P 23` is *unified* with each -and every rule present in the program starting from the first one. - -Unification compares two -terms structurally and eventually assigns variables. -For example for the first rule of the program we obtain -the following unification problem: - -.. code:: elpi - - age P 23 = age mallory 23 - -This problem can be simplified into smaller unification problems following -the structure of the terms: - -.. code:: elpi - - age = age - P = mallory - 23 = 23 - -The first and last are trivial, while the second one can be satisfied by -assigning :e:`mallory` to :e:`P`. All equations are solved, -hence unification succeeds. - -See also the `Wikipedia page on Unification `_. - -Since the first part of the query is succesful the rest of -the query is run: the value of :e:`P` is printed as well as -the :e:`"is 23 years old"` string. - -.. note:: :e:`=` is a regular predicate - - The query :e:`age P 23` can be also written as follows: - - .. code:: elpi - - A = 23, age P A, Msg = "is 23 years old", coq.say P Msg - - -Let's try a query harder to solve! - -|*) - -Elpi Query lp:{{ - - age P 20, coq.say P "is 20 years old" - -}}. - -(*| - -This time the unification problem for the first rule -in the program is: - -.. code:: elpi - - age P 20 = age mallory 23 - -that is simplified to: - -.. code:: elpi - - age = age - P = mallory - 20 = 23 - -The second equation can be solved by assigning :e:`mallory` to :e:`P`, -but the third one has no solution, so unification fails. - ------------- -Backtracking ------------- - -When failure occurs all assignements are undone (i.e. :e:`P` is unset again) -and the next rule in the program is tried. This operation is called -*backtracking*. - -The unification problem for the next rule is: - -.. code:: elpi - - age P 20 = age bob 23 - -This one also fails. The unification problem for the last rule is: - -.. code:: elpi - - age P 20 = age alice 20 - -This one works, and the assigment :e:`P = alice` is kept as the result -of the first part of the query. Then :e:`P` is printed and the program -ends. - -An even harder query is the following one where we ask for two distinct -individuals to have the same age. - -|*) - -Elpi Query lp:{{ - - age P A, age Q A, not(P = Q), - coq.say P "and" Q "are" A "years old" - -}}. - -(*| - -This example shows that backtracking is global. The first solution for -:e:`age P A` and :e:`age Q A` picks :e:`P` and :e:`Q` to -be the same individual :e:`mallory`, -but then :e:`not(P = Q)` fails and forces the last choice that was made to be -reconsidered, so :e:`Q` becomes :e:`bob`. - -Look at the output of the following code to better understand -how backtracking works. - -|*) - -Elpi Query lp:{{ - - age P A, coq.say "I picked P =" P, - age Q A, coq.say "I picked Q =" Q, - not(P = Q), - coq.say "the last choice worked!", - coq.say P "and" Q "are" A "years old" - -}}. - -(*| - -.. note:: :e:`not` is a black hole - - The :e:`not(P)` predicate tries to solve the query :e:`P`: it fails if - :e:`P` succeeds, and succeeds if :e:`P` fails. In any case no trace is left - of the computation for :e:`P`. E.g. :e:`not(X = 1, 2 < 1)` suceeds, but - the assignment for :e:`X` is undone. See also the section - about the `foundations`_ of λProlog. - ---------------------------- -Facts and conditional rules ---------------------------- - -The rules we have seen so far are *facts*: they always hold. -In general rules can only be applied if some *condition* holds. Conditions are -also called premises, we may use the two terms interchangeably. - -Here we add to our program a rule that defines what :e:`older P Q` means -in terms of the :e:`age` of :e:`P` and :e:`Q`. - -.. note:: :e:`:-` separates the *head* of a rule from the *premises* - -|*) - -Elpi Accumulate lp:{{ - - pred older o:person, o:person. - older P Q :- age P N, age Q M, N > M. - -}}. - -(*| - -The rule reads: :e:`P` is older than :e:`Q` if -:e:`N` is the age of :e:`P` -*and* :e:`M` is the age of :e:`Q` -*and* :e:`N` is greater than :e:`M`. - -Let's run a query using older: - -|*) - -Elpi Query lp:{{ - - older bob X, - coq.say "bob is older than" X - -}}. - -(*| - -The query :e:`older bob X` is unified with the head of -the program rule :e:`older P Q` -assigning :e:`P = bob` and :e:`X = Q`. Then three new queries are run: - -.. code:: elpi - - age bob N - age Q M - N > M - -The former assigns :e:`N = 23`, the second one first -sets :e:`Q = mallory` and :e:`M = 23`. This makes the last -query to fail, since :e:`23 > 23` is false. Hence the -second query is run again and again until :e:`Q` is -set to :e:`alice` and :e:`M` to :e:`20`. - -Variables in the query are said to be existentially -quantified because Elpi will try to find one -possible value for them. - -Conversely, the variables used in rules are -universally quantified in the front of the rule. -This means that the same program rule can be used -multiple times, and each time the variables are fresh. - -In the following example the variable :e:`P` in :e:`older P Q :- ...` -once takes :e:`bob` and another time takes :e:`mallory`. - -|*) - -Elpi Query lp:{{ - - older bob X, older mallory X, - coq.say "both bob and mallory are older than" X - -}}. - -(*| - -================== -Terms with binders -================== - -So far the syntax of terms is based on constants -(eg :e:`age` or :e:`mallory`) and variables (eg :e:`X`). - -λProlog adds another term constructor: -λ-abstraction (written :e:`x\ ...`). - -.. note:: the variable name before the ``\`` can be a capital - - Given that it is explicitly bound Elpi needs not to guess if it is a global - symbol or a rule variable (that required the convention of using capitals for - variables in the first place). - -------------- -λ-abstraction -------------- - -Functions built using λ-abstraction can be applied -to arguments and honor the usual β-reduction rule -(the argument is substituted for the bound variable). - -In the following example :e:`F 23` reads, once -the β-reduction is performed, :e:`age alice 23`. - -|*) - -Elpi Query lp:{{ - - F = (x\ age alice x), - coq.say "F =" F, - coq.say "F 20 =" (F 20), - coq.say "F 23 =" (F 23) - -}}. - -(*| - -Let's now write the "hello world" of λProlog: an -interpreter and type checker for the simply -typed λ-calculus. We call this program `stlc`. - -We start by declaring that :e:`term` is a type and -that :e:`app` and :e:`fun` are constructors of that type. - -|*) - -Elpi Program stlc lp:{{ - - kind term type. - - type app term -> term -> term. - type fun (term -> term) -> term. - -}}. - -(*| - -The constructor :e:`app` takes two terms -while :e:`fun` only one (of functional type). - -Note that - -* there is no constructor for variables, we will - use the notion of bound variable of λProlog in order - to represent variables -* :e:`fun` takes a function as subterm, i.e. something - we can build using the λ-abstraction :e:`x\ ...` - -As a consequence, the identity function λx.x is written like this: - -.. code:: elpi - - fun (x\ x) - -while the first projection λx.λy.x is written: - -.. code:: elpi - - fun (x\ fun (y\ x)) - -Another consequence of this approach is that there is no -such thing as a free variable in our representation of the λ-calculus. -Variables are only available under the λ-abstraction of the -programming language, that gives them a well defined scope and -substitution operation (β-reduction). - -This approach is called `HOAS `_. - -We can now implement weak head reduction, that is we stop reducing -when the term is a :e:`fun` or a global constant (potentially applied). -If the term is :e:`app (fun F) A` then we compute the reduct :e:`F A`. -Note that :e:`F` is a λProlog function, so passing an argument to it -implements the substitution of the actual argument for the bound variable. - -We first give a type and a mode for our predicate :e:`whd`. It reads -"whd takes a term in input and gives a term in output". We will -explain what input means precisely later, for now just think about it -as a comment. - -|*) - -Elpi Accumulate lp:{{ - - pred whd i:term, o:term. - - % when the head "Hd" of an "app" (lication) is a - % "fun" we substitute and continue - whd (app Hd Arg) Reduct :- whd Hd (fun F), !, - whd (F Arg) Reduct. - - % otherwise a term X is already in normal form. - whd X Reduct :- Reduct = X. - -}}. - -(*| - -Recall that, due to backtracking, all rules are potentially used. -Here whenever the first premise of the first rule succeeds -we want the second rule to be skipped, since we found a redex. - -The premises of a rule are run in order and the :e:`!` operator discards all -other rules following the current one. Said otherwise it commits to -the currently chosen rule for the current query (but leaves -all rules available for subsequent queries, they are not erased from the -program). So, as soon as :e:`whd Hd (fun F)` succeeds we discard the second -rule. - -|*) - -Elpi Query lp:{{ - - I = (fun x\x), - whd I T, coq.say "λx.x ~>" T, - whd (app I I) T1, coq.say "(λx.x) (λx.x) ~>" T1 - -}}. - -(*| - -Another little test using global constants: - -|*) -Elpi Accumulate lp:{{ - - type foo, bar term. - -}}. - -Elpi Query lp:{{ - - Fst = fun (x\ fun y\ x), - T = app (app Fst foo) bar, - whd T T1, coq.say "(Fst foo bar) ~>" T1, - S = app foo bar, - whd S S1, coq.say "(foo bar) ~>" S1 - -}}. - -(*| - -A last test with a lambda term that has no weak head normal form: - -|*) - -Elpi Bound Steps 1000. (* Let's be cautious *) -Fail Elpi Query lp:{{ - - Delta = fun (x\ app x x), - Omega = app Delta Delta, - whd Omega Hummm, coq.say "not going to happen" - -}}. (* .fails *) -Elpi Bound Steps 0. - -(*| - ------------------------ -:e:`pi x\ ` and :e:`=>` ------------------------ - -We have seen how to implement subtitution using the binders of λProlog. -More often than not we need to move under binders rather than remove them by -substituting some term in place of the bound variable. - -In order to move under a binder and inspect the body of a function λProlog -provides the :e:`pi` quantifier and the :e:`=>` connective. - -A good showcase for these features is to implement a type checker -for the simply typed lambda calculus. -See also `the Wikipedia page on the simply typed lambda calculus `_. - -We start by defining the data type of simple types. -We then declare a new predicate :e:`of` (for "type of") and finally -we provide two rules, one for each term constructor. - -|*) - -Elpi Accumulate lp:{{ - - kind ty type. % the data type of types - type arr ty -> ty -> ty. % our type constructor - - pred of i:term, o:ty. % the type checking algorithm - - % for the app node we ensure the head is a function from - % A to B, and that the argument is of type A - of (app Hd Arg) B :- - of Hd (arr A B), of Arg A. - - % for lambda, instead of using a context (a list) of bound - % variables we use pi and => , explained below - of (fun F) (arr A B) :- - pi x\ of x A => of (F x) B. - -}}. - -(*| - -The :e:`pi name\ code` syntax is reserved, as well as -:e:`rule => code`. - -Operationally :e:`pi x\ code` introduces a fresh -constant :e:`c` for :e:`x` and then runs :e:`code`. -Operationally :e:`rule => code` adds :e:`rule` to -the program and runs :e:`code`. Such extra rule is -said to be hypothetical. -Both the constant for :e:`x` and :e:`rule` are -removed once :e:`code` terminates. - -.. important:: hypothetical rules are added at the *top* of the program - - Hypothetical rules hence take precedence over static rules, since - they are tried first. - -Note that in this last example the hypothetical rule is going to be -:e:`of c A` for a fixed :e:`A` and a fresh constant :e:`c`. -The variable :e:`A` is fixed but not assigned yet, meaning -that :e:`c` has a type, and only one, but we may not know it yet. - - -Now let's assign a type to λx.λy.x: - -|*) - -Elpi Query lp:{{ - -of (fun (x\ fun y\ x)) Ty, coq.say "The type of λx.λy.x is:" Ty - -}}. - -(*| - -Let's run this example step by step: - -The rule for :e:`fun` is used: - -* :e:`arrow A1 B1` is assigned to :e:`Ty` by unification -* the :e:`pi x\ ` quantifier creates a fresh constant :e:`c1` to play - the role of :e:`x` -* the :e:`=>` connective adds the rule :e:`of c1 A1` the program -* the new query :e:`of (fun y\ c1) B1` is run. - -Again, the rule for :e:`fun` is used (since its variables are -universally quantified, we use :e:`A2`, :e:`B2`... this time): - -* :e:`arrow A2 B2` is assigned to :e:`B1` by unification -* the :e:`pi x\ ` quantifier creates a fresh constant :e:`c2` to play - the role of :e:`x` -* the :e:`=>` connective adds the rule :e:`of c2 A2` the program -* the new query :e:`of c1 B2` is run. - -The (hypotetical) rule :e:`of c1 A1` is used: - -* unification assigns :e:`A1` to :e:`B2` - -The value of :e:`Ty` is hence :e:`arr A1 (arr A2 A1)`, a good type -for λx.λy.x (the first argument and the output have the same type :e:`A1`). - -What about the term λx.(x x) ? - -|*) - -Elpi Query lp:{{ - - Delta = fun (x\ app x x), - (of Delta Ty ; coq.say "Error:" Delta "has no type") - -}}. - -(*| - -The :e:`;` infix operator stands for disjunction. Since we see the message -:e:`of` failed: the term :e:`fun (x\ app x x)` is not well typed. - -First, the rule for elpi:`fun` is selected: - -* :e:`arrow A1 B1` is assigned to :e:`Ty` by unification -* the :e:`pi x\ ` quantifier creates a fresh constant :e:`c1` to play the - role of :e:`x` -* the :e:`=>` connective adds the rule :e:`of c1 A1` the program -* the new query :e:`of (app c1 c1) B1` is run. - -Then it's the turn of typing the application: - -* the query :e:`of c1 (arr A2 B2)` assignes to :e:`A1` the - value :e:`arr A2 B2`. This means that the - hypothetical rule is now :e:`of c1 (arr A2 B2)`. -* the query :e:`of c1 A2` fails because the unification - - .. code:: elpi - - of c1 A2 = of c1 (arr A2 B2) - - has no solution, in particular the sub problem :e:`A2 = (arr A2 B2)` - fails the so called occur check. - - -.. _foundations: - -=================== -Logical foundations -=================== - -This section tries to link, informally, λProlog with logic, assuming the reader -has some familiarity with first order intuitionistic logic and proof theory. -The reader which is not familiar with that can probably skip this section, -although section `functional-style`_ contains some explanations about -the scope of variables which are based on the logical foundations of -the language. - -The semantics of a λProlog program is given by interpreting -it in terms of logical formulas and proof search in intuitionistic logic. - -A rule - -.. code:: elpi - - p A B :- q A C, r C B. - -has to be understood as a formula - -.. math:: - - ∀A~B~C, (\mathrm{q}~A~C ∧ \mathrm{r}~C~B) → \mathrm{p}~A~B - -A query is a goal that is proved by backchaining -rules. For example :e:`p 3 X` -is solved by unifying it with the conclusion of -the formula above (that sets :e:`A` to :e:`3`) and -generating two new goals, :e:`q 3 C` and -:e:`r C B`. Note that :e:`C` is an argument to both -:e:`q` and :e:`r` and acts as a link: if solving :e:`q` -fixes :e:`C` then the query for :e:`r` sees that. -Similarly for :e:`B`, that is identified with :e:`X`, -and is hence a link from the solution of :e:`r` to -the solution of :e:`p`. - -A rule like: - -.. code:: elpi - - of (fun F) (arr A B) :- - pi x\ of x A => of (F x) B. - -reads, as a logical formula: - -.. math:: - - ∀F~A~B, (∀x, \mathrm{of}~x~A → \mathrm{of}~(F~x)~B) → \mathrm{of}~(\mathrm{fun}~F)~(\mathrm{arr}~A~B) - -where :math:`F` stands for a function. -Alternatively, using the inference rule notation typically used for -type systems: - -.. math:: - - \frac{\Gamma, \mathrm{of}~x~A \vdash \mathrm{of}~(F~x)~B \quad x~\mathrm{fresh}}{\Gamma \vdash \mathrm{of}~(\mathrm{fun}~F)~(\mathrm{arr}~A~B)} - -Hence, :e:`x` and :e:`of x A` are available only -temporarily to prove :e:`of (F x) B` and this is -also why :e:`A` cannot change during this sub proof (:e:`A` is -quantified once and forall outside). - -Each program execution is a proof (tree) of the query -and is made of the program rules seen as proof rules or axioms. - -As we hinted before negation is a black hole, indeed the usual definition of -:math:`\neg A` as :math:`A \to \bot` is the one of a function with no output -(see also the `the Wikipedia page on the Curry-Howard correspondence `_). - -===================== -Modes and constraints -===================== - -Elpi extends λProlog with *syntactic constraints* -and rules to manipulate the store of constraints. - -Syntactic constraints are goals suspended on -a variable which are resumed as soon as that variable -gets instantiated. While suspended they are kept in a store -which can be manipulated by dedicated rules. - -A companion facility is the declaration of *modes*. -The argument of a predicate can be marked as input -to avoid instantiating the goal when it is unified -with the head of a rule (an input argument -is matched, rather than unified). - -A simple example: Peano's addition: - -|*) - -Elpi Program peano lp:{{ - -kind nat type. -type z nat. -type s nat -> nat. - -pred add o:nat, o:nat, o:nat. - -add (s X) Y (s Z) :- add X Y Z. -add z X X. - -}}. - -Elpi Query lp:{{ - - add (s (s z)) (s z) R, coq.say "2 + 1 =" R - -}}. - -(*| - -Unfortunately the relation does not work well -when the first argument is a variable. Depending on the -order of the rules for :e:`add` Elpi can either diverge or pick -:e:`z` as a value for :e:`X` (that may not be what one wants) - -|*) - -Elpi Bound Steps 100. -Fail Elpi Query lp:{{ add X (s z) Y }}. (* .fails *) -Elpi Bound Steps 0. - -(*| - -Indeed the first rule for add can be applied forever. -If one exchanges the two rules in the program, then Elpi -terminates picking :e:`z` for :e:`X`. - -We can use the mode directive in order to -*match* arguments marked as :e:`i:` against the patterns -in the head of rules, rather than unifying them. - -|*) - -Elpi Program peano2 lp:{{ - -kind nat type. -type z nat. -type s nat -> nat. - -pred sum i:nat, i:nat, o:nat. - -sum (s X) Y (s Z) :- sum X Y Z. -sum z X X. -sum _ _ _ :- - coq.error "nothing matched but for this catch all clause!". - -}}. - -Fail Elpi Query lp:{{ sum X (s z) Y }}. (* .fails *) - -(*| - -The query fails because no rule first argument matches :e:`X`. - -Instead of failing we can suspend goals and turn them into -syntactic constraints - -|*) - -Elpi Program peano3 lp:{{ - -kind nat type. -type z nat. -type s nat -> nat. - -pred sum i:nat, i:nat, o:nat. - -sum (s X) Y (s Z) :- sum X Y Z. -sum z X X. -sum X Y Z :- - % the head of the rule always unifies with the query, so - % we double check X is a variable (we could also be - % here because the other rules failed) - var X, - % then we declare the constraint and schedule its resumption - % on the assignment of X - declare_constraint (sum X Y Z) [X]. - -}}. - -Elpi Query lp:{{ sum X (s z) Z }}. - -(*| - -Syntactic constraints are resumed when the variable -they are suspended on is assigned: - -|*) - -Elpi Query lp:{{ - - sum X (s z) Z, X = z, - coq.say "The result is:" Z - -}}. - -(*| - -Here a couple more examples. Keep in mind that: - -* resumption can cause failure -* recall that :e:`;` stands for disjunction - -|*) - -Fail Elpi Query lp:{{ sum X (s z) (s (s z)), X = z }}. (* .fails *) -Elpi Query lp:{{ sum X (s z) (s (s z)), (X = z ; X = s z) }}. - -(*| - -In this example the computation suspends, then makes progess, -then suspends again... - -|*) - -Elpi Query lp:{{ - - sum X (s z) Y, - print_constraints, coq.say "Currently Y =" Y, - X = s Z, - print_constraints, coq.say "Currently Y =" Y, - Z = z, - coq.say "Finally Y =" Y - -}}. - -(*| - -Sometimes the set of syntactic constraints becomes unsatisfiable -and we would like to be able to fail early. - -|*) - -Elpi Accumulate lp:{{ - -pred even i:nat. -pred odd i:nat. - -even z. -even (s X) :- odd X. -odd (s X) :- even X. - -odd X :- var X, declare_constraint (odd X) [X]. -even X :- var X, declare_constraint (even X) [X]. - -}}. - -Elpi Query lp:{{ even (s X), odd (s X) }}. (* hum, not nice *) - -(*| - -------------------------- -Constraint Handling Rules -------------------------- - -A constraint (handling) rule can see the store of syntactic constraints -as a whole, remove constraints and/or create new goals: - -|*) - -Elpi Accumulate lp:{{ - -constraint even odd { - % if two distinct, conflicting, constraints about the same X - % are part of the constraint store - rule (even X) (odd X) <=> - % generate the following goal - (coq.say X "can't be even and odd at the same time", fail). -} - -}}. - -Fail Elpi Query lp:{{ even (s X), odd (s X) }}. (* .fails *) - -(*| - -.. note:: :e:`fail` is a predicate with no solution - -See also the Wikipedia page on `Constraint Handling Rules `_ -for an introduction to the sub language to manipulate constraints. - -.. _functional-style: - -================ -Functional style -================ - -Elpi is a relational language, not a functional one. Still some features -typical of functional programming are available, with some caveats. - -------------------------------- -Spilling (relation composition) -------------------------------- - -Chaining "relations" can be painful, especially when -they look like functions. Here we use :stdlib:`std.append` -and :stdlib:`std.rev` to build a palindrome: - -|*) - -Elpi Program function lp:{{ - -pred make-palindrome i:list A, o:list A. - -make-palindrome L Result :- - std.rev L TMP, - std.append L TMP Result. - -}}. - -Elpi Query lp:{{ - - make-palindrome [1,2,3] A - -}}. - -(*| - -.. note:: variables (capital letters) can be used in - types in order to describe ML-like polymorphism. - -.. note:: :e:`list A` is a built-in data type - - The empty list is written :e:`[]`, while the cons constructor - is written :e:`[Hd | Tail]`. Iterated cons can be written - :e:`[ E1, E2 | Tail ]` and :e:`| Tail` can be omitted if the list - is nil terminated. - -The :e:`make-palindrome` predicate has to use a temporary variable -just to pass the output of a function as the input to another function. - -Spilling is a syntactic elaboration which does that for you. -Expressions between `{` and `}` are -said to be spilled out and placed just before the predicate -that contains them. - -*) - -Elpi Accumulate lp:{{ - -pred make-palindrome2 i:list A, o:list A. - -make-palindrome2 L Result :- - std.append L {std.rev L} Result. - -}}. - -Elpi Query lp:{{ - - make-palindrome2 [1,2,3] A - -}}. - -(*| - -The two versions of :e:`make-palindrome` are equivalent. -Actually the latter is elaborated into the former. - ----------------------- -APIs for built-in data ----------------------- - -Functions about built-in data types are available via the -:stdlib:`calc` predicate or its infix version :e:`is`. Example: - -|*) - -Elpi Query lp:{{ - - calc ( "result " ^ "=" ) X, - Y is 3 + 2, - coq.say X Y - -}}. - -(*| - -The :stdlib:`calc` predicate works nicely with spilling: - -|*) - -Elpi Query lp:{{ coq.say "result =" {calc (2 + 3)} }}. - -(*| - ------------------------ -Allocation of variables ------------------------ - -The language let's one use λ-abstraction also to write anonymous rules -but one has to be wary of where variables are bound (allocated really). - -In our example we use the higher order predicate :stdlib:`std.map`: - -.. code:: elpi - - pred std.map i:list A, i:(A -> B -> prop), o:list B. - -.. note:: :e:`prop` is the type of predicates - - The actual type of the :e:`std.map` symbol is: - - .. code:: elpi - - type std.map list A -> (A -> B -> prop) -> list B -> prop. - - The :e:`pred` directive complements a type declaration for predicates - (the trailing :e:`-> prop` is implicit) with a mode declaration for - each argument. - -The type of the second argument of :e:`std.map` -is the one of a predicate relating :e:`A` with :e:`B`. - -Let's try to call :e:`std.map` passing an anonymous rule (as we -would do in a functional language by passing an anonymous function): - -|*) - -Elpi Accumulate lp:{{ - -pred bad i:list int, o:list int. - -bad L Result :- - std.map L (x\ r\ TMP is x + 1, r = TMP) Result. - -pred good i:list int, o:list int. -good L Result :- - std.map L good.aux Result. -good.aux X R :- TMP is X + 1, R = TMP. - -pred good2 i:list int, o:list int. -good2 L Result :- - std.map L (x\ r\ sigma TMP\ TMP is x + 1, r = TMP) Result. - -}}. - -Elpi Query lp:{{ - - not(bad [1,2,3] R1), - good [1,2,3] R2, - good2 [1,2,3] R3 - -}}. - -(*| - -The problem with :e:`bad` is that :e:`TMP` is fresh each time the rule -is used, but not every time the anonymous rule passed to :stdlib:`map` -is used. Technically :e:`TMP` is quantified (allocated) where :e:`L` -and :e:`Result` are. - -There are two ways to quantify :e:`TMP` correctly, that is inside the -anonymous predicate. One is to actually name the predicate. Another one is -to use the :e:`sigma x\ ` quantifier to allocate :e:`TMP` at every call. -We recommend to name the auxiliary predicate. - -.. tip:: predicates whose name ends in `.aux` don't trigger a missing type - declaration warning - -One last way to skin the cat is to use :e:`=>` as follows. It gives us -the occasion to clarify further the scope of variables. - -|*) - -Elpi Accumulate lp:{{ - -pred good3 i:list int, o:list int. -good3 L Result :- - pi aux\ - (pi TMP X R\ aux X R :- TMP is X + 1, R = TMP) => - std.map L aux Result. - -}}. - -Elpi Query lp:{{ - - good3 [1,2,3] R - -}}. - -(*| - -In this case the auxiliary predicate :e:`aux` -is only visible inside :e:`good3`. -What is interesting to remark is that the quantifications are explicit -in the hypothetical rule, and they indicate clearly that each and every -time :e:`aux` is used :e:`TMP`, :e:`X` and :e:`R` are fresh. - -The :e:`pi x\ ` quantifier is dual to :e:`sigma x\ `: since here it -occurs negatively it has the same meaning. That is, the hypothetical rule -could be written :e:`pi X R\ aux X R :- sigma TMP\ TMP is X + 1, R = TMP`. - -.. tip:: :e:`pi x\ ` and :e:`sigma x\ ` can quantify on a bunch of variables - at once - - That is, :e:`pi x y\ ...` is equivalent to :e:`pi x\ pi y\ ...` and - :e:`sigma x y\ ...` is equivalent to :e:`sigma x\ sigma y\ ...`. - -.. tip:: :e:`=>` can load more than one clause at once - - It is sufficient to put a list on the left hand side, eg :e:`[ rule1, rule2 ] => code`. - Moreover one can synthesize a rule before loading it, eg: - - .. code:: elpi - - Rules = [ one-more-rule | ExtraRules ], Rules => code - -The last remark worth making is that bound variables are intimately related -to universal quantification, while unification variables are related to -existential quantification. It goes without saying that the following -two formulas are not equivalent and while the former is trivial the latter -is in general false: - -.. math:: - - ∀x, ∃Y, Y = x\\ - ∃Y, ∀x, Y = x - -Let's run these two corresponding queries: - -|*) - -Elpi Query lp:{{ pi x\ sigma Y\ Y = x, coq.say "Y =" Y }}. -Fail Elpi Query lp:{{ sigma Y\ pi x\ Y = x, coq.say "Y =" Y }}. (* .fails *) - -(*| - -Another way to put it: :e:`x` is in the scope of :e:`Y` only in the first -formula since it is quantified before it. Hence :e:`x` can be assigned to -:e:`Y` in that case, but not in the second query, where it is quantified -after. - -More in general, λProlog tracks the bound variables that are in scope of each -unification variable. There are only two ways to put a bound variable -in the scope: - -* quantify the unification variable under the bound one (first formula) -* pass the bound variable to the unification variable explicitly: in this - case the unification variable needs to have a functional type. - Indeed :math:`∃Y, ∀x, (Y x) = x` has a solution: :e:`Y` can be - the identity function. - - .. coq:: - - Elpi Query lp:{{ sigma Y\ pi x\ Y x = x, coq.say "Y =" Y }}. - -If we look again at the rule for type checking -λ-abstraction: - -.. code:: elpi - - of (fun F) (arr A B) :- - pi x\ of x A => of (F x) B. - -we can see that the only unification variable that sees the fresh -`x` is :e:`F`, because we pass :e:`x` to :e:`F` explicitly -(recall all unification variables such as :e:`F`, :e:`A`, :e:`B` are -quantified upfront, before the :e:`pi x\ `). -Indeed when we write: - -.. math:: - - \frac{\Gamma, x : A \vdash f : B}{\Gamma \vdash λx.f : A → B} - -on paper, the variable denoted by :e:`x` being bound there can only occur in -:math:`f`, not in :math:`\Gamma` or :math:`B` for example (although a -*different* variable could be named the same, hence the usual freshness side -conditions which are not really necessary using HOAS). - -Remark that in the premise the variable :math:`x` is still bound, this time -not by a λ-abstraction but by the context :math:`\Gamma, x : A`. -In λProlog the context is the set of hypothetical rules and :e:`pi\ ` --quantified variables and is implicitly handled by the runtime of the -programming language. - -A slogan to keep in mind is that: - -.. important:: There is no such thing as a free variable! - -Indeed the variable bound by the λ-abstraction (of our data) is -replaced by a fresh variable bound by the context (of our program). This is -called binder mobility. See also the paper -`Mechanized metatheory revisited `_ by -Dale Miller which is an excellent -introduction to these concepts. - -========= -Debugging -========= - -The most sophisticated debugging feature can be used via -the Visual Sudio Code extension ``gares.elpi-lang`` and its -``Elpi Tracer`` tab. - ---------------- -Trace browser ---------------- - -In order to generate a trace one needs to execute the -``Elpi Trace Browser.`` command and then run any Elpi code. - -|*) - -(* Elpi Trace Browser. *) - -Elpi Query stlc lp:{{ % We run the query in the stlc program - - of (fun (x\ fun y\ x)) Ty, coq.say Ty - -}}. - -(*| - -The trace file is generated in ``/tmp/traced.tmp.json``. -If it does not load automatically one can do it manually by clicking on -the load icon, in the upper right corner of the Elpi Tracer panel. - -.. note:: partial display of goals - - At the time of writing one may need to disable syntax highlighting in - the extension settings in order to get a correct display. - -The trace browser displays, on the left column, a list of cards corresponding -to a step perfoemd by the interpreter. The right side of the -panel gives more details about the selected step. In the image below one -can see the goal, the rule being applied, the assignments performed by the -unification of the rule's head with the goal, the subgoals generated. - -.. image:: tracer.png - :width: 800 - -One can also look at the trace in text format (if VSCode is not an option, -for example). - -|*) -Elpi Trace. - -Elpi Query stlc lp:{{ % We run the query in the stlc program - - of (fun (x\ fun y\ x)) Ty, coq.say Ty - -}}. - -Fail Elpi Query stlc lp:{{ - - of (fun (x\ app x x)) Ty, coq.say Ty - -}}. (* .fails *) - -(*| - -The trace can be limited to a range of steps. Look at the -numbers ``run HERE {{{``. - -|*) - -Elpi Trace 6 8. -Elpi Query stlc lp:{{ - - of (fun (x\ fun y\ x)) Ty, coq.say Ty - -}}. - -(*| - -The trace can be limited to a (list of) predicates as follows: - -|*) - -Elpi Trace "of". -Elpi Query stlc lp:{{ - - of (fun (x\ fun y\ x)) Ty, coq.say Ty - -}}. - -(*| - -One can combine the range of steps with the predicate: - -|*) - -Elpi Trace 6 8 "of". -Elpi Query stlc lp:{{ - - of (fun (x\ fun y\ x)) Ty, coq.say Ty - -}}. - -(*| - -To switch traces off: - -|*) - -Elpi Trace Off. - -(*| - ---------------- -Good old print ---------------- - -A common λProlog idiom is to have a debug rule -lying around. The :e:`:if` attribute can be used to -make the rule conditionally interpreted (only if the -given debug variable is set). - -|*) - -Elpi Debug "DEBUG_MYPRED". -Elpi Program debug lp:{{ - - pred mypred i:int. - - :if "DEBUG_MYPRED" - mypred X :- - coq.say "calling mypred on " X, fail. - - mypred 0 :- coq.say "ok". - mypred M :- N is M - 1, mypred N. - -}}. -Elpi Query lp:{{ mypred 3 }}. - -(*| - ------------------------- -Printing entire programs ------------------------- - -Given that programs are not written in a single place, but rather obtained by -accumulating code, Elpi is able to print a (full) program to an html file -as follows. The obtained file provides a facility to filter rules by their -predicate. - -|*) - -Elpi Print stlc. - -(*| - -Look at the `generated page `_ -and type :e:`of` in the filter. - -Finally, one can bound the number of backchaining steps -performed by the interpreter: - -|*) - -Elpi Query lp:{{ 0 = 0, 1 = 1 }}. -Elpi Bound Steps 1. -Fail Elpi Query lp:{{ 0 = 0, 1 = 1 }}. (* .fails *) (* it needs 2 steps! *) -Elpi Bound Steps 0. (* Go back to no bound *) - -(*| - ---------------- -Common pitfalls ---------------- - -Well, no programming language is perfect. - -++++++++++++++++++++++++++++++++ -Precedence of :e:`,` and :e:`=>` -++++++++++++++++++++++++++++++++ - - -The precedence of :e:`,` and :e:`=>` can be surprising - -|*) - -Fail Elpi Query stlc lp:{{ - - pi x\ - of x A => of x B, of x C - -}}. (* .fails *) - -Elpi Query stlc lp:{{ - - pi x\ - of x A => (of x B, of x C) % both goals see of x A - -}}. - -(*| - -++++++++++++ -Backtracking -++++++++++++ - - -Backtracking can lead to weird execution traces. The :stdlib:`std.do!` predicate -should be used to write non-backtracking code. - -.. code:: elpi - - pred not-a-backtracking-one. - not-a-backtracking-one :- condition, !, std.do! [ - step, - (generate, test), - step, - ]. - -In the example above once :e:`condition` holds we start a sequence of -steps which we will not reconsider. Locally, backtracking is still -available, e.g. between :e:`generate` and :e:`test`. -See also the :stdlib:`std.spy-do!` predicate which prints each and every step, -and the :stdlib:`std.spy` one which can be used to spy on a single one. - -+++++++++++++++++++++++++++++++++++++++++++++++ -Unification variables v.s. Imperative variables -+++++++++++++++++++++++++++++++++++++++++++++++ - -Unification variables sit in between variables in imperative programming and -functional programming. In imperative programming a variable can hold a value, -and that value can change over time via assignment. In functional languages -variables always hold a value, and that value never changes. In logic programming -a unification variable can either be unset (no value) or set to a value that -never changes. Backtracking goes back in time, it is not visible to the program. - -As a result of this, code like - -.. code:: elpi - - pred bad-example. - bad-example :- X is 1 + 2, X is 4 + 5. - -fails, because :e:`X` cannot be at the same time 3 and 9. Initially -:e:`X` is unset, then it is set to 3, and finally the programmer is -asserting that 3 (the value hold by :e:`X`) is equal to 9. -The second call to :e:`is` does not change the value carried by :e:`X`! - -Unification, and hence the :e:`=` pradicate, plays two roles. -When :e:`X` is unset, :e:`X = v` sets the variable. -When :e:`X` is set to :e:`u`, :e:`X = v` checks if the value -of :e:`X` is equal to :e:`u`: it is equivalent to :e:`u = v`. - -=============== -Further reading -=============== - -The `λProlog website `_ -contains useful links to λProlog related material. - -Papers and other documentation about Elpi can be found at -the `Elpi home on github `_. - -Three more tutorials specific to Elpi as an extension language for Coq -can be found in the `examples folder `_. -You can continue by reading the one about the -`HOAS for Coq terms `_. - -|*) - - diff --git a/examples/tutorial_elpi_lang.v b/examples/tutorial_elpi_lang.v new file mode 120000 index 000000000..bb686c312 --- /dev/null +++ b/examples/tutorial_elpi_lang.v @@ -0,0 +1 @@ +../tests/tutorial_elpi_lang.t/test.v \ No newline at end of file diff --git a/src/coq_elpi_arg_syntax.mlg b/src/coq_elpi_arg_syntax.mlg index c0b3f9af9..4536b9d38 100644 --- a/src/coq_elpi_arg_syntax.mlg +++ b/src/coq_elpi_arg_syntax.mlg @@ -136,6 +136,10 @@ let synterp_attribute : EA.phase option Attributes.attribute = | Attributes.VernacFlagLeaf (Attributes.FlagString "execution") -> Interp | Attributes.VernacFlagLeaf (Attributes.FlagString "both") -> Both | _ -> CErrors.user_err ?loc (Pp.str "Syntax error, use #[phase=\"parsing\"] or #[phase=\"execution\"] or #[phase=\"both\"]")) + ;"phases", + (fun ?loc old -> function + | Attributes.VernacFlagLeaf (Attributes.FlagString "both") -> Both + | _ -> CErrors.user_err ?loc (Pp.str "Syntax error, use #[phases=\"both\"]")) ;"synterp", (fun ?loc old -> function | Attributes.VernacFlagEmpty -> Synterp diff --git a/src/coq_elpi_builtins_arg_HOAS.ml b/src/coq_elpi_builtins_arg_HOAS.ml deleted file mode 100644 index bdc7098b9..000000000 --- a/src/coq_elpi_builtins_arg_HOAS.ml +++ /dev/null @@ -1,137 +0,0 @@ -(* Automatically generated from elpi/coq-arg-HOAS.elpi, don't edit *) -(* Regenerate via 'make src/coq_elpi_builtins_arg_HOAS.ml' *) -let code = {| -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-arg-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% This section contains the low level data types linking Coq and elpi. -% In particular the entry points for commands - - -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Entry points -% -% Command and tactic invocation -% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% Entry point for commands. Eg. "#[att=true] Elpi mycommand foo 3 (f x)." becomes -% main [str "foo", int 3, trm (app[f,x])] -% in a context where -% attributes [attribute "att" (leaf "true")] -% holds. The encoding of terms is described below. -% See also the coq.parse-attributes utility. -pred main i:list argument. -pred main-interp i:list argument, i:any. -pred main-synterp i:list argument, o:any. -pred usage. -pred attributes o:list attribute. - -% see coq-lib.elpi for coq.parse-attributes generating the options below -type get-option string -> A -> prop. - -% The data type of arguments (for commands or tactics) -kind argument type. -type int int -> argument. % Eg. 1 -2. -type str string -> argument. % Eg. x "y" z.w. or any Coq keyword/symbol -type trm term -> argument. % Eg. (t). - -% Extra arguments for commands. [Definition], [Axiom], [Record] and [Context] -% take precedence over the [str] argument above (when not "quoted"). -% -% Eg. Record or Inductive -type indt-decl indt-decl -> argument. -% Eg. #[universes(polymorphic,...)] Record or Inductive -type upoly-indt-decl indt-decl -> upoly-decl -> argument. -type upoly-indt-decl indt-decl -> upoly-decl-cumul -> argument. -% Eg. Definition or Axiom (when the body is none) -type const-decl id -> option term -> arity -> argument. -% Eg. #[universes(polymorphic,...)] Definition or Axiom -type upoly-const-decl id -> option term -> arity -> upoly-decl -> argument. -% Eg. Context A (b : A). -type ctx-decl context-decl -> argument. - -% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -kind indt-decl type. -kind indc-decl type. -kind record-decl type. - -% An arity is written, in Coq syntax, as: -% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U -% This syntax is used, for example, in the type of an inductive type or -% in the type of constructors. We call the abstractions on the left of ":" -% "parameters" while we call the type following the ":" (proper) arity. - -% Note: in some contexts, like the type of an inductive type constructor, -% Coq makes no distinction between these two writings -% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ... -% while Elpi is a bit more restrictive, since it understands user directives -% such as the implicit status of an arguments (eg, using {} instead of () around -% the binder), only on parameters. -% Moreover parameters carry the name given by the user as an "id", while binders -% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see -% also the HOAS of terms). A user command can hence only use the names of -% parameters, and not the names of "forall" quantified variables in the arity. -% -% See also the arity->term predicate in coq-lib.elpi - -type parameter id -> implicit_kind -> term -> (term -> arity) -> arity. -type arity term -> arity. - -type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl. -type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive -type record id -> term -> id -> record-decl -> indt-decl. - -type constructor id -> arity -> indc-decl. - -type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl. -type end-record record-decl. - -% Example. -% Remark that A is a regular parameter; y is a non-uniform parameter and t -% also features an index of type bool. -% -% Inductive t (A : Type) | (y : nat) : bool -> Type := -% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true -% | K2 : t A y false -% -% is written -% -% (parameter "A" explicit {{ Type }} a\ -% inductive "t" tt (parameter "y" explicit {{ nat }} _\ -% arity {{ bool -> Type }}) -% t\ -% [ constructor "K1" -% (parameter "y" explicit {{ nat }} y\ -% (parameter "x" explicit a x\ -% (parameter "n" maximal {{ nat }} n\ -% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }}))) -% , constructor "K2" -% (parameter "y" explicit {{ nat }} y\ -% arity {{ lp:t lp:y false }}) ]) -% -% Remark that the uniform parameters are not passed to occurrences of t, since -% they never change, while non-uniform parameters are both abstracted -% in each constructor type and passed as arguments to t. -% -% The coq.typecheck-indt-decl API can be used to fill in implicit arguments -% an infer universe constraints in the declaration above (e.g. the hidden -% argument of "=" in the arity of K1). -% -% Note: when and inductive type declaration is passed as an argument to an -% Elpi command non uniform parameters must be separated from the uniform ones -% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since -% version 1.4, in Coq this separator is optional, but not in Elpi). - -% Context declaration (used as an argument to Elpi commands) -kind context-decl type. -% Eg. (x : T) or (x := B), body is optional, type may be a variable -type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl. -type context-end context-decl. - -typeabbrev field-attributes (list field-attribute). - -macro @global! :- get-option "coq:locality" "global". -macro @local! :- get-option "coq:locality" "local". -|} diff --git a/src/coq_elpi_programs.ml b/src/coq_elpi_programs.ml index aa71fdf53..480038bca 100644 --- a/src/coq_elpi_programs.ml +++ b/src/coq_elpi_programs.ml @@ -663,7 +663,7 @@ let file_resolver = in aux None paths in let legacy_paths = - let build_dir = Coq_elpi_config.elpi_dir in + let build_dir = Filename.dirname Coq_elpi_config.elpi2html in let installed_dirs = let valid_dir d = try Sys.is_directory d with Sys_error _ -> false in let user_contrib = diff --git a/src/coq_elpi_vernacular.ml b/src/coq_elpi_vernacular.ml index 409dc6ca1..adec25691 100644 --- a/src/coq_elpi_vernacular.ml +++ b/src/coq_elpi_vernacular.ml @@ -657,7 +657,8 @@ let run_tactic_common loc ?(static_check=false) program ~main ?(atts=[]) () = | API.Execute.NoMoreSteps -> CErrors.user_err Pp.(str "elpi run out of steps") | API.Execute.Failure -> elpi_fails program | exception (Coq_elpi_utils.LtacFail (level, msg)) -> tclFAILn level msg - | exception e -> let e = Exninfo.capture e in (Feedback.msg_debug Pp.(str "elpi lets escape exception: " ++ CErrors.print (fst e)); Exninfo.iraise e)) + | exception (CErrors.UserError _ as e) -> let e = Exninfo.capture e in Exninfo.iraise e + | exception e when CErrors.noncritical e -> let e = Exninfo.capture e in (Feedback.msg_debug Pp.(str "elpi lets escape exception: " ++ CErrors.print (fst e)); Exninfo.iraise e)) tclIDTAC let run_tactic loc program ~atts _ist args = diff --git a/src/dune b/src/dune new file mode 100644 index 000000000..6729a32b2 --- /dev/null +++ b/src/dune @@ -0,0 +1,35 @@ +(library + (name elpi_plugin) + (public_name coq-elpi.elpi) + (synopsis "Elpi") + (flags :standard -w -27) + (libraries coq-core.plugins.ltac coq-core.vernac elpi)) + +(rule + (target coq_elpi_builtins_arg_HOAS.ml) + (deps ../elpi/coq-arg-HOAS.elpi) + (action (with-stdout-to %{target} + (progn + (echo "(* Automatically generated from %{deps}, don't edit *)\n") + (echo "let code = {|\n") + (cat %{deps}) + (echo "|}\n"))))) + +(rule + (target coq_elpi_builtins_HOAS.ml) + (deps ../elpi/coq-HOAS.elpi) + (action (with-stdout-to %{target} + (progn + (echo "(* Automatically generated from %{deps}, don't edit *)\n") + (echo "let code = {|\n") + (cat %{deps}) + (echo "|}\n"))))) + +(rule + (target coq_elpi_config.ml) + (action (with-stdout-to %{target} + (progn + (echo "let elpi2html = \"%{lib:elpi:elpi2html.elpi}\";;"))))) + +(coq.pp + (modules coq_elpi_vernacular_syntax coq_elpi_arg_syntax)) diff --git a/tests/API.t/run.t b/tests/API.t/run.t new file mode 100644 index 000000000..b7349f373 --- /dev/null +++ b/tests/API.t/run.t @@ -0,0 +1,121 @@ + $ . ../setup-project.sh + $ dune build test.vo + Coq version: 8.19.1 = 8 . 19 . 1 + Query assignments: + MA = 8 + MI = 19 + P = 1 + V = 8.19.1 + hello world + A + B + Query assignments: + GR = «nat» + Query assignments: + GR = «Nat.add» + MP = «Coq.Init.Datatypes» + Query assignments: + A = «test.test.succ» + GR = «Nat.add» + MP = «Coq.Init.Datatypes» + X1 = [loc-gref (const «Nat.add»)] + X2 = [loc-gref (const «Nat.add»)] + X3 = [loc-abbreviation «test.test.succ»] + X4 = [loc-modpath «Coq.Init.Datatypes»] + Universe constraints: + Query assignments: + X = «test.test.1» + Universe constraints: + UNIVERSES: + {test.test.1} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + X = typ «test.test.2» + Y = typ «test.test.3» + Universe constraints: + UNIVERSES: + {test.test.3 test.test.2} |= test.test.2 <= test.test.3 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + X = typ «test.test.4» + Y = typ «test.test.5» + Universe constraints: + UNIVERSES: + {test.test.5 test.test.4} |= test.test.4 <= test.test.5 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + X = typ «test.test.6» + Y = typ «test.test.7» + Z = typ «test.test.8» + Universe constraints: + UNIVERSES: + {test.test.8 test.test.7 test.test.6} |= + test.test.6 <= test.test.8 + test.test.7 <= test.test.8 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + X = typ «test.test.9» + Y = typ «test.test.10» + Universe constraints: + UNIVERSES: + {test.test.10 test.test.9} |= test.test.9 < test.test.10 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + [foo (const «X»), foo (indt «nat»), foo (indt «bool»)] + [foo (indt «nat»), foo (indt «bool»)] + [] + [foo (indt «nat»)] + hello [int 1, int 2, trm (global (indt «nat»)), str x] + coq.pp.box (coq.pp.hv 2) + [coq.pp.str Module, coq.pp.spc, coq.pp.str Foo, coq.pp.spc, coq.pp.str :=, + coq.pp.brk 1 0, coq.pp.str body, coq.pp.spc, coq.pp.str End Foo.] + Module + Foo + := + body + End Foo. + fix foo (x : ?e3) (y : ?e4) {struct x} : ?e2 := + match x as x0 return ?e6@{x:=x0} with + | true => S (S (S O)) + | false => y + end + fix foo x y {struct x} := if x as x0 return ?e14@{x:=x0} then 3 else y diff --git a/tests/test_API.v b/tests/API.t/test.v similarity index 100% rename from tests/test_API.v rename to tests/API.t/test.v diff --git a/tests/API2.t/run.t b/tests/API2.t/run.t new file mode 100644 index 000000000..64e73fe5e --- /dev/null +++ b/tests/API2.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_API is required + from root elpi and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 3, characters 0-27: + Error: Cannot find a physical path bound to logical path + test_API with prefix elpi. + + [1] diff --git a/tests/test_API2.v b/tests/API2.t/test.v similarity index 100% rename from tests/test_API2.v rename to tests/API2.t/test.v diff --git a/tests/API_TC_CS.t/run.t b/tests/API_TC_CS.t/run.t new file mode 100644 index 000000000..584ab8f91 --- /dev/null +++ b/tests/API_TC_CS.t/run.t @@ -0,0 +1,196 @@ + $ . ../setup-project.sh + $ dune build test.vo + ?r : Reflexive R + : Reflexive R + where + ?r : [ |- Reflexive R] + Query assignments: + GR = const «myi» + myi : Reflexive R + : Reflexive R + Query assignments: + L = [tc-instance (const «relation_equivalence_rewrite_relation») + (tc-priority-computed 0), + tc-instance (const «iff_rewrite_relation») (tc-priority-given 2), + tc-instance (const «impl_rewrite_relation») (tc-priority-given 3), + tc-instance (const «inverse_impl_rewrite_relation») (tc-priority-given 3), + tc-instance (const «Equivalence_PER») (tc-priority-given 10), + tc-instance (const «relation_equivalence_equivalence») + (tc-priority-computed 0), + tc-instance (const «predicate_equivalence_equivalence») + (tc-priority-computed 0), + tc-instance (const «iff_equivalence») (tc-priority-computed 0), + tc-instance (const «eq_equivalence») (tc-priority-given 10), + tc-instance (const «relation_implication_preorder») + (tc-priority-computed 0), + tc-instance (const «predicate_implication_preorder») + (tc-priority-computed 0), + tc-instance (const «Equivalence_PreOrder») (tc-priority-given 10), + tc-instance (const «Bool.Decidable_eq_bool») (tc-priority-computed 0), + tc-instance (const «DecidableClass.Decidable_not») + (tc-priority-computed 1), + tc-instance (const «subrelation_partial_order») (tc-priority-computed 0), + tc-instance (const «iff_Transitive») (tc-priority-computed 0), + tc-instance (const «impl_Transitive») (tc-priority-computed 0), + tc-instance (const «eq_Transitive») (tc-priority-computed 0), + tc-instance (const «Equivalence_Transitive») (tc-priority-computed 1), + tc-instance (const «StrictOrder_Transitive») (tc-priority-computed 1), + tc-instance (const «PreOrder_Transitive») (tc-priority-given 2), + tc-instance (const «PER_Transitive») (tc-priority-given 3), + tc-instance (const «StrictOrder_Irreflexive») (tc-priority-computed 1), + tc-instance (const «StrictOrder_Asymmetric») (tc-priority-computed 1), + tc-instance (const «iff_Reflexive») (tc-priority-computed 0), + tc-instance (const «impl_Reflexive») (tc-priority-computed 0), + tc-instance (const «eq_Reflexive») (tc-priority-computed 0), + tc-instance (const «Equivalence_Reflexive») (tc-priority-computed 1), + tc-instance (const «PreOrder_Reflexive») (tc-priority-given 2), + tc-instance (const «myi») (tc-priority-given 10), + tc-instance (const «partial_order_antisym») (tc-priority-computed 2), + tc-instance (const «iff_Symmetric») (tc-priority-computed 0), + tc-instance (const «neq_Symmetric») (tc-priority-computed 0), + tc-instance (const «eq_Symmetric») (tc-priority-computed 0), + tc-instance (const «Equivalence_Symmetric») (tc-priority-computed 1), + tc-instance (const «PER_Symmetric») (tc-priority-given 3)] + Query assignments: + GR = indt «RewriteRelation» + L = [tc-instance (const «relation_equivalence_rewrite_relation») + (tc-priority-computed 0), + tc-instance (const «iff_rewrite_relation») (tc-priority-given 2), + tc-instance (const «impl_rewrite_relation») (tc-priority-given 3), + tc-instance (const «inverse_impl_rewrite_relation») (tc-priority-given 3)] + Query assignments: + GR = indt «RewriteRelation» + Query assignments: + GR = indt «True» + Query assignments: + GR = const «myc» + eq_op myc t t + : bool + Query assignments: + L = [cs-instance (const «carrier») (cs-gref (const «W»)) (const «myc»), + cs-instance (const «eq_op») (cs-gref (const «Z»)) (const «myc»)] + Query assignments: + I = «eq» + P1 = «carrier» + P2 = «eq_op» + Query assignments: + GR = const «myc1» + eq_op myc1 t1 t1 + : bool + Query assignments: + P = const «eq_op» + Query assignments: + W = const «W» + [cs-instance (const «eq_op») (cs-gref (const «Z1»)) (const «myc1»)] + Query assignments: + L = [cs-instance (const «eq_op») (cs-gref (const «Z1»)) (const «myc1»)] + P = const «eq_op» + W = const «Z1» + Query assignments: + P = const «eq_op» + W = indt «nat» + Query assignments: + C1 = const «C1» + GR1 = const «c12» + GR2 = const «c1t» + GR3 = const «c1f» + fun x : C1 => x : C2 + : C1 -> C2 + fun (x : C1) (_ : x) => true + : forall x : C1, x -> bool + fun x : C1 => x 3 + : C1 -> nat + Query assignments: + L = [coercion (const «c1t») 0 (const «C1») sortclass, + coercion (const «c1f») 0 (const «C1») funclass, + coercion (const «c12») 0 (const «C1») (grefclass (const «C2»)), + coercion (const «reverse_coercion») 3 (const «ReverseCoercionSource») + (grefclass (const «ReverseCoercionTarget»))] + Query assignments: + Spilled_1 = const «nuc» + nuc : forall x : nat, C1 -> C3 x + + nuc is not universe polymorphic + Arguments nuc x%nat_scope _ + nuc is a reversible coercion + Expands to: Constant test.test.nuc + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (equiv_rewrite_relation R) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_StrictOrder) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_PreOrder) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @PartialOrder_inverse) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @subrelation_symmetric) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_Transitive) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_Irreflexive) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @complement_Irreflexive) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_Asymmetric) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @irreflexivity) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (apply flip_Reflexive) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) unconvertible + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_Antisymmetric) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @flip_Symmetric) + [TC.hints,elpi,default] + File "./test.v", line 24, characters 0-30: + Warning: + There is an hint extern in the typeclass db: + (*external*) (class_apply @complement_Symmetric) + [TC.hints,elpi,default] + File "./test.v", line 25, characters 0-70: + Warning: + There is an hint extern in the typeclass db: + (*external*) (equiv_rewrite_relation R) + [TC.hints,elpi,default] diff --git a/tests/test_API_TC_CS.v b/tests/API_TC_CS.t/test.v similarity index 100% rename from tests/test_API_TC_CS.v rename to tests/API_TC_CS.t/test.v diff --git a/tests/API_arguments.t/run.t b/tests/API_arguments.t/run.t new file mode 100644 index 000000000..8e74368c7 --- /dev/null +++ b/tests/API_arguments.t/run.t @@ -0,0 +1,42 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query assignments: + I = const «imp» + X2.imp : forall (T : Type) (x : T), x = x -> Prop + + X2.imp is not universe polymorphic + Arguments X2.imp T%type_scope x _ + Expands to: Constant test.test.X2.imp + Query assignments: + Spilled_1 = const «foo» + foo 3 + : nat + Query assignments: + Spilled_1 = const «f» + Spilled_2 = const «f» + Spilled_3 = const «f» + Spilled_4 = const «f» + Spilled_5 = const «f» + f : forall [S : Type], S -> Prop + + f is not universe polymorphic + Arguments f [S]%type_scope _ + (where some original arguments have been renamed) + f is transparent + Expands to: Constant test.test.f + f (S:=bool * bool) + : bool * bool -> Prop + Query assignments: + Spilled_1 = const «f» + f : forall [S : Type], S -> Prop + + f is not universe polymorphic + Arguments f [S]%type_scope / _ + (where some original arguments have been renamed) + The reduction tactics unfold f when applied to 1 argument + f is transparent + Expands to: Constant test.test.f + f (S:=bool * bool) + : bool * bool -> Prop + = fun x : bool => x = x + : bool -> Prop diff --git a/tests/test_API_arguments.v b/tests/API_arguments.t/test.v similarity index 100% rename from tests/test_API_arguments.v rename to tests/API_arguments.t/test.v diff --git a/tests/API_elaborate.t/run.t b/tests/API_elaborate.t/run.t new file mode 100644 index 000000000..f2e0c6ffd --- /dev/null +++ b/tests/API_elaborate.t/run.t @@ -0,0 +1,193 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query assignments: + E = fun `n` (global (indt «nat»)) c0 \ + fun `t` (app [global (const «T2»), c0]) c1 \ + fun `x` + (app [global (const «f3»), c0, app [global (const «h»), c0, c1]]) c2 \ + app + [global (const «g3»), c0, app [global (const «h»), c0, c1], + app + [global (indc «S»), + app + [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]] + TY = prod `n` (global (indt «nat»)) c0 \ + prod `t` (app [global (const «T2»), c0]) c1 \ + prod `x` + (app [global (const «f3»), c0, app [global (const «h»), c0, c1]]) c2 \ + global (indt «nat») + _uvk_1_ = X0 + Universe constraints: + UNIVERSES: + {test.test.13 test.test.10 test.test.9} |= + test.test.13 < test.test.9 + Set <= test.test.10 + Set <= test.test.13 + T2.u0 <= test.test.13 + f3.u0 <= test.test.13 + ALGEBRAIC UNIVERSES: + {test.test.10} + FLEXIBLE UNIVERSES: + test.test.10 + SORTS: + α4 := Type + α5 := Type + WEAK CONSTRAINTS: + + + Query assignments: + E = app + [global (const «bar»), + app + [global (indc «S»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]], + global (const «xxx»)] + TY = prop + _uvk_4_ = X0 + _uvk_5_ = X1 + Query assignments: + E = app + [global (const «op»), global (const «c»), + app + [global (indc «S»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]] + TY = app [global (const «field»), global (const «c»)] + _uvk_6_ = X0 + Universe constraints: + UNIVERSES: + {test.test.19 test.test.18} |= + test.test.19 < test.test.18 + s.u0 <= test.test.19 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α11 := Type + WEAK CONSTRAINTS: + + + raw: + parameter A explicit (global (const «T1»)) c0 \ + inductive ind1 tt + (parameter B explicit (sort (typ «test.test.20»)) c1 \ + arity (sort (typ «test.test.22»))) c1 \ + [constructor K1 + (parameter B explicit (sort (typ «test.test.20»)) c2 \ + arity (prod `_` (app [c1, c2]) c3 \ app [c1, c2])), + constructor K2 + (parameter B explicit (sort (typ «test.test.20»)) c2 \ + arity (prod `_` (app [global (const «f1»), c0]) c3 \ app [c1, c2])), + constructor K3 + (parameter B explicit (sort (typ «test.test.20»)) c2 \ + arity (prod `a` (app [global (const «f1»), c0]) c3 \ app [c1, c2]))] + elab1: + parameter A explicit (global (const «T1»)) c0 \ + inductive ind1 tt + (parameter B explicit (sort (typ «test.test.23»)) c1 \ + arity (sort (typ «test.test.25»))) c1 \ + [constructor K1 + (parameter B explicit (sort (typ «test.test.28»)) c2 \ + arity (prod `_` (app [c1, c2]) c3 \ app [c1, c2])), + constructor K2 + (parameter B explicit (sort (typ «test.test.30»)) c2 \ + arity (prod `_` (app [global (const «f1»), c0]) c3 \ app [c1, c2])), + constructor K3 + (parameter B explicit (sort (typ «test.test.33»)) c2 \ + arity (prod `a` (app [global (const «f1»), c0]) c3 \ app [c1, c2]))] + elab2: + parameter A explicit (global (const «T1»)) c0 \ + parameter B explicit (sort (typ «ind1.u0»)) c1 \ + inductive ind1 tt (arity (sort (typ «ind1.u1»))) c2 \ + [constructor K1 (arity (prod `_` c2 c3 \ c2)), + constructor K2 + (arity (prod `_` (app [global (const «f1»), c0]) c3 \ c2)), + constructor K3 + (arity (prod `a` (app [global (const «f1»), c0]) c3 \ c2))] + raw: + parameter A explicit (global (const «T1»)) c0 \ + record ind2 (sort (typ «f1.u0»)) Build_ind2 + (field [coercion off, canonical tt] fld1 (app [global (const «f1»), c0]) + c1 \ + field [coercion off, canonical tt] fld2 + (app [global (indt «eq»), app [global (const «f1»), c0], c1, c1]) + c2 \ end-record) + elab1: + parameter A explicit (global (const «T1»)) c0 \ + record ind2 (sort (typ «test.test.38»)) Build_ind2 + (field [coercion off, canonical tt] fld1 (app [global (const «f1»), c0]) + c1 \ + field [coercion off, canonical tt] fld2 + (app [global (indt «eq»), app [global (const «f1»), c0], c1, c1]) + c2 \ end-record) + elab2: + parameter A explicit (global (const «T1»)) c0 \ + record ind2 (sort (typ «ind2.u0»)) Build_ind2 + (field [coercion off, canonical tt] fld1 (app [global (const «f1»), c0]) + c1 \ + field [coercion off, canonical tt] fld2 + (app [global (indt «eq»), app [global (const «f1»), c0], c1, c1]) + c2 \ end-record) + raw: + record ind3 (sort (typ «test.test.41»)) Build_ind3 + (field [coercion reversible, canonical tt] fld3 + (sort (typ «test.test.40»)) c0 \ + field [coercion off, canonical tt] fld4 + (prod `x` c0 c1 \ app [global (indt «eq»), c0, c1, c1]) c1 \ end-record) + elab1: + record ind3 (sort (typ «test.test.42»)) Build_ind3 + (field [coercion reversible, canonical tt] fld3 + (sort (typ «test.test.43»)) c0 \ + field [coercion off, canonical tt] fld4 + (prod `x` c0 c1 \ app [global (indt «eq»), c0, c1, c1]) c1 \ end-record) + elab2: + record ind3 (sort (typ «ind3.u0»)) Build_ind3 + (field [coercion reversible, canonical tt] fld3 (sort (typ «ind3.u1»)) + c0 \ + field [coercion off, canonical tt] fld4 + (prod `x` c0 c1 \ app [global (indt «eq»), c0, c1, c1]) c1 \ end-record) + forall x : ind3, x -> Prop + : Type + Query assignments: + E = app + [global (const «op»), global (const «c»), + app + [global (indc «S»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]] + TY = app [global (const «field»), global (const «c»)] + Universe constraints: + UNIVERSES: + {test.test.50 test.test.49} |= + test.test.50 < test.test.49 + s.u0 <= test.test.50 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α19 := Type + WEAK CONSTRAINTS: + + + unknown_gref + «test.test.52» «test.test.52» + Query assignments: + E = app [global (indt «list»), global (const «C»)] + TY = sort (typ «test.test.58») + Universe constraints: + UNIVERSES: + {test.test.59 test.test.58 test.test.57} |= + test.test.58 < test.test.59 + test.test.59 < test.test.57 + Set <= test.test.58 + test.test.56 <= list.u0 + test.test.56 <= test.test.58 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α22 := Type + WEAK CONSTRAINTS: + + diff --git a/tests/test_API_elaborate.v b/tests/API_elaborate.t/test.v similarity index 100% rename from tests/test_API_elaborate.v rename to tests/API_elaborate.t/test.v diff --git a/tests/API_env.t/run.t b/tests/API_env.t/run.t new file mode 100644 index 000000000..2c0b97b61 --- /dev/null +++ b/tests/API_env.t/run.t @@ -0,0 +1,1834 @@ + $ . ../setup-project.sh + $ dune build test.vo 2>&1 | sed 's/T = [0-9]*\.[0-9]*/T = __TIME__/g' + Query assignments: + BO = fix `add` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]] + GR = «Nat.add» + GRNat = indt «nat» + GRSucc = indc «S» + Nat = global (indt «nat») + Succ = global (indc «S») + TY = prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat») + Query assignments: + GR = «empty_nat» + TY = global (indt «nat») + Query assignments: + GR1 = indc «Vector.nil» + GR2 = indt «nat» + GR3 = const «A» + add_equal + Query assignments: + BO = fix `add` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]] + GR = «Nat.add» + NGR = «add_equal» + Name = add_equal + S = add + Spilled_1 = add_equal + Spilled_2 = add_equal + TY = prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat») + add_equal : nat -> nat -> nat + + add_equal is not universe polymorphic + Arguments add_equal (n m)%nat_scope + add_equal is opaque + Expands to: Constant test.test.add_equal + «myfalse» + Query assignments: + F = indt «False» + GR = «myfalse» + myfalse + : False + parameter T X0 (sort (typ X1)) c0 \ + record eq_class (sort (typ X2)) mk_eq_class + (field [canonical ff, coercion regular] eq_f (global (indt «bool»)) c1 \ + field X3 eq_proof + (app [global (indt «eq»), global (indt «bool»), c1, c1]) c2 \ + end-record) + Query assignments: + DECL = parameter T X0 (sort (typ «eq_class.u0»)) c0 \ + record eq_class (sort (typ «eq_class.u1»)) mk_eq_class + (field [canonical ff, coercion regular] eq_f (global (indt «bool»)) c1 \ + field X3 eq_proof + (app [global (indt «eq»), global (indt «bool»), c1, c1]) c2 \ + end-record) + GR = «eq_class» + _uvk_1_ = «eq_class.u0» + _uvk_2_ = «eq_class.u1» + Universe constraints: + UNIVERSES: + + ALGEBRAIC UNIVERSES: + {eq_class.u1 eq_class.u0} + FLEXIBLE UNIVERSES: + eq_class.u1 + eq_class.u0 + SORTS: + + WEAK CONSTRAINTS: + + + Record eq_class (T : Type@{eq_class.u0}) : Type@{eq_class.u1} := mk_eq_class + { eq_f : bool; eq_proof : eq_f = eq_f }. + + Arguments eq_class T%type_scope + Arguments mk_eq_class T%type_scope eq_f%bool_scope eq_proof + fun x : eq_class nat => x : bool + : eq_class nat -> bool + p <- eq_proof ( xxx ) + Query assignments: + DECL = parameter T X0 (sort (typ «prim_eq_class.u0»)) c0 \ + record prim_eq_class (sort (typ «prim_eq_class.u1»)) mk_prim_eq_class + (field [canonical ff, coercion reversible] prim_eq_f + (global (indt «bool»)) c1 \ + field X1 prim_eq_proof + (app [global (indt «eq»), global (indt «bool»), c1, c1]) c2 \ + end-record) + GR = «prim_eq_class» + _uvk_3_ = «prim_eq_class.u0» + _uvk_4_ = «prim_eq_class.u1» + Universe constraints: + UNIVERSES: + + ALGEBRAIC UNIVERSES: + {prim_eq_class.u1 prim_eq_class.u0} + FLEXIBLE UNIVERSES: + prim_eq_class.u1 + prim_eq_class.u0 + SORTS: + + WEAK CONSTRAINTS: + + + fun r : prim_eq_class nat => + eq_refl : r = {| prim_eq_f := r; prim_eq_proof := prim_eq_proof _ r |} + : forall r : prim_eq_class nat, + r = {| prim_eq_f := r; prim_eq_proof := prim_eq_proof _ r |} + (* {} |= prim_eq_class.u1 <= eq.u0 *) + fun `r` (app [global (indt «prim_eq_class»), global (indt «nat»)]) c0 \ + app [primitive (proj test.test.prim_eq_f 1), c0] + Query assignments: + C = «pc» + Universe constraints: + UNIVERSES: + + ALGEBRAIC UNIVERSES: + {myind.u0} + FLEXIBLE UNIVERSES: + myind.u0 + SORTS: + + WEAK CONSTRAINTS: + + + myind true false : Prop + : Prop + K2 true : myind true true + : myind true true + myind1 true false : Prop + : Prop + K21 true : myind1 true true + : myind1 true true + Query assignments: + _uvk_6_ = «nuind.u0» + _uvk_7_ = «nuind.u1» + Universe constraints: + UNIVERSES: + + ALGEBRAIC UNIVERSES: + {nuind.u1 nuind.u0} + FLEXIBLE UNIVERSES: + nuind.u1 + nuind.u0 + SORTS: + + WEAK CONSTRAINTS: + + + fun x : nuind nat 3 false => + match x in (nuind _ _ b) return (b = b) with + | k1 _ _ => eq_refl : true = true + | k2 _ _ x0 => (fun _ : nuind nat 1 false => eq_refl : false = false) x0 + end + : nuind nat 3 false -> false = false + c0 global (indt «nat») + Query assignments: + T = global (indt «nat») + Query assignments: + D = parameter A X0 (sort (typ «tx.u0»)) c0 \ + inductive tx X1 + (parameter y X2 (global (indt «nat»)) c1 \ + arity (prod `_` (global (indt «bool»)) c2 \ sort (typ «tx.u1»))) c1 \ + [constructor K1x + (parameter y X3 (global (indt «nat»)) c2 \ + arity + (prod `x` c0 c3 \ + prod `n` (global (indt «nat»)) c4 \ + prod `p` + (app + [global (indt «eq»), global (indt «nat»), + app [global (indc «S»), c4], c2]) c5 \ + prod `e` (app [c1, c4, global (indc «true»)]) c6 \ + app [c1, c2, global (indc «true»)])), + constructor K2x + (parameter y X4 (global (indt «nat»)) c2 \ + arity (app [c1, c2, global (indc «false»)]))] + _uvk_8_ = «tx.u0» + _uvk_9_ = «tx.u1» + Universe constraints: + UNIVERSES: + {test.test.18 test.test.17 test.test.16 test.test.15 test.test.14 + test.test.13 test.test.11} |= + tx.u0 < test.test.11 + tx.u1 < test.test.13 + Set <= eq.u0 + Set <= test.test.13 + Set <= test.test.14 + Set <= test.test.15 + Set <= test.test.16 + Set <= test.test.17 + Set <= test.test.18 + tx.u0 <= test.test.14 + tx.u1 <= test.test.14 + test.test.14 <= tx.u1 + ALGEBRAIC UNIVERSES: + {tx.u1 tx.u0} + FLEXIBLE UNIVERSES: + tx.u1 + tx.u0 + SORTS: + α2 := Type + α3 := Type + α4 := Type + α5 := Type + WEAK CONSTRAINTS: + + + Query assignments: + D = parameter A explicit (sort (typ «test.test.20»)) c0 \ + parameter a explicit c0 c1 \ + inductive ind1 tt + (parameter B explicit (sort (typ «ind1.u0»)) c2 \ + parameter b explicit c2 c3 \ + arity + (prod `C` (sort (typ «test.test.22»)) c4 \ + prod `_` c4 c5 \ sort (typ «test.test.26»))) c2 \ + [constructor k1 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + arity + (prod `bb` (app [global (indt «prod»), c3, c3]) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c5, + global (indt «bool»), global (indc «true»)]) c6 \ + app [c2, c3, c4, global (indt «unit»), global (indc «tt»)])), + constructor k2 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + arity + (app + [c2, c3, c4, global (indt «nat»), + app [global (indc «S»), global (indc «O»)]]))] + D1 = parameter A explicit (sort (typ «test.test.20»)) c0 \ + parameter a explicit c0 c1 \ + inductive ind1 tt + (parameter B explicit (sort (typ «ind1.u0»)) c2 \ + parameter b explicit c2 c3 \ + arity + (prod `C` (sort (typ «test.test.22»)) c4 \ + prod `_` c4 c5 \ sort (typ «test.test.26»))) c2 \ + [constructor k1 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + arity + (prod `bb` (app [global (indt «prod»), c3, c3]) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c5, + global (indt «bool»), global (indc «true»)]) c6 \ + app [c2, c3, c4, global (indt «unit»), global (indc «tt»)])), + constructor k2 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + arity + (app + [c2, c3, c4, global (indt «nat»), + app [global (indc «S»), global (indc «O»)]]))] + I = «ind1» + U = «test.test.26» + UA = «test.test.20» + UB1 = «ind1.u0» + UB2 = «ind1.u0» + UB3 = «ind1.u0» + UC = «test.test.22» + Universe constraints: + UNIVERSES: + {test.test.26} |= Set <= test.test.26 + ind1.u0 <= test.test.26 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + D = parameter A explicit (sort (typ «test.test.20»)) c0 \ + parameter a explicit c0 c1 \ + inductive ind1 tt + (parameter B explicit (sort (typ «ind1.u0»)) c2 \ + parameter b explicit c2 c3 \ + arity + (prod `C` (sort (typ «test.test.22»)) c4 \ + prod `_` c4 c5 \ sort (typ «test.test.27»))) c2 \ + [constructor k1 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + parameter bb implicit (app [global (indt «prod»), c3, c3]) c5 \ + arity + (prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c5, + global (indt «bool»), global (indc «true»)]) c6 \ + app [c2, c3, c4, global (indt «unit»), global (indc «tt»)])), + constructor k2 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + arity + (app + [c2, c3, c4, global (indt «nat»), + app [global (indc «S»), global (indc «O»)]]))] + D1 = parameter A explicit (sort (typ «test.test.20»)) c0 \ + parameter a explicit c0 c1 \ + inductive ind1 tt + (parameter B explicit (sort (typ «ind1.u0»)) c2 \ + parameter b explicit c2 c3 \ + arity + (prod `C` (sort (typ «test.test.22»)) c4 \ + prod `_` c4 c5 \ sort (typ «test.test.27»))) c2 \ + [constructor k1 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + parameter bb implicit (app [global (indt «prod»), c3, c3]) c5 \ + arity + (prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c5, + global (indt «bool»), global (indc «true»)]) c6 \ + app [c2, c3, c4, global (indt «unit»), global (indc «tt»)])), + constructor k2 + (parameter B explicit (sort (typ «ind1.u0»)) c3 \ + parameter b explicit c3 c4 \ + arity + (app + [c2, c3, c4, global (indt «nat»), + app [global (indc «S»), global (indc «O»)]]))] + I = «ind1» + U = «test.test.27» + UA = «test.test.20» + UB1 = «ind1.u0» + UB2 = «ind1.u0» + UB3 = «ind1.u0» + UC = «test.test.22» + Universe constraints: + UNIVERSES: + {test.test.27} |= Set <= test.test.27 + ind1.u0 <= test.test.27 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + D = parameter P explicit (sort (typ «r1.u0»)) c0 \ + parameter p explicit c0 c1 \ + record r1 (sort (typ «r1.u0»)) mk_r1 + (field [coercion reversible, canonical tt] f1 (prod `_` c0 c2 \ c0) c2 \ + field [coercion off, canonical ff] f2 + (app [global (indt «eq»), c0, c1, app [c2, c1]]) c3 \ end-record) + D1 = parameter P explicit (sort (typ «r1.u0»)) c0 \ + parameter p explicit c0 c1 \ + record r1 (sort (typ «r1.u0»)) mk_r1 + (field [coercion reversible, canonical tt] f1 (prod `_` c0 c2 \ c0) c2 \ + field [coercion off, canonical ff] f2 + (app [global (indt «eq»), c0, c1, app [c2, c1]]) c3 \ end-record) + I = «r1» + UP = «r1.u0» + UR = «r1.u0» + Query assignments: + D = parameter P explicit (sort (typ «r1.u0»)) c0 \ + parameter p explicit c0 c1 \ + record r1 (sort (typ «r1.u0»)) mk_r1 + (field [coercion reversible, canonical tt] f1 (prod `_` c0 c2 \ c0) c2 \ + field [coercion regular, canonical ff] f2 + (app [global (indt «eq»), c0, c1, app [c2, c1]]) c3 \ end-record) + D1 = parameter P explicit (sort (typ «r1.u0»)) c0 \ + parameter p explicit c0 c1 \ + record r1 (sort (typ «r1.u0»)) mk_r1 + (field [coercion reversible, canonical tt] f1 (prod `_` c0 c2 \ c0) c2 \ + field [coercion regular, canonical ff] f2 + (app [global (indt «eq»), c0, c1, app [c2, c1]]) c3 \ end-record) + I = «r1» + UP = «r1.u0» + UR = «r1.u0» + {{ nat; S; }} + {{ nat; S; }} + Query assignments: + GR = const «Nat.add» + L = {{ nat; S; }} + S = {{ nat; S; }} + {{ X.a; }} {{ X.a; Nat.add; nat; }} + {{ X.a; }} {{ X.a; Nat.add; nat; O; S; }} + Query assignments: + AllL = {{ X.a; Nat.add; nat; }} + AllS = {{ X.a; Nat.add; nat; O; S; }} + GR = const «X.b» + L = {{ X.a; }} + M = «test.test.HOAS.X» + S = {{ X.a; }} + Spilled_1 = const «X.a» + Query assignments: + GR = const «Ranalysis5.derivable_pt_lim_CVU» + S = {{ Field_theory.AF_1_neq_0; Field_theory.AF_AR; Field_theory.AFdiv_def; + Field_theory.AFinv_l; Ring_theory.ARadd_0_l; Ring_theory.ARadd_0_r; + Ring_theory.ARadd_assoc; Ring_theory.ARadd_assoc1; + Ring_theory.ARadd_assoc2; Ring_theory.ARadd_comm; Ring_theory.ARdistr_l; + Ring_theory.ARdistr_r; InitialRing.ARgen_phiPOS_Psucc; + InitialRing.ARgen_phiPOS_add; InitialRing.ARgen_phiPOS_mult; + Ring_theory.ARmul_0_l; Ring_theory.ARmul_0_r; Ring_theory.ARmul_1_l; + Ring_theory.ARmul_1_r; Ring_theory.ARmul_assoc; + Ring_theory.ARmul_assoc1; Ring_theory.ARmul_assoc2; + Ring_theory.ARmul_comm; Ring_theory.ARopp_add; Ring_theory.ARopp_mul_l; + Ring_theory.ARopp_mul_r; Ring_theory.ARopp_zero; Ring_theory.ARsub_def; + Ring_theory.ARsub_ext; Ring_theory.ARth_SRth; RList.AbsList; + RList.AbsList_P1; RList.AbsList_P2; Acc_inv; + Morphisms_Prop.Acc_pt_morphism; Acc_rect; Tauto.BFormula; + PSeries_reg.Ball_in_inter; Rlimit.Base; PSeries_reg.Boule; + PSeries_reg.Boule_center; Setoid.Build_Setoid_Theory; + Ring_polynom.CFactor; RMicromega.CInvR0; RMicromega.CPowR0; + ConstructiveReals.CR_Q_dense; ConstructiveReals.CR_archimedean; + ConstructiveReals.CR_cauchy; ConstructiveReals.CR_complete; + ConstructiveReals.CR_cv; ConstructiveLimits.CR_cv_bound_down; + ConstructiveLimits.CR_cv_le; ConstructiveLimits.CR_cv_open_above; + ConstructiveLimits.CR_cv_open_below; ConstructiveLimits.CR_cv_opp; + ConstructiveLimits.CR_cv_plus; ConstructiveLimits.CR_cv_proper; + ConstructiveReals.CR_of_Q; ConstructiveReals.CR_of_Q_le; + ConstructiveReals.CR_of_Q_lt; ConstructiveReals.CR_of_Q_morph; + ConstructiveReals.CR_of_Q_morph_Proper; + ConstructiveReals.CR_of_Q_morph_T; ConstructiveReals.CR_of_Q_mult; + ConstructiveReals.CR_of_Q_opp; ConstructiveReals.CR_of_Q_plus; + ConstructiveReals.CR_of_Q_pos; ConstructiveLUB.CR_sig_lub; + ConstructiveReals.CRabs; ConstructiveReals.CRabs_def; + ConstructiveAbs.CRabs_le; ConstructiveAbs.CRabs_lt; + ConstructiveAbs.CRabs_morph; ConstructiveAbs.CRabs_morph_prop_Proper; + ConstructiveAbs.CRabs_opp; ConstructiveAbs.CRabs_right; + ConstructiveAbs.CRabs_triang; ConstructiveReals.CRapart; + ConstructiveReals.CRcarrier; ConstructiveRcomplete.CRealAbsLUB; + ConstructiveCauchyRealsMult.CRealArchimedean; + ConstructiveRcomplete.CRealComplete; + ConstructiveRcomplete.CRealConstructive; + ConstructiveCauchyReals.CRealEq; ConstructiveCauchyReals.CRealEq_diff; + ConstructiveCauchyReals.CRealEq_refl; + ConstructiveCauchyReals.CRealEq_rel; + ConstructiveCauchyReals.CRealEq_relT; + ConstructiveCauchyReals.CRealEq_rel_Reflexive; + ConstructiveCauchyReals.CRealEq_rel_Symmetric; + ConstructiveCauchyReals.CRealEq_rel_Transitive; + ConstructiveCauchyReals.CRealEq_sym; + ConstructiveCauchyReals.CRealEq_trans; ConstructiveCauchyReals.CRealGe; + ConstructiveCauchyReals.CRealLe; + ConstructiveCauchyAbs.CRealLe_0R_to_single_dist; + ConstructiveCauchyReals.CRealLe_morph_Proper; + ConstructiveCauchyReals.CRealLe_not_lt; + ConstructiveCauchyReals.CRealLe_refl; + ConstructiveCauchyRealsMult.CRealLowerBound; + ConstructiveCauchyRealsMult.CRealLowerBoundSpec; + ConstructiveCauchyRealsMult.CRealLowerBound_lt_scale; + ConstructiveCauchyReals.CRealLt; + ConstructiveRcomplete.CRealLtDisjunctEpsilon; + ConstructiveCauchyReals.CRealLtEpsilon; + ConstructiveCauchyReals.CRealLtForget; + ConstructiveRcomplete.CRealLtIsLinear; + ConstructiveCauchyReals.CRealLtProp; + ConstructiveCauchyReals.CRealLtProp_morph_Proper; + ConstructiveCauchyReals.CRealLt_0_1; + ConstructiveCauchyAbs.CRealLt_RQ_from_single_dist; + ConstructiveCauchyReals.CRealLt_above; + ConstructiveCauchyReals.CRealLt_aboveSig; + ConstructiveCauchyReals.CRealLt_aboveSig'; + ConstructiveCauchyReals.CRealLt_above_same; + ConstructiveCauchyReals.CRealLt_asym; + ConstructiveCauchyReals.CRealLt_dec; + ConstructiveCauchyReals.CRealLt_irrefl; + ConstructiveCauchyReals.CRealLt_lpo_dec; + ConstructiveCauchyReals.CRealLt_morph; + ConstructiveCauchyRealsMult.CRealQ_dense; + ConstructiveCauchyRealsMult.CRealRing_ring_lemma1; + ConstructiveCauchyRealsMult.CRealRing_ring_lemma2; + ConstructiveCauchyAbs.CReal_abs; + ConstructiveCauchyAbs.CReal_abs_appart_0; + ConstructiveCauchyAbs.CReal_abs_bound; + ConstructiveCauchyAbs.CReal_abs_cauchy; + ConstructiveCauchyAbs.CReal_abs_def2; + ConstructiveCauchyAbs.CReal_abs_le; + ConstructiveCauchyAbs.CReal_abs_left; + ConstructiveCauchyAbs.CReal_abs_minus_sym; + ConstructiveCauchyAbs.CReal_abs_morph; + ConstructiveCauchyAbs.CReal_abs_morph_Proper; + ConstructiveCauchyAbs.CReal_abs_opp; + ConstructiveCauchyAbs.CReal_abs_pos; + ConstructiveCauchyAbs.CReal_abs_right; + ConstructiveCauchyAbs.CReal_abs_scale; + ConstructiveCauchyAbs.CReal_abs_seq; + ConstructiveCauchyAbs.CReal_abs_triang; + ConstructiveCauchyReals.CReal_appart; + ConstructiveRcomplete.CReal_cv_self'; + ConstructiveRcomplete.CReal_from_cauchy; + ConstructiveRcomplete.CReal_from_cauchy_bound; + ConstructiveRcomplete.CReal_from_cauchy_cauchy; + ConstructiveRcomplete.CReal_from_cauchy_cm; + ConstructiveRcomplete.CReal_from_cauchy_cm_mono; + ConstructiveRcomplete.CReal_from_cauchy_scale; + ConstructiveRcomplete.CReal_from_cauchy_seq; + ConstructiveRcomplete.CReal_from_cauchy_seq_bound; + ConstructiveCauchyRealsMult.CReal_inv; + ConstructiveCauchyRealsMult.CReal_inv_0_lt_compat; + ConstructiveCauchyRealsMult.CReal_inv_l; + ConstructiveCauchyRealsMult.CReal_inv_l_pos; + ConstructiveCauchyRealsMult.CReal_inv_pos; + ConstructiveCauchyRealsMult.CReal_inv_pos_bound; + ConstructiveCauchyRealsMult.CReal_inv_pos_cauchy; + ConstructiveCauchyRealsMult.CReal_inv_pos_cm; + ConstructiveCauchyRealsMult.CReal_inv_pos_scale; + ConstructiveCauchyRealsMult.CReal_inv_pos_seq; + ConstructiveCauchyRealsMult.CReal_isRing; + ConstructiveCauchyRealsMult.CReal_isRingExt; + ConstructiveCauchyAbs.CReal_le_abs; + ConstructiveCauchyReals.CReal_le_lt_trans; + ConstructiveCauchyReals.CReal_le_trans; + ConstructiveCauchyReals.CReal_lt_le_trans; + ConstructiveCauchyReals.CReal_lt_trans; + ConstructiveCauchyReals.CReal_minus; + ConstructiveCauchyRealsMult.CReal_mult; + ConstructiveCauchyRealsMult.CReal_mult_1_l; + ConstructiveCauchyRealsMult.CReal_mult_assoc; + ConstructiveCauchyRealsMult.CReal_mult_bound; + ConstructiveCauchyRealsMult.CReal_mult_cauchy; + ConstructiveCauchyRealsMult.CReal_mult_comm; + ConstructiveCauchyRealsMult.CReal_mult_lt_0_compat; + ConstructiveCauchyRealsMult.CReal_mult_lt_0_compat_correct; + ConstructiveCauchyRealsMult.CReal_mult_lt_compat_l; + ConstructiveCauchyRealsMult.CReal_mult_morph_Proper; + ConstructiveCauchyRealsMult.CReal_mult_plus_distr_l; + ConstructiveCauchyRealsMult.CReal_mult_proper_0_l; + ConstructiveCauchyRealsMult.CReal_mult_proper_l; + ConstructiveCauchyRealsMult.CReal_mult_scale; + ConstructiveCauchyRealsMult.CReal_mult_seq; + ConstructiveCauchyRealsMult.CReal_neg_lt_pos; + ConstructiveCauchyRealsMult.CReal_neg_lt_pos_subproof; + ConstructiveCauchyReals.CReal_opp; ConstructiveCauchyReals.CReal_opp_0; + ConstructiveCauchyReals.CReal_opp_bound; + ConstructiveCauchyReals.CReal_opp_cauchy; + ConstructiveCauchyReals.CReal_opp_ge_le_contravar; + ConstructiveCauchyReals.CReal_opp_involutive; + ConstructiveCauchyRealsMult.CReal_opp_morph_Proper; + ConstructiveCauchyRealsMult.CReal_opp_morph_T; + ConstructiveCauchyRealsMult.CReal_opp_mult_distr_l; + ConstructiveCauchyRealsMult.CReal_opp_mult_distr_r; + ConstructiveCauchyReals.CReal_opp_scale; + ConstructiveCauchyReals.CReal_opp_seq; + ConstructiveCauchyReals.CReal_plus; + ConstructiveCauchyReals.CReal_plus_0_l; + ConstructiveCauchyReals.CReal_plus_0_r; + ConstructiveCauchyReals.CReal_plus_assoc; + ConstructiveCauchyReals.CReal_plus_bound; + ConstructiveCauchyReals.CReal_plus_cauchy; + ConstructiveCauchyReals.CReal_plus_comm; + ConstructiveCauchyReals.CReal_plus_eq_reg_l; + ConstructiveCauchyReals.CReal_plus_le_compat; + ConstructiveCauchyReals.CReal_plus_le_compat_l; + ConstructiveCauchyReals.CReal_plus_le_lt_compat; + ConstructiveCauchyReals.CReal_plus_le_reg_r; + ConstructiveCauchyReals.CReal_plus_lt_compat_l; + ConstructiveCauchyReals.CReal_plus_lt_compat_r; + ConstructiveCauchyReals.CReal_plus_lt_reg_l; + ConstructiveCauchyReals.CReal_plus_lt_reg_r; + ConstructiveCauchyReals.CReal_plus_morph; + ConstructiveCauchyReals.CReal_plus_morph_Proper; + ConstructiveCauchyReals.CReal_plus_morph_T; + ConstructiveCauchyReals.CReal_plus_opp_l; + ConstructiveCauchyReals.CReal_plus_opp_r; + ConstructiveCauchyReals.CReal_plus_proper_l; + ConstructiveCauchyReals.CReal_plus_proper_r; + ConstructiveCauchyReals.CReal_plus_scale; + ConstructiveCauchyReals.CReal_plus_seq; + ConstructiveCauchyRealsMult.CReal_red_scale; + ConstructiveCauchyReals.CReal_red_seq; + ConstructiveCauchyRealsMult.CReal_scale_sep0_limit; + ConstructiveReals.CReq; ConstructiveReals.CReq_refl; + ConstructiveReals.CReq_rel; ConstructiveReals.CReq_relT; + ConstructiveReals.CReq_rel_Reflexive; + ConstructiveReals.CReq_rel_Symmetric; + ConstructiveReals.CReq_rel_Transitive; ConstructiveReals.CReq_sym; + ConstructiveReals.CReq_trans; ConstructiveReals.CRinv; + ConstructiveReals.CRinv_0_lt_compat; ConstructiveReals.CRinv_l; + ConstructiveReals.CRinv_r; ConstructiveReals.CRisRing; + ConstructiveReals.CRisRingExt; ConstructiveLUB.CRis_upper_bound; + ConstructiveReals.CRle; ConstructiveAbs.CRle_abs; + ConstructiveReals.CRle_lt_trans; ConstructiveReals.CRle_morph_Proper; + ConstructiveReals.CRle_refl; ConstructiveReals.CRle_trans; + ConstructiveReals.CRlt; ConstructiveReals.CRltEpsilon; + ConstructiveReals.CRltForget; ConstructiveReals.CRltLinear; + ConstructiveReals.CRltProp; ConstructiveReals.CRlt_asym; + ConstructiveReals.CRlt_le_trans; ConstructiveLUB.CRlt_lpo_dec; + ConstructiveReals.CRlt_minus; ConstructiveReals.CRlt_morph; + ConstructiveReals.CRlt_proper; ConstructiveReals.CRlt_trans; + ConstructiveReals.CRminus; ConstructiveReals.CRmult; + ConstructiveReals.CRmult_0_r; ConstructiveReals.CRmult_1_l; + ConstructiveReals.CRmult_1_r; ConstructiveReals.CRmult_assoc; + ConstructiveReals.CRmult_comm; ConstructiveReals.CRmult_lt_0_compat; + ConstructiveReals.CRmult_lt_compat_l; + ConstructiveReals.CRmult_lt_compat_r; ConstructiveReals.CRmult_lt_reg_l; + ConstructiveReals.CRmult_lt_reg_r; ConstructiveReals.CRmult_morph; + ConstructiveReals.CRmult_morph_Proper; ConstructiveReals.CRmult_morph_T; + ConstructiveReals.CRmult_plus_distr_l; + ConstructiveReals.CRmult_plus_distr_r; ConstructiveReals.CRopp; + ConstructiveReals.CRopp_0; ConstructiveReals.CRopp_ge_le_contravar; + ConstructiveReals.CRopp_gt_lt_contravar; + ConstructiveReals.CRopp_involutive; ConstructiveReals.CRopp_lt_cancel; + ConstructiveReals.CRopp_morph_Proper; + ConstructiveReals.CRopp_mult_distr_l; + ConstructiveReals.CRopp_mult_distr_r; + ConstructiveReals.CRopp_plus_distr; ConstructiveReals.CRplus; + ConstructiveReals.CRplus_0_l; ConstructiveReals.CRplus_0_r; + ConstructiveReals.CRplus_assoc; ConstructiveReals.CRplus_comm; + ConstructiveReals.CRplus_eq_reg_l; ConstructiveReals.CRplus_le_compat; + ConstructiveReals.CRplus_le_compat_l; + ConstructiveReals.CRplus_le_compat_r; ConstructiveReals.CRplus_le_reg_l; + ConstructiveReals.CRplus_le_reg_r; ConstructiveReals.CRplus_lt_compat_l; + ConstructiveReals.CRplus_lt_compat_r; ConstructiveReals.CRplus_lt_reg_l; + ConstructiveReals.CRplus_lt_reg_r; ConstructiveReals.CRplus_morph; + ConstructiveReals.CRplus_morph_Proper; ConstructiveReals.CRplus_morph_T; + ConstructiveReals.CRplus_opp_l; ConstructiveReals.CRplus_opp_r; + ConstructiveReals.CRup_nat; ConstructiveReals.CRzero_double; + PSeries_reg.CVU; CompOpp; CompOpp_iff; CompOpp_inj; CompOpp_involutive; + CompSpec; CompSpec2Type; CompSpecT; CompareSpec2Type; + ConstructiveLUB.DDcut_limit; ConstructiveLUB.DDcut_limit_fix; + ConstructiveLUB.DDdec; ConstructiveLUB.DDhigh; + ConstructiveLUB.DDhighProp; ConstructiveLUB.DDinterval; + ConstructiveLUB.DDlow; ConstructiveLUB.DDlowProp; + ConstructiveLUB.DDlow_below_up; ConstructiveLUB.DDproper; + ConstructiveLUB.DDupcut; Rderiv.D_in; Rderiv.D_x; Rderiv.Dmult; Env.Env; + Ring_theory.Eq_ext; Ring_theory.Eqsth; RelationClasses.Equivalence_PER; + CRelationClasses.Equivalence_Reflexive; + RelationClasses.Equivalence_Reflexive; + CRelationClasses.Equivalence_Symmetric; + RelationClasses.Equivalence_Symmetric; + RelationClasses.Equivalence_Transitive; ZMicromega.F; Field_theory.F2AF; + Field_theory.FEeval; Field_theory.FExpr_ind; Field_theory.F_1_neq_0; + Field_theory.F_R; False_ind; False_rec; False_rect; Field_theory.Fapp; + Field_theory.Fcons0; Field_theory.Fcons1; Field_theory.Fcons2; + Field_theory.Fdiv_def; Field_theory.Field_correct; + Field_theory.Field_rw_pow_correct; + Field_theory.Field_simplify_eq_pow_correct; Field_theory.Finv_l; + Field_theory.Fnorm; Field_theory.Fnorm_FEeval_PEeval; + Field_theory.Fnorm_crossproduct; Tauto.GFormula_ind; ID; + Ring_theory.IDmorph; Ring_theory.IDphi; Rdefinitions.IPR; + Rdefinitions.IPR_2; RIneq.IPR_2_xH; RIneq.IPR_2_xI; RIneq.IPR_2_xO; + RIneq.IPR_IPR_2; RIneq.IPR_ge_1; RIneq.IPR_gt_0; RIneq.IPR_xH; + RIneq.IPR_xI; RIneq.IPR_xO; Rdefinitions.IZR; RIneq.IZR_ge; + RIneq.IZR_le; RIneq.IZR_lt; Qreals.IZR_nz; List.In; ZifyInst.Inj_Z_Z; + ZifyInst.Inj_pos_Z; RelationClasses.Irreflexive; Ring_polynom.MFactor; + Ring_polynom.MPcond; MVT.MVT; RList.MaxRlist; RList.MaxRlist_P1; + Ring_polynom.Mcphi_ok; RList.MinRlist; RList.MinRlist_P1; + RList.MinRlist_P2; Ring_polynom.Mphi; Ring_polynom.Mphi_ok; + RingMicromega.NFormula; Classical_Prop.NNPP; Field_theory.NPEadd; + Field_theory.NPEadd_ok; Field_theory.NPEequiv; Field_theory.NPEequiv_eq; + Field_theory.NPEeval_ext; Field_theory.NPEmul; Field_theory.NPEmul_ok; + Field_theory.NPEopp; Field_theory.NPEopp_ok; Field_theory.NPEpow; + Field_theory.NPEpow_ok; Field_theory.NPEsub; Field_theory.NPEsub_ok; + InitialRing.Nopp; InitialRing.Nsub; Field_theory.NtoZ; + InitialRing.Ntriv_div_th; O_S; ConstructiveEpsilon.O_witness; + RingMicromega.OpAdd; RingMicromega.OpAdd_sound; RingMicromega.OpMult; + RingMicromega.OpMult_sound; ConstructiveEpsilon.P'; + ConstructiveEpsilon.P'_decidable; EnvRing.P0; Ring_polynom.P0; + EnvRing.P1; Ring_polynom.P1; Field_theory.PCond; Field_theory.PCond_app; + Field_theory.PCond_cons; RelationClasses.PER_Symmetric; + RelationClasses.PER_Transitive; Morphisms.PER_morphism; + Morphisms.PER_morphism_obligation_1; Field_theory.PE_1_l; + Field_theory.PE_1_r; Field_theory.PEadd_ext; EnvRing.PEeval; + Ring_polynom.PEeval; Field_theory.PEmul_ext; Field_theory.PEopp_ext; + Field_theory.PEpow_0_r; Field_theory.PEpow_1_l; Field_theory.PEpow_1_r; + Field_theory.PEpow_add_r; Field_theory.PEpow_ext; + Field_theory.PEpow_mul_l; Field_theory.PEpow_mul_r; + Field_theory.PEpow_nz; Field_theory.PEsimp; Field_theory.PEsimp_ok; + Field_theory.PEsub_ext; Field_theory.PExpr_eq; + Field_theory.PExpr_eq_semi_ok; Field_theory.PExpr_eq_spec; + EnvRing.PExpr_ind; Ring_polynom.PExpr_ind; + Field_theory.PFcons0_fcons_inv; Field_theory.PFcons1_fcons_inv; + Field_theory.PFcons2_fcons_inv; Ring_polynom.PNSubst; + Ring_polynom.PNSubst1; Ring_polynom.PNSubst1_ok; Ring_polynom.PNSubstL; + Ring_polynom.PNSubstL_ok; Ring_polynom.PNSubst_ok; + Ring_polynom.POneSubst; Ring_polynom.POneSubst_ok; Ring_polynom.PSubstL; + Ring_polynom.PSubstL1; Ring_polynom.PSubstL1_ok; + Ring_polynom.PSubstL_ok; Ring_polynom.PX_ext; EnvRing.Padd; + Ring_polynom.Padd; EnvRing.PaddC; Ring_polynom.PaddC; EnvRing.PaddC_ok; + Ring_polynom.PaddC_ok; EnvRing.PaddI; Ring_polynom.PaddI; EnvRing.PaddX; + Ring_polynom.PaddX; EnvRing.PaddX_ok; Ring_polynom.PaddX_ok; + EnvRing.Padd_ok; Ring_polynom.Padd_ok; Field_theory.Pcond_Fnorm; + Field_theory.Pcond_simpl_complete; EnvRing.Peq; Ring_polynom.Peq; + EnvRing.Peq_ok; Ring_polynom.Peq_ok; EnvRing.Peq_spec; + Ring_polynom.Peq_spec; Ring_polynom.Pequiv; Ring_polynom.Pequiv_eq; + EnvRing.Pjump_add; EnvRing.Pjump_pred_double; EnvRing.Pjump_xO_tail; + EnvRing.Pmul; Ring_polynom.Pmul; EnvRing.PmulC; Ring_polynom.PmulC; + EnvRing.PmulC_aux; Ring_polynom.PmulC_aux; EnvRing.PmulC_aux_ok; + Ring_polynom.PmulC_aux_ok; EnvRing.PmulC_ok; Ring_polynom.PmulC_ok; + EnvRing.PmulI; Ring_polynom.PmulI; EnvRing.PmulI_ok; + Ring_polynom.PmulI_ok; EnvRing.Pmul_ok; Ring_polynom.Pmul_ok; + RingMicromega.PolC; RingMicromega.PolEnv; EnvRing.Pol_ind; + Ring_polynom.Pol_ind; EnvRing.Popp; Ring_polynom.Popp; EnvRing.Popp_ok; + Ring_polynom.Popp_ok; ConstructiveRcomplete.Pos2Z_pos_is_pos; + QExtra.Pos_log2floor_plus1; QExtra.Pos_log2floor_plus1_spec; + PosExtra.Pos_pow_1_r; PosExtra.Pos_pow_le_mono_r; + ConstructiveExtra.Pos_pred_double_inj; + ConstructiveRcomplete.Pospow_lin_le_2pow; EnvRing.Pphi; + Ring_polynom.Pphi; EnvRing.Pphi0; Ring_polynom.Pphi0; EnvRing.Pphi1; + Ring_polynom.Pphi1; Ring_polynom.Pphi_avoid; Ring_polynom.Pphi_avoid_ok; + Ring_polynom.Pphi_dev; Ring_polynom.Pphi_dev_ok; Ring_polynom.Pphi_ext; + Ring_polynom.Pphi_pow; Ring_polynom.Pphi_pow_ok; + BinPos.Pplus_one_succ_l; BinPos.Pplus_one_succ_r; EnvRing.Ppow_N; + Ring_polynom.Ppow_N; EnvRing.Ppow_N_ok; Ring_polynom.Ppow_N_ok; + EnvRing.Ppow_pos; Ring_polynom.Ppow_pos; EnvRing.Ppow_pos_ok; + Ring_polynom.Ppow_pos_ok; RelationClasses.PreOrder_Reflexive; + RelationClasses.PreOrder_Transitive; RIneq.Private_sumbool_to_or; + CMorphisms.Proper; Morphisms.Proper; CMorphisms.ProperProxy; + Morphisms.ProperProxy; Qminmax.Q.Proper_instance_0; + BinInt.Z.Proper_instance_0; RingMicromega.Psatz_ind; EnvRing.Psquare; + EnvRing.Psquare_ok; EnvRing.Psub; Ring_polynom.Psub; EnvRing.PsubC; + Ring_polynom.PsubC; EnvRing.PsubC_ok; RingMicromega.PsubC_ok; + Ring_polynom.PsubC_ok; EnvRing.PsubI; Ring_polynom.PsubI; EnvRing.PsubX; + Ring_polynom.PsubX; EnvRing.PsubX_ok; EnvRing.Psub_ok; + Ring_polynom.Psub_ok; Ring_polynom.Psub_opp; Rdefinitions.Q2R; + RMicromega.Q2R_0; RMicromega.Q2R_1; Qreals.Q2R_inv; + RMicromega.Q2R_inv_ext; RMicromega.Q2R_m_Proper; Qreals.Q2R_minus; + Qreals.Q2R_mult; Qreals.Q2R_opp; Qreals.Q2R_plus; RMicromega.Q2R_pow_N; + RMicromega.Q2R_pow_pos; RMicromega.Q2RpowerRZ; + ConstructiveCauchyReals.QBound; ConstructiveCauchyReals.QCauchySeq; + QMicromega.QNpower; RMicromega.QReval_expr; RMicromega.QReval_formula; + RMicromega.QReval_formula'; RMicromega.QReval_formula_compat; + QMicromega.QSORaddon; RMicromega.QSORaddon; QMicromega.QTautoChecker; + QMicromega.QTautoChecker_sound; QMicromega.QWeakChecker; + QMicromega.QWeakChecker_sound; QMicromega.QWitness; + QArith_base.Q_Setoid; QArith_base.Q_dec; RMicromega.Q_of_Rcst; + RMicromega.Q_of_RcstR; Qabs.Qabs; + ConstructiveRcomplete.Qabs_Qgt_condition; Qabs.Qabs_Qinv; + Qabs.Qabs_Qle_condition; Qabs.Qabs_Qlt_condition; Qabs.Qabs_Qmult; + ConstructiveRcomplete.Qabs_Rabs; Qabs.Qabs_case; + Qabs.Qabs_case_subproof; Qabs.Qabs_case_subproof0; + Qabs.Qabs_case_subproof1; Qabs.Qabs_gt; + ConstructiveCauchyAbs.Qabs_involutive; Qabs.Qabs_neg; Qabs.Qabs_nonneg; + Qabs.Qabs_opp; Qabs.Qabs_pos; Qabs.Qabs_triangle; + Qabs.Qabs_triangle_reverse; Qabs.Qabs_wd; Qabs.Qabs_wd_Proper; + QArith_base.Qarchimedean; QExtra.QarchimedeanExp2_Z; + QExtra.QarchimedeanLowExp2_Z; QExtra.Qbound_lt_ZExp2; + QExtra.Qbound_lt_ZExp2_spec; QExtra.Qbound_ltabs_ZExp2; + QExtra.Qbound_ltabs_ZExp2_spec; QArith_base.Qcompare; + QArith_base.Qcompare_comp; QArith_base.Qden; QArith_base.Qdiv; + QArith_base.Qdiv_comp; QArith_base.Qdiv_mult_l; QArith_base.Qeq; + QArith_base.Qeq_alt; QArith_base.Qeq_bool; QArith_base.Qeq_bool_eq; + QArith_base.Qeq_bool_iff; QArith_base.Qeq_bool_neq; QArith_base.Qeq_dec; + Qreals.Qeq_eqR; QArith_base.Qeq_eq_bool; RMicromega.Qeq_false; + QArith_base.Qeq_refl; QArith_base.Qeq_sym; QArith_base.Qeq_trans; + RMicromega.Qeq_true; QMicromega.Qeval_bop2; QMicromega.Qeval_expr; + QMicromega.Qeval_expr'; QMicromega.Qeval_expr_compat; + QMicromega.Qeval_formula; QMicromega.Qeval_formula'; + QMicromega.Qeval_formula_compat; QMicromega.Qeval_nformula; + RMicromega.Qeval_nformula; QMicromega.Qeval_nformula_dec; + QMicromega.Qeval_op2; QMicromega.Qeval_op2_hold; QMicromega.Qeval_pop2; + Qfield.Qfield_field_lemma1; Qfield.Qfield_field_lemma2; + Qfield.Qfield_lemma5; Qfield.Qfield_ring_lemma1; + Qfield.Qfield_ring_lemma2; Qround.Qfloor; Qround.Qfloor_le; + QArith_base.Qinv; QArith_base.Qinv_comp; QArith_base.Qinv_involutive; + QArith_base.Qinv_le_0_compat; QArith_base.Qinv_lt_0_compat; + QArith_base.Qinv_lt_contravar; QArith_base.Qinv_mult_distr; + QArith_base.Qinv_plus_distr; QArith_base.Qinv_pos; Qpower.Qinv_power; + Qpower.Qinv_power_positive; QArith_base.Qle; Qabs.Qle_Qabs; + Qreals.Qle_Rle; QArith_base.Qle_alt; QArith_base.Qle_antisym; + QArith_base.Qle_bool; QArith_base.Qle_bool_iff; + QArith_base.Qle_bool_imp_le; QArith_base.Qle_comp; + QArith_base.Qle_lt_trans; QArith_base.Qle_minus_iff; + QArith_base.Qle_not_lt; QArith_base.Qle_refl; + QArith_base.Qle_shift_div_l; QArith_base.Qle_shift_div_r; + QArith_base.Qle_trans; RMicromega.Qle_true; + QExtra.Qlowbound_lt_ZExp2_spec; QExtra.Qlowbound_ltabs_ZExp2; + QExtra.Qlowbound_ltabs_ZExp2_inv; QArith_base.Qlt; QArith_base.Qlt_alt; + QMicromega.Qlt_bool; QMicromega.Qlt_bool_iff; QArith_base.Qlt_compat; + Qround.Qlt_floor; QArith_base.Qlt_irrefl; QArith_base.Qlt_le_dec; + QArith_base.Qlt_le_trans; QArith_base.Qlt_le_weak; + QArith_base.Qlt_leneq; QArith_base.Qlt_minus_iff; + QArith_base.Qlt_not_eq; QArith_base.Qlt_not_le; + QArith_base.Qlt_shift_div_l; QArith_base.Qlt_shift_div_r; + QArith_base.Qlt_shift_inv_l; QArith_base.Qlt_trans; + ConstructiveRcomplete.Qlt_trans_swap_hyp; QArith_base.Qminus; + QArith_base.Qminus_comp; QArith_base.Qmult; QArith_base.Qmult_0_l; + QArith_base.Qmult_0_r; QArith_base.Qmult_1_l; QArith_base.Qmult_1_r; + QArith_base.Qmult_assoc; QArith_base.Qmult_comm; QArith_base.Qmult_comp; + QArith_base.Qmult_div_r; QArith_base.Qmult_frac_l; + QArith_base.Qmult_integral; RMicromega.Qmult_integral; + QArith_base.Qmult_integral_l; QArith_base.Qmult_inv_r; + QArith_base.Qmult_le_0_compat; QArith_base.Qmult_le_1_compat; + QArith_base.Qmult_le_compat_nonneg; QArith_base.Qmult_le_compat_r; + QArith_base.Qmult_le_l; QArith_base.Qmult_le_lt_compat_pos; + QArith_base.Qmult_le_r; QArith_base.Qmult_lt_0_le_reg_r; + QArith_base.Qmult_lt_compat_nonneg; QArith_base.Qmult_lt_compat_r; + QArith_base.Qmult_lt_l; QArith_base.Qmult_lt_r; + QArith_base.Qmult_plus_distr_l; QMicromega.Qnegate; + QMicromega.Qnormalise; QArith_base.Qnot_eq_sym; QArith_base.Qnot_le_lt; + QArith_base.Qnot_lt_le; QArith_base.Qnum; QArith_base.Qopp; + QArith_base.Qopp_comp; QArith_base.Qopp_le_compat; + QArith_base.Qopp_lt_compat; ConstructiveCauchyAbs.Qopp_mult_mone; + Qfield.Qopp_opp; QArith_base.Qplus; QArith_base.Qplus_0_l; + QArith_base.Qplus_0_r; QArith_base.Qplus_assoc; QArith_base.Qplus_comm; + QArith_base.Qplus_comp; QArith_base.Qplus_le_compat; + QArith_base.Qplus_le_l; QArith_base.Qplus_le_r; QArith_base.Qplus_lt_l; + QArith_base.Qplus_lt_le_compat; QArith_base.Qplus_lt_r; + QArith_base.Qplus_opp_r; QArith_base.Qpower; RMicromega.Qpower0; + Qpower.Qpower_0_le; Qpower.Qpower_0_lt; Qpower.Qpower_0_r; + Qpower.Qpower_1_le; Qpower.Qpower_1_le_pos; + ConstructiveRcomplete.Qpower_2powneg_le_inv; QArith_base.Qpower_comp; + Qpower.Qpower_decomp_pos; Qpower.Qpower_decomp_positive; + Qpower.Qpower_le_compat_l; Qpower.Qpower_lt_compat_l_inv; + Qpower.Qpower_minus; Qpower.Qpower_minus_pos; + Qpower.Qpower_minus_positive; Qpower.Qpower_not_0; + Qpower.Qpower_not_0_positive; Qpower.Qpower_opp; Qpower.Qpower_plus; + Qpower.Qpower_plus_positive; Qpower.Qpower_pos_positive; + QArith_base.Qpower_positive; Qpower.Qpower_positive_0; + QArith_base.Qpower_positive_comp; RMicromega.Qpower_positive_eq_zero; + RMicromega.Qpower_positive_zero; Qfield.Qpower_theory; Qreduction.Qred; + Qreduction.Qred_correct; Qfield.Qsft; QMicromega.Qsor; Qfield.Qsrt; + Rdefinitions.RbaseSymbolsImpl.R; Rdefinitions.RbaseSymbolsImpl.R0; + Rdefinitions.RbaseSymbolsImpl.R0_def; Rdefinitions.RbaseSymbolsImpl.R1; + Rdefinitions.RbaseSymbolsImpl.R1_def; Raxioms.R1_neq_R0; + RIneq.RField_field_lemma1; RIneq.RField_field_lemma3; + RIneq.RField_lemma5; RIneq.RField_ring_lemma1; Rbasic_fun.RRle_abs; + RMicromega.RTautoChecker; RMicromega.RTautoChecker_sound; + RealField.RTheory; RMicromega.RWeakChecker; + RMicromega.RWeakChecker_sound; RMicromega.RWitness; Rlimit.R_met; + RMicromega.R_of_Rcst; RealField.R_power_theory; RIneq.R_rm; + InitialRing.R_set1; InitialRing.R_set1_Reflexive; + InitialRing.R_set1_Transitive; InitialRing.R_setoid3; + InitialRing.R_setoid3_Reflexive; InitialRing.R_setoid3_Symmetric; + InitialRing.R_setoid3_Transitive; InitialRing.R_setoid4; + InitialRing.R_setoid4_Reflexive; InitialRing.R_setoid4_Transitive; + Rbasic_fun.Rabs; Rbasic_fun.Rabs_R0; Rbasic_fun.Rabs_Ropp; + Rbasic_fun.Rabs_def1; Rbasic_fun.Rabs_def2; Rbasic_fun.Rabs_inv; + Rbasic_fun.Rabs_minus_sym; Rbasic_fun.Rabs_mult; Rbasic_fun.Rabs_no_R0; + Rbasic_fun.Rabs_pos; Rbasic_fun.Rabs_pos_eq; Rbasic_fun.Rabs_pos_lt; + Rbasic_fun.Rabs_right; Rbasic_fun.Rabs_triang; + Rbasic_fun.Rabs_triang_inv; Rdefinitions.RbaseSymbolsImpl.Rabst; + Ring_theory.Radd_0_l; Ring_theory.Radd_assoc; Ring_theory.Radd_comm; + Ring_theory.Radd_ext; Rbasic_fun.Rcase_abs; + ConstructiveRcomplete.Rcauchy_complete; RMicromega.Rcst_ind; + RealField.Rdef_pow_add; Rfunctions.Rdist; Rfunctions.Rdist_plus; + Rfunctions.Rdist_pos; Rfunctions.Rdist_refl; Rfunctions.Rdist_sym; + Rfunctions.Rdist_tri; Ring_theory.Rdistr_l; Rdefinitions.Rdiv; + RIneq.Rdiv_plus_distr; CRelationClasses.Reflexive; + RelationClasses.Reflexive; Morphisms.ReflexiveProxy; + CMorphisms.Reflexive_partial_app_morphism; + Morphisms.Reflexive_partial_app_morphism; Rdefinitions.Req_appart_dec; + RIneq.Req_dec; RIneq.Req_dec_T; OrderedRing.Req_dne; OrderedRing.Req_em; + RIneq.Req_le; RIneq.Req_le_sym; RMicromega.Reval_bop2; + RMicromega.Reval_expr; RMicromega.Reval_formula; + RMicromega.Reval_formula'; RMicromega.Reval_formula_compat; + RMicromega.Reval_nformula_dec; RMicromega.Reval_op2; + RMicromega.Reval_op2_hold; RMicromega.Reval_pop2; + RMicromega.Reval_pop2_eval_op2; RealField.Rfield; Rdefinitions.Rge; + RIneq.Rge_antisym; RIneq.Rge_gt_dec; RIneq.Rge_gt_trans; RIneq.Rge_le; + RIneq.Rge_minus; RIneq.Rge_not_lt; RIneq.Rge_trans; Rdefinitions.Rgt; + RIneq.Rgt_dec; RIneq.Rgt_ge_trans; RIneq.Rgt_lt; RIneq.Rgt_minus; + RIneq.Rgt_not_eq; RIneq.Rgt_not_ge; RIneq.Rgt_not_le; RIneq.Rgt_trans; + BinInt.Z.Rgt_wd; Rdefinitions.RinvImpl.Rinv; RIneq.Rinv_0; + RIneq.Rinv_0_lt_compat; RIneq.Rinv_1; RMicromega.Rinv_1; + Rdefinitions.RinvImpl.Rinv_def; Raxioms.Rinv_l; RIneq.Rinv_lt_0_compat; + RIneq.Rinv_mult; RIneq.Rinv_neq_0_compat; RIneq.Rinv_opp; RIneq.Rinv_r; + Rdefinitions.Rle; RIneq.Rle_0_1; RIneq.Rle_0_sqr; RIneq.Rle_Reflexive; + RIneq.Rle_Transitive; Rbasic_fun.Rle_abs; RIneq.Rle_antisym; + OrderedRing.Rle_antisymm; RIneq.Rle_dec; RIneq.Rle_ge; + OrderedRing.Rle_gt_cases; RIneq.Rle_le_eq; OrderedRing.Rle_le_minus; + RIneq.Rle_lt_dec; OrderedRing.Rle_lt_eq; OrderedRing.Rle_lt_trans; + RIneq.Rle_lt_trans; OrderedRing.Rle_ngt; RIneq.Rle_not_lt; + OrderedRing.Rle_refl; RIneq.Rle_refl; OrderedRing.Rle_trans; + RIneq.Rle_trans; Rdefinitions.RbaseSymbolsImpl.Rlt; RIneq.Rlt_0_1; + RIneq.Rlt_0_2; RIneq.Rlt_0_minus; RIneq.Rlt_0_sqr; Raxioms.Rlt_asym; + RIneq.Rlt_dec; Rdefinitions.RbaseSymbolsImpl.Rlt_def; + RIneq.Rlt_dichotomy_converse; RIneq.Rlt_gt; RIneq.Rlt_irrefl; + RIneq.Rlt_le; RIneq.Rlt_le_dec; OrderedRing.Rlt_le_neq; + OrderedRing.Rlt_le_trans; RIneq.Rlt_le_trans; OrderedRing.Rlt_lt_minus; + OrderedRing.Rlt_neq; OrderedRing.Rlt_nge; RIneq.Rlt_not_eq; + RIneq.Rlt_not_ge; RIneq.Rlt_not_le; RIneq.Rlt_or_le; + OrderedRing.Rlt_trans; Raxioms.Rlt_trans; OrderedRing.Rlt_trichotomy; + BinNat.N.Rlt_wd; PeanoNat.Nat.Rlt_wd; BinInt.Z.Rlt_wd; Rbasic_fun.Rmax; + Rbasic_fun.Rmax_Rlt; Rbasic_fun.Rmax_case_strong; Rbasic_fun.Rmax_l; + Rbasic_fun.Rmax_left; Rbasic_fun.Rmax_lub_lt; Rbasic_fun.Rmax_r; + Rbasic_fun.Rmax_right; Rbasic_fun.Rmax_stable_in_negreal; + Rbasic_fun.Rmin; Rbasic_fun.Rmin_Rgt; Rbasic_fun.Rmin_Rgt_l; + Rbasic_fun.Rmin_Rgt_r; Rbasic_fun.Rmin_case_strong; + Rbasic_fun.Rmin_glb_lt; Rbasic_fun.Rmin_l; Rbasic_fun.Rmin_r; + Rbasic_fun.Rmin_stable_in_posreal; Rdefinitions.Rminus; + RIneq.Rminus_0_r; RIneq.Rminus_diag_eq; RIneq.Rminus_diag_uniq; + RIneq.Rminus_diag_uniq_sym; OrderedRing.Rminus_eq_0; + RIneq.Rminus_eq_contra; RIneq.Rminus_ge; RIneq.Rminus_gt; + RIneq.Rminus_le; RIneq.Rminus_lt; RIneq.Rminus_not_eq; + RIneq.Rminus_plus_distr; RIneq.Rminus_plus_l_l; RIneq.Rminus_plus_r_l; + RIneq.Rminus_plus_r_r; Ring_theory.Rmul_0_l; Ring_theory.Rmul_1_l; + Ring_theory.Rmul_assoc; Ring_theory.Rmul_comm; Ring_theory.Rmul_ext; + Rdefinitions.RbaseSymbolsImpl.Rmult; RIneq.Rmult_0_l; RIneq.Rmult_0_r; + Raxioms.Rmult_1_l; RIneq.Rmult_1_r; Raxioms.Rmult_assoc; + Raxioms.Rmult_comm; Rdefinitions.RbaseSymbolsImpl.Rmult_def; + RIneq.Rmult_div_l; RIneq.Rmult_div_r; RIneq.Rmult_eq_compat_l; + RIneq.Rmult_eq_reg_l; RIneq.Rmult_ge_0_gt_0_lt_compat; + RIneq.Rmult_gt_0_compat; RIneq.Rmult_integral; + RIneq.Rmult_integral_contrapositive; + RIneq.Rmult_integral_contrapositive_currified; RIneq.Rmult_inv_r_id_l; + RIneq.Rmult_inv_r_id_m; RIneq.Rmult_inv_r_uniq; + RIneq.Rmult_le_0_lt_compat; RIneq.Rmult_le_compat; + RIneq.Rmult_le_compat_l; RIneq.Rmult_le_compat_neg_l; + RIneq.Rmult_le_compat_r; RIneq.Rmult_le_pos; RIneq.Rmult_lt_0_compat; + Raxioms.Rmult_lt_compat_l; RIneq.Rmult_lt_compat_r; + RIneq.Rmult_lt_gt_compat_neg_l; RIneq.Rmult_lt_reg_l; RIneq.Rmult_ne; + RIneq.Rmult_opp_opp; Raxioms.Rmult_plus_distr_l; + RIneq.Rmult_plus_distr_r; RMicromega.Rnegate; OrderedRing.Rneq_symm; + RMicromega.Rnormalise; RIneq.Rnot_gt_ge; RIneq.Rnot_le_gt; + RIneq.Rnot_le_lt; RIneq.Rnot_lt_ge; RIneq.Rnot_lt_le; + Rdefinitions.RbaseSymbolsImpl.Ropp; RIneq.Ropp_0; Rbasic_fun.Ropp_Rmin; + RIneq.Ropp_Ropp_IZR; Ring_theory.Ropp_add; Ring_theory.Ropp_def; + Rdefinitions.RbaseSymbolsImpl.Ropp_def; RIneq.Ropp_eq_0_compat; + RIneq.Ropp_eq_compat; RIneq.Ropp_eq_reg; Ring_theory.Ropp_ext; + RIneq.Ropp_ge_cancel; RIneq.Ropp_ge_le_contravar; + RIneq.Ropp_gt_lt_0_contravar; RIneq.Ropp_gt_lt_contravar; + RIneq.Ropp_involutive; RIneq.Ropp_le_cancel; RIneq.Ropp_le_contravar; + RIneq.Ropp_le_ge_contravar; RIneq.Ropp_lt_cancel; + RIneq.Ropp_lt_contravar; RIneq.Ropp_lt_gt_0_contravar; + RIneq.Ropp_lt_gt_contravar; OrderedRing.Ropp_lt_mono; + RIneq.Ropp_minus_distr; Ring_theory.Ropp_mul_l; RIneq.Ropp_mult_distr_l; + RIneq.Ropp_mult_distr_l_reverse; RIneq.Ropp_mult_distr_r; + RIneq.Ropp_neq_0_compat; Ring_theory.Ropp_opp; RIneq.Ropp_plus_distr; + OrderedRing.Ropp_pos_neg; RingMicromega.Rops_wd; + Rdefinitions.RbaseSymbolsImpl.Rplus; OrderedRing.Rplus_0_l; + Raxioms.Rplus_0_l; OrderedRing.Rplus_0_r; RIneq.Rplus_0_r; + RIneq.Rplus_0_r_uniq; Raxioms.Rplus_assoc; OrderedRing.Rplus_cancel_l; + OrderedRing.Rplus_comm; Raxioms.Rplus_comm; + Rdefinitions.RbaseSymbolsImpl.Rplus_def; RIneq.Rplus_diag; + RIneq.Rplus_eq_compat_l; RIneq.Rplus_eq_compat_r; RIneq.Rplus_eq_reg_l; + RIneq.Rplus_ge_compat_l; RIneq.Rplus_ge_compat_r; RIneq.Rplus_ge_reg_r; + RIneq.Rplus_half_diag; RIneq.Rplus_le_compat; RIneq.Rplus_le_compat_l; + RIneq.Rplus_le_compat_r; RIneq.Rplus_le_lt_0_compat; + RIneq.Rplus_le_lt_0_neq_0; RIneq.Rplus_le_lt_compat; + OrderedRing.Rplus_le_lt_mono; OrderedRing.Rplus_le_mono; + OrderedRing.Rplus_le_mono_l; OrderedRing.Rplus_le_mono_r; + RIneq.Rplus_le_reg_l; RIneq.Rplus_le_reg_r; RIneq.Rplus_lt_0_compat; + RIneq.Rplus_lt_compat; Raxioms.Rplus_lt_compat_l; + RIneq.Rplus_lt_compat_r; RIneq.Rplus_lt_le_0_compat; + RIneq.Rplus_lt_le_compat; OrderedRing.Rplus_lt_le_mono; + OrderedRing.Rplus_lt_mono; OrderedRing.Rplus_lt_mono_l; + OrderedRing.Rplus_lt_mono_r; RIneq.Rplus_lt_reg_l; RIneq.Rplus_lt_reg_r; + RIneq.Rplus_minus_assoc; RIneq.Rplus_minus_l; RIneq.Rplus_minus_r; + RIneq.Rplus_ne; OrderedRing.Rplus_nonneg_nonneg; + OrderedRing.Rplus_nonneg_pos; RIneq.Rplus_opp_l; Raxioms.Rplus_opp_r; + RIneq.Rplus_opp_r_uniq; OrderedRing.Rplus_pos_nonneg; + OrderedRing.Rplus_pos_pos; Rdefinitions.RbaseSymbolsImpl.Rquot1; + Rdefinitions.RbaseSymbolsImpl.Rquot2; + Rdefinitions.RbaseSymbolsImpl.Rrepr; Raxioms.Rrepr_0; Raxioms.Rrepr_1; + Rdefinitions.Rrepr_appart_0; Raxioms.Rrepr_le; Raxioms.Rrepr_mult; + Raxioms.Rrepr_opp; Raxioms.Rrepr_plus; Field_theory.Rring_ring_lemma1; + RMicromega.Rsor; RIneq.Rsqr; RIneq.Rsqr_0_uniq; RIneq.Rsqr_def; + RMicromega.Rsrt; Ring_theory.Rsub_def; Ring_theory.Rth_ARth; + OrderedRing.Rtimes_0_l; OrderedRing.Rtimes_0_r; OrderedRing.Rtimes_comm; + OrderedRing.Rtimes_neg_neg; OrderedRing.Rtimes_neq_0; + OrderedRing.Rtimes_nonneg_nonneg; OrderedRing.Rtimes_pos_neg; + OrderedRing.Rtimes_pos_pos; OrderedRing.Rtimes_square_nonneg; + RIneq.Rtotal_order; ConstructiveRcomplete.Rup_pos; + RingMicromega.SORRing_ring_lemma1; OrderedRing.SOR_ring_lemma1; + RingMicromega.SORcleb_morph; RingMicromega.SORcneqb_morph; + OrderedRing.SORle_antisymm; OrderedRing.SORle_refl; + OrderedRing.SORle_trans; OrderedRing.SORle_wd; OrderedRing.SORlt_le_neq; + OrderedRing.SORlt_trichotomy; OrderedRing.SORlt_wd; + OrderedRing.SORopp_wd; OrderedRing.SORplus_le_mono_l; + OrderedRing.SORplus_wd; RingMicromega.SORpower; RingMicromega.SORrm; + OrderedRing.SORrt; OrderedRing.SORsetoid; OrderedRing.SORtimes_pos_pos; + OrderedRing.SORtimes_wd; Ring_theory.SRadd_0_l; Ring_theory.SRadd_assoc; + Ring_theory.SRadd_comm; Ring_theory.SRadd_ext; Ring_theory.SRdistr_l; + Ring_theory.SReqe_Reqe; Ring_theory.SRmul_0_l; Ring_theory.SRmul_1_l; + Ring_theory.SRmul_assoc; Ring_theory.SRmul_comm; Ring_theory.SRmul_ext; + Ring_theory.SRopp; Ring_theory.SRopp_add; Ring_theory.SRopp_ext; + Ring_theory.SRopp_mul_l; Ring_theory.SRsub; Ring_theory.SRsub_def; + Ring_theory.SRth_ARth; Setoid.Seq_refl; Setoid.Seq_sym; + Setoid.Seq_trans; Setoid.Setoid_Theory; Ring_theory.Smorph0; + Ring_theory.Smorph1; Ring_theory.Smorph_add; Ring_theory.Smorph_eq; + Ring_theory.Smorph_morph; Ring_theory.Smorph_mul; + Ring_theory.Smorph_opp; Ring_theory.Smorph_sub; + RelationClasses.StrictOrder_Irreflexive; + RelationClasses.StrictOrder_Transitive; CRelationClasses.Symmetric; + RelationClasses.Symmetric; Tauto.TFormula; CRelationClasses.Transitive; + RelationClasses.Transitive; ConstructiveRcomplete.Un_cauchy_mod; + Rseries.Un_cv; ConstructiveLimits.Un_cv_nat_real; Init.Unconvertible; + ConstructiveCauchyRealsMult.Weaken_Qle_QpowerAddExp; + ConstructiveCauchyRealsMult.Weaken_Qle_QpowerFac; + ConstructiveCauchyRealsMult.Weaken_Qle_QpowerRemSubExp; + ZMicromega.ZChecker; ZMicromega.ZChecker_sound; ZMicromega.ZNpower; + ZMicromega.ZSORaddon; ZMicromega.ZTautoChecker; + ZMicromega.ZTautoChecker_sound; ZMicromega.ZWitness; Znat.Z_N_nat; + RIneq.Z_R_minus; ZArith_dec.Z_dec'; Zdiv.Z_div_mod; + Zdiv.Z_div_mod_eq_full; ConstructiveExtra.Z_inj_nat; + ConstructiveExtra.Z_inj_nat_id; ConstructiveExtra.Z_inj_nat_rev; + ZArith_dec.Z_le_lt_eq_dec; ZArith_dec.Z_lt_dec; ZArith_dec.Z_lt_ge_dec; + ZArith_dec.Z_lt_le_dec; Znumtheory.Z_lt_neq; Zdiv.Z_mod_lt; + Zdiv.Z_mod_mult; Field_theory.Z_pos_sub_gt; BinNums.Z_rec; + BinNums.Z_rect; Zcompare.Zcompare_mult_compat; ZArith_dec.Zcompare_rec; + ZArith_dec.Zcompare_rect; ZMicromega.Zdeduce; ZMicromega.Zdiv_pol; + ZMicromega.Zdiv_pol_correct; Znumtheory.Zdivide_Zdiv_eq; + ZMicromega.Zdivide_ceiling; Znumtheory.Zdivide_mod; + Znumtheory.Zdivide_opp_r; ZMicromega.Zdivide_pol_Zdivide; + ZMicromega.Zdivide_pol_ind; ZMicromega.Zdivide_pol_one; + ZMicromega.Zdivide_pol_sub; Zbool.Zeq_bool; RIneq.Zeq_bool_IZR; + Zbool.Zeq_bool_eq; Zbool.Zeq_bool_neq; Zbool.Zeq_is_eq_bool; + ZMicromega.Zeval_bop2; ZMicromega.Zeval_expr; + ZMicromega.Zeval_expr_compat; ZMicromega.Zeval_formula; + ZMicromega.Zeval_formula'; ZMicromega.Zeval_formula_compat; + ...TRUNCATED BY DUNE... + BinPos.Pos.add_reg_r; BinInt.Z.add_simpl_r; BinNat.N.add_sub; + BinPos.Pos.add_sub; BinNat.N.add_sub_assoc; BinPos.Pos.add_sub_assoc; + BinInt.Z.add_sub_assoc; BinNat.N.add_succ_l; PeanoNat.Nat.add_succ_l; + BinPos.Pos.add_succ_l; BinInt.Z.add_succ_l; BinNat.N.add_succ_r; + PeanoNat.Nat.add_succ_r; BinPos.Pos.add_succ_r; BinInt.Z.add_succ_r; + Tauto.add_term; Tauto.add_term_correct; BinNat.N.add_wd; + PeanoNat.Nat.add_wd; BinInt.Z.add_wd; PeanoNat.Nat.add_wd_obligation_1; + BinPos.Pos.add_xI_pred_double; BinPos.Pos.add_xO; Rlimit.adhDa; + Rtopology.adherence; Rtopology.adherence_P1; Rtopology.adherence_P2; + Rtopology.adherence_P3; ZMicromega.agree_env; + ZMicromega.agree_env_eval_nformula; ZMicromega.agree_env_eval_nformulae; + ZMicromega.agree_env_jump; ZMicromega.agree_env_subset; + ZMicromega.agree_env_tail; all; Morphisms_Prop.all_iff_morphism; + Morphisms_Prop.all_iff_morphism_obligation_1; and_assoc; Tauto.and_cnf; + Tauto.and_cnf_opt; Tauto.and_cnf_opt_cnf_ff_r; Tauto.and_cnf_opt_cnf_tt; + and_comm; and_iff_compat_l; Morphisms_Prop.and_iff_morphism; + Morphisms_Prop.and_iff_morphism_obligation_1; and_ind; + ZifyClasses.and_morph; and_rec; and_rect; andb; Bool.andb_false_iff; + andb_prop; Bool.andb_true_iff; app; CRelationClasses.arrow; + CRelationClasses.arrow_Transitive; + CRelationClasses.arrow_Transitive_obligation_1; ZMicromega.bdepth; + BinNat.N.bi_induction; PeanoNat.Nat.bi_induction; BinInt.Z.bi_induction; + ConstructiveCauchyReals.bound; Raxioms.bound; ZMicromega.bound_var; + Rtopology.bounded; BinNat.N.case_analysis; PeanoNat.Nat.case_analysis; + ConstructiveCauchyReals.cauchy; ZMicromega.ceiling; + BinNat.N.central_induction; PeanoNat.Nat.central_induction; + BinInt.Z.central_induction; EnvRing.ceqb_spec; Field_theory.ceqb_spec; + Ring_polynom.ceqb_spec; Field_theory.ceqb_spec'; + RingMicromega.check_inconsistent; + RingMicromega.check_inconsistent_sound; + RingMicromega.check_normalised_formulas; RingMicromega.checker_nf_sound; + Classical_Prop.classic; Tauto.clause; RingMicromega.cleb_sound; + Rtopology.closed_set; Rtopology.closed_set_P1; RingMicromega.cltb; + RingMicromega.cltb_sound; RingMicromega.cneqb; + RingMicromega.cneqb_sound; Tauto.cnf; Tauto.cnf_checker; + Tauto.cnf_checker_sound; Tauto.cnf_ff; RingMicromega.cnf_negate; + RingMicromega.cnf_negate_correct; RingMicromega.cnf_normalise; + RingMicromega.cnf_normalise_correct; RingMicromega.cnf_of_list; + ZMicromega.cnf_of_list; RingMicromega.cnf_of_list_correct; + ZMicromega.cnf_of_list_correct; Tauto.cnf_tt; Rtopology.compact; + Rtopology.compact_EMP; Rtopology.compact_P1; Rtopology.compact_P2; + Rtopology.compact_P3; Rtopology.compact_eqDom; PeanoNat.Nat.compare; + BinNat.N.compare; BinPos.Pos.compare; BinInt.Z.compare; + BinNat.N.compare_antisym; PeanoNat.Nat.compare_antisym; + BinPos.Pos.compare_antisym; BinInt.Z.compare_antisym; + BinPos.Pos.compare_cont; BinPos.Pos.compare_cont_antisym; + BinPos.Pos.compare_cont_spec; BinNat.N.compare_eq_iff; + PeanoNat.Nat.compare_eq_iff; BinPos.Pos.compare_eq_iff; + BinInt.Z.compare_eq_iff; PeanoNat.Nat.compare_ge_iff; + PeanoNat.Nat.compare_gt_iff; BinInt.Z.compare_gt_iff; + BinNat.N.compare_le_iff; PeanoNat.Nat.compare_le_iff; + BinPos.Pos.compare_le_iff; BinInt.Z.compare_le_iff; + BinNat.N.compare_lt_iff; PeanoNat.Nat.compare_lt_iff; + BinPos.Pos.compare_lt_iff; BinInt.Z.compare_lt_iff; + BinNat.N.compare_nge_iff; BinInt.Z.compare_nge_iff; + BinInt.Z.compare_ngt_iff; BinNat.N.compare_nle_iff; + BinInt.Z.compare_nle_iff; BinNat.N.compare_refl; + PeanoNat.Nat.compare_refl; BinPos.Pos.compare_refl; + BinInt.Z.compare_refl; BinNat.N.compare_spec; PeanoNat.Nat.compare_spec; + BinPos.Pos.compare_spec; Qminmax.Q.OT.compare_spec; + BinInt.Z.compare_spec; BinInt.Z.compare_sub; + BinPos.Pos.compare_sub_mask; PeanoNat.Nat.compare_succ; + BinPos.Pos.compare_succ_l; BinPos.Pos.compare_succ_r; + BinPos.Pos.compare_succ_succ; BinPos.Pos.compare_xI_xI; + BinPos.Pos.compare_xI_xO; BinPos.Pos.compare_xO_xI; + BinPos.Pos.compare_xO_xO; RelationClasses.complement; + Rtopology.complementary; Raxioms.completeness; Rtopology.cond_fam; + RIneq.cond_neg; RIneq.cond_pos; Field_theory.condition; + ConstructiveEpsilon.constructive_indefinite_ground_description; + ConstructiveExtra.constructive_indefinite_ground_description_Z; + ConstructiveEpsilon.constructive_indefinite_ground_description_nat; + Rderiv.cont_deriv; Rderiv.continue_in; Ranalysis1.continuity; + Rtopology.continuity_P1; Rtopology.continuity_P2; + Rtopology.continuity_ab_maj; Rtopology.continuity_ab_min; + Rtopology.continuity_compact; Ranalysis1.continuity_pt; + Ranalysis1.continuity_pt_minus; Ranalysis1.continuity_pt_mult; + Ranalysis1.continuity_pt_opp; Rtopology.covering; + Rtopology.covering_finite; Rtopology.covering_open_set; + CRelationClasses.crelation; Field_theory.cross_product_eq; + ZMicromega.cutting_plane_sound; Decidable.decidable; + Field_theory.default_isIn; Field_theory.default_isIn_ok; + SetoidTactics.default_relation; Field_theory.denum; + Ranalysis1.deriv_constant2; Ranalysis1.deriv_maximum; + Ranalysis1.deriv_minimum; Ranalysis1.derivable; + Ranalysis1.derivable_const; Ranalysis1.derivable_continuous; + Ranalysis1.derivable_continuous_pt; Ranalysis1.derivable_derive; + Ranalysis1.derivable_id; Ranalysis1.derivable_pt; + Ranalysis1.derivable_pt_abs; Ranalysis1.derivable_pt_const; + Ranalysis1.derivable_pt_id; Ranalysis1.derivable_pt_lim; + Ranalysis1.derivable_pt_lim_D_in; Ranalysis1.derivable_pt_lim_const; + Ranalysis1.derivable_pt_lim_id; Ranalysis1.derivable_pt_lim_minus; + Ranalysis1.derivable_pt_lim_mult; Ranalysis1.derivable_pt_lim_opp; + Ranalysis1.derivable_pt_lim_opp_fwd; Ranalysis1.derivable_pt_minus; + Ranalysis1.derivable_pt_mult; Ranalysis1.derivable_pt_opp; + Ranalysis1.derive_pt; Ranalysis1.derive_pt_D_in; + Ranalysis1.derive_pt_const; Ranalysis1.derive_pt_eq; + Ranalysis1.derive_pt_eq_0; Ranalysis1.derive_pt_eq_1; + Ranalysis1.derive_pt_id; Ranalysis1.derive_pt_minus; + Ranalysis1.derive_pt_mult; Ranalysis1.derive_pt_opp; + Bool.diff_false_true; Rtopology.disc; Rtopology.disc_P1; + Field_theory.display_pow_linear; Rlimit.dist; BinInt.Z.div; + BinNat.N.div_eucl; BinInt.Z.div_eucl; BinInt.Z.div_eucl_eq; + BinNat.N.div_eucl_spec; Ring_theory.div_eucl_th; BinInt.Z.div_mod; + BinInt.Z.Private_NZDiv.div_mod_unique; BinInt.Z.div_mod_unique; + BinInt.Z.div_mul; BinInt.Z.div_unique; BinInt.Z.div_unique_exact; + BinInt.Z.div_wd; BinPos.Pos.divide; BinInt.Z.divide; + BinInt.Z.divide_Zpos; BinInt.Z.divide_Zpos_Zneg_l; + BinInt.Z.divide_Zpos_Zneg_r; BinInt.Z.divide_abs_l; + BinInt.Z.divide_abs_r; BinPos.Pos.divide_add_cancel_l; + BinInt.Z.divide_antisym; BinInt.Z.divide_antisym_abs; + BinInt.Z.divide_antisym_nonneg; BinPos.Pos.divide_mul_l; + BinPos.Pos.divide_mul_r; BinInt.Z.divide_opp_l; BinInt.Z.divide_opp_r; + BinInt.Z.divide_refl; BinInt.Z.divide_trans; BinInt.Z.divide_wd; + BinPos.Pos.divide_xO_xI; BinPos.Pos.divide_xO_xO; + Rtopology.domain_finite; BinNat.N.double; BinInt.Z.double; + BinNat.N.double_add; BinPos.Pos.double_mask; BinNat.N.double_mul; + BinPos.Pos.double_pred_mask; Tauto.eAND; Tauto.eAnd_morph_Proper; + Tauto.eFF; Tauto.eIFF; Tauto.eIFF_morph_Proper; Tauto.eIMPL; + Tauto.eIMPL_morph_Proper; Tauto.eKind; Tauto.eNOT; + Tauto.eNOT_morph_Proper; Tauto.eOR; Tauto.eOR_morph_Proper; Tauto.eTT; + Tauto.e_rtyp; Tauto.eiff; Tauto.eiff_eq; Tauto.eiff_refl; + Tauto.eiff_sym; Tauto.eiff_trans; Ztac.elim_concl_le; EnvRing.env_morph; + Rlimit.eps2; Rlimit.eps2_Rgt_R0; BinNat.N.eq; BinInt.Z.eq; + RingMicromega.eq0_cnf; Qreals.eqR_Qeq; Rtopology.eq_Dom; RIneq.eq_IZR; + RIneq.eq_IZR_R0; RIneq.eq_IZR_contrapositive; + RelationClasses.eq_Reflexive; RelationClasses.eq_Symmetric; + RelationClasses.eq_Transitive; eq_add_S; ZMicromega.eq_cnf; + BinPos.Pos.eq_dec; BinInt.Z.eq_dec; BinInt.Z.eq_decidable; + BinNat.N.Private_OrderTac.IsTotal.eq_equiv; + PeanoNat.Nat.Private_OrderTac.IsTotal.eq_equiv; + BinInt.Z.Private_OrderTac.IsTotal.eq_equiv; BinNat.N.eq_equiv; + PeanoNat.Nat.eq_equiv; BinPos.Pos.eq_equiv; Qminmax.Q.OT.eq_equiv; + BinInt.Z.eq_equiv; RelationClasses.eq_equivalence; Ztac.eq_incl; eq_ind; + eq_ind_r; BinPos.Pos.Private_Tac.eq_le; Qminmax.Q.Private_Tac.eq_le; + BinInt.Z.Private_Tac.eq_le; BinInt.Z.Private_OrderTac.Tac.eq_le; + ZMicromega.eq_le_iff; BinNat.N.eq_le_incl; PeanoNat.Nat.eq_le_incl; + BinInt.Z.eq_le_incl; PeanoNat.Nat.Private_Tac.eq_lt; + BinPos.Pos.Private_Tac.eq_lt; Qminmax.Q.Private_Tac.eq_lt; + BinInt.Z.Private_Tac.eq_lt; BinInt.Z.Private_OrderTac.Tac.eq_lt; + BinInt.Z.eq_mul_0; BinInt.Z.eq_mul_1_nonneg; BinInt.Z.eq_mul_1_nonneg'; + BinPos.Pos.Private_Tac.eq_neq; BinInt.Z.Private_OrderTac.Tac.eq_neq; + BinInt.Z.eq_opp_l; ZifyInst.eq_pos_inj; Morphisms.eq_proper_proxy; + eq_rec; eq_rec_r; eq_rect; BinPos.Pos.Private_Tac.eq_refl; + BinInt.Z.Private_OrderTac.Tac.eq_refl; BinInt.Z.eq_refl; eq_sym; + PeanoNat.Nat.Private_Tac.eq_sym; BinPos.Pos.Private_Tac.eq_sym; + Qminmax.Q.Private_Tac.eq_sym; BinInt.Z.Private_Tac.eq_sym; + BinInt.Z.Private_OrderTac.Tac.eq_sym; BinInt.Z.eq_sym_iff; eq_trans; + BinPos.Pos.Private_Tac.eq_trans; BinInt.Z.Private_OrderTac.Tac.eq_trans; + Bool.eqb; BinNat.N.eqb; BinPos.Pos.eqb; BinInt.Z.eqb; BinNat.N.eqb_eq; + BinPos.Pos.eqb_eq; BinInt.Z.eqb_eq; BinPos.Pos.eqb_neq; + BinPos.Pos.eqb_refl; BinNat.N.eqb_spec; BinPos.Pos.eqb_spec; + Bool.eqb_true_iff; SetoidTactics.equivalence_default; + RelationClasses.equivalence_rewrite_relation; RingMicromega.eval_Psatz; + ZMicromega.eval_Psatz; RingMicromega.eval_Psatz_Sound; + ZMicromega.eval_Psatz_sound; Tauto.eval_bf; Tauto.eval_bf_map; + Tauto.eval_clause; Tauto.eval_cnf; Tauto.eval_cnf_and_opt; + Tauto.eval_cnf_app; Tauto.eval_cnf_cons_iff; Tauto.eval_cnf_ff; + Tauto.eval_cnf_tt; ZMicromega.eval_expr; Tauto.eval_f; + Tauto.eval_f_morph; RingMicromega.eval_formula; + RingMicromega.eval_formulaSC; RingMicromega.eval_nformula; + ZMicromega.eval_nformula; ZMicromega.eval_nformula_bound_var; + RingMicromega.eval_nformula_dec; ZMicromega.eval_nformula_mk_eq_pos; + ZMicromega.eval_nformula_split; RingMicromega.eval_op1; + RingMicromega.eval_op2; Tauto.eval_opt_clause; RingMicromega.eval_pexpr; + RingMicromega.eval_pexprSC; RingMicromega.eval_pol; ZMicromega.eval_pol; + ZMicromega.eval_pol_Pc; RingMicromega.eval_pol_add; + ZMicromega.eval_pol_add; RingMicromega.eval_pol_norm; + ZMicromega.eval_pol_norm; RingMicromega.eval_pol_opp; + RingMicromega.eval_pol_sub; ZMicromega.eval_pol_sub; + RingMicromega.eval_sexpr; RingMicromega.eval_sformula; Tauto.eval_tt; + Morphisms_Prop.ex_iff_morphism; + Morphisms_Prop.ex_iff_morphism_obligation_1; ex_ind; Rtopology.f; + f_equal; f_equal_nat; Rtopology.family_finite; + Rtopology.family_open_set; Field_theory.fcons_ok; Ranalysis1.fct_cte; + Field_theory.field_is_integral_domain; VarMap.find; Basics.flip; + CRelationClasses.flip; CMorphisms.flip1; CMorphisms.flip2; + RelationClasses.flip_Reflexive; List.fold_left; List.fold_right; fst; + BinPos.Pos.gcd; BinInt.Z.gcd; BinInt.Z.gcd_divide_l; + BinInt.Z.gcd_divide_r; BinPos.Pos.gcd_greatest; BinInt.Z.gcd_greatest; + BinInt.Z.gcd_nonneg; BinPos.Pos.gcdn; BinPos.Pos.gcdn_greatest; ge; + BinPos.Pos.ge; BinInt.Z.ge; BinInt.Z.ge_le; BinPos.Pos.ge_le_iff; + BinInt.Z.ge_le_iff; BinInt.Z.geb; BinInt.Z.geb_le; BinInt.Z.geb_leb; + ZMicromega.genCuttingPlane; ZMicromega.genCuttingPlaneNone; + InitialRing.gen_Zeqb_ok; InitialRing.gen_phiN; InitialRing.gen_phiN1; + InitialRing.gen_phiN_add; InitialRing.gen_phiN_morph; + InitialRing.gen_phiN_mult; InitialRing.gen_phiN_sub; + InitialRing.gen_phiPOS; InitialRing.gen_phiPOS1; InitialRing.gen_phiZ; + InitialRing.gen_phiZ1; InitialRing.gen_phiZ1_pos_sub; + InitialRing.gen_phiZ_add; InitialRing.gen_phiZ_ext; + InitialRing.gen_phiZ_morph; InitialRing.gen_phiZ_mul; EnvRing.get_PEopp; + Ring_polynom.get_PEopp; InitialRing.get_signZ; InitialRing.get_signZ_th; + Ring_theory.get_sign_None; Ring_theory.get_sign_None_th; + BinPos.Pos.ggcd; BinInt.Z.ggcd; BinPos.Pos.ggcd_correct_divisors; + BinInt.Z.ggcd_correct_divisors; BinPos.Pos.ggcd_gcd; BinInt.Z.ggcd_gcd; + BinPos.Pos.ggcdn; BinPos.Pos.ggcdn_correct_divisors; + BinPos.Pos.ggcdn_gcdn; ConstructiveLUB.glb_dec_Q; BinPos.Pos.gt; + BinInt.Z.gt; BinPos.Pos.gt_lt; BinInt.Z.gt_lt; BinPos.Pos.gt_lt_iff; + BinInt.Z.gt_lt_iff; BinInt.Z.gt_wf; BinInt.Z.gtb; BinInt.Z.gtb_ltb; + BinInt.Z.gtb_spec; Env.hd; List.hd; Tauto.hold; Tauto.hold_eAND; + Tauto.hold_eEQ; Tauto.hold_eFF; Tauto.hold_eIFF; Tauto.hold_eIFF_IMPL; + Tauto.hold_eIMPL; Tauto.hold_eNOT; Tauto.hold_eOR; Tauto.hold_eTT; + Tauto.hold_eiff; id; Ranalysis1.id; Nnat.N2Nat.id; Znat.N2Z.id; + Nnat.Nat2N.id; Pnat.Nat2Pos.id; Znat.Nat2Z.id; Pnat.Pos2Nat.id; + Znat.Z2N.id; Znat.Z2Nat.id; BinInt.Z2Pos.id; Ring_theory.id_phi_N; + Pnat.SuccNat2Pos.id_succ; Tauto.if_cnf_tt; Field_theory.if_true; iff; + CRelationClasses.iffT; CMorphisms.iffT_arrow_subrelation; + CMorphisms.iffT_flip_arrow_subrelation; RelationClasses.iff_Reflexive; + RelationClasses.iff_Symmetric; RelationClasses.iff_Transitive; + RelationClasses.iff_equivalence; Morphisms.iff_flip_impl_subrelation; + Morphisms_Prop.iff_iff_iff_impl_morphism; + Morphisms_Prop.iff_iff_iff_impl_morphism_obligation_1; + Morphisms.iff_impl_subrelation; iff_refl; Bool.iff_reflect; iff_stepl; + iff_sym; iff_trans; Rtopology.image_dir; Rtopology.image_rec; + Basics.impl; RelationClasses.impl_Reflexive; + RelationClasses.impl_Reflexive_obligation_1; implb; + Classical_Prop.imply_to_and; ZMicromega.in_bdepth; Rtopology.included; + Rtopology.included_trans; Rtopology.ind; BinNat.N.induction; + PeanoNat.Nat.induction; ZifyClasses.inj; Nnat.N2Nat.inj; Znat.Nat2Z.inj; + Pnat.Pos2Nat.inj; BinInt.Pos2Z.inj; Pnat.Pos2Nat.inj_1; + Nnat.N2Nat.inj_add; Znat.N2Z.inj_add; Nnat.Nat2N.inj_add; + Znat.Nat2Z.inj_add; Pnat.Pos2Nat.inj_add; BinInt.Pos2Z.inj_add; + Nnat.N2Nat.inj_compare; Znat.N2Z.inj_compare; Nnat.Nat2N.inj_compare; + Znat.Nat2Z.inj_compare; Pnat.Pos2Nat.inj_compare; + Znat.Z2Nat.inj_compare; Znat.Nat2Z.inj_ge; Znat.Nat2Z.inj_iff; + BinInt.Pos2Z.inj_iff; Znat.Nat2Z.inj_le; Pnat.Pos2Nat.inj_le; + Znat.Z2Nat.inj_le; Znat.Nat2Z.inj_lt; Nnat.N2Nat.inj_max; + Znat.N2Z.inj_max; Nnat.Nat2N.inj_max; Znat.Nat2Z.inj_max; + Pnat.Pos2Nat.inj_mul; BinInt.Pos2Z.inj_mul; Znat.N2Z.inj_pos; + BinInt.Pos2Z.inj_pow; BinInt.Pos2Z.inj_pow_pos; Znat.Nat2Z.inj_succ; + Pnat.Pos2Nat.inj_succ; BinInt.Pos2Z.inj_succ; Pnat.Pos2Nat.inj_xI; + Pnat.Pos2Nat.inj_xO; ConstructiveCauchyReals.inject_Q; + ConstructiveCauchyReals.inject_Q_cauchy; + ConstructiveCauchyReals.inject_Q_compare; + ConstructiveCauchyReals.inject_Q_le; + ConstructiveCauchyReals.inject_Q_lt; + ConstructiveCauchyReals.inject_Q_morph; + ConstructiveCauchyReals.inject_Q_morph_Proper; + ConstructiveCauchyRealsMult.inject_Q_mult; + ConstructiveCauchyReals.inject_Q_plus; ConstructiveCauchyReals.inject_Z; + QArith_base.inject_Z; Rtopology.interior; Rtopology.interior_P1; + Rtopology.interior_P2; Ring_polynom.interp_PElist; + Ring_polynom.interp_PElist_ok; PeanoNat.Nat.Private_Tac.interp_ord; + BinPos.Pos.Private_Tac.interp_ord; Qminmax.Q.Private_Tac.interp_ord; + BinInt.Z.Private_Tac.interp_ord; + BinNat.N.Private_OrderTac.Tac.interp_ord; + PeanoNat.Nat.Private_OrderTac.Tac.interp_ord; + BinInt.Z.Private_OrderTac.Tac.interp_ord; Rtopology.intersection_domain; + Pnat.SuccNat2Pos.inv; ConstructiveEpsilon.inv_before_witness; + Field_theory.isIn; Field_theory.isIn_ok; + ConstructiveReals.isLinearOrder; Tauto.is_bool; Tauto.is_bool_inv; + Tauto.is_cnf_ff; Tauto.is_cnf_ff_cnf_ff; Tauto.is_cnf_ff_inv; + Tauto.is_cnf_tt; Tauto.is_cnf_tt_cnf_ff; Tauto.is_cnf_tt_inv; + ConstructiveLUB.is_lub; Raxioms.is_lub; Znat.Nat2Z.is_nonneg; + BinInt.Pos2Z.is_nonneg; ZMicromega.is_pol_Z0; + ZMicromega.is_pol_Z0_eval_pol; Pnat.Pos2Nat.is_pos; BinInt.Pos2Z.is_pos; + Pnat.Pos2Nat.is_succ; is_true; ConstructiveLUB.is_upper_bound; + Raxioms.is_upper_bound; ConstructiveLUB.is_upper_bound_closed; + ConstructiveLUB.is_upper_bound_dec; + ConstructiveLUB.is_upper_bound_epsilon; + ConstructiveLUB.is_upper_bound_glb; + ConstructiveLUB.is_upper_bound_not_epsilon; BinPos.Pos.iter; + BinPos.Pos.iter_add; BinPos.Pos.iter_ind; BinPos.Pos.iter_invariant; + BinPos.Pos.iter_op; BinPos.Pos.iter_op_succ; BinPos.Pos.iter_succ; + BinPos.Pos.iter_swap; BinPos.Pos.iter_swap_gen; BinList.jump; Env.jump; + BinList.jump_add; Env.jump_add; Ring_polynom.jump_add'; + BinList.jump_pred_double; Env.jump_pred_double; Env.jump_simpl; + BinList.jump_succ; BinList.jump_tl; BinNat.N.le; BinPos.Pos.le; + BinInt.Z.le; ZMicromega.le_0_iff; BinNat.N.le_0_l; PeanoNat.Nat.le_0_l; + le_0_n; BinInt.Z.le_0_sub; BinPos.Pos.le_1_l; le_S_n; + BinInt.Z.le_add_le_sub_l; BinInt.Z.le_add_le_sub_r; + BinPos.Pos.le_antisym; BinPos.Pos.Private_Tac.le_antisym; + BinInt.Z.Private_OrderTac.Tac.le_antisym; BinInt.Z.le_antisymm; + Qminmax.Q.Private_Tac.le_eq; BinInt.Z.Private_Tac.le_eq; + BinInt.Z.Private_OrderTac.Tac.le_eq; BinInt.Z.le_exists_sub; + BinInt.Z.le_ge; BinInt.Z.le_ge_cases; BinNat.N.le_gt_cases; + PeanoNat.Nat.le_gt_cases; BinInt.Z.le_gt_cases; le_ind; BinInt.Z.le_ind; + BinNat.N.le_le_succ_r; PeanoNat.Nat.le_le_succ_r; BinInt.Z.le_le_succ_r; + BinInt.Z.le_lt_add_lt; Compare_dec.le_lt_dec; + PeanoNat.Nat.Private_Tac.le_lt_trans; + BinPos.Pos.Private_Tac.le_lt_trans; Qminmax.Q.Private_Tac.le_lt_trans; + BinInt.Z.Private_Tac.le_lt_trans; + BinNat.N.Private_OrderTac.Tac.le_lt_trans; + PeanoNat.Nat.Private_OrderTac.Tac.le_lt_trans; + BinInt.Z.Private_OrderTac.Tac.le_lt_trans; BinInt.Z.le_lt_trans; + BinNat.N.Private_OrderTac.IsTotal.le_lteq; + PeanoNat.Nat.Private_OrderTac.IsTotal.le_lteq; + BinInt.Z.Private_OrderTac.IsTotal.le_lteq; BinNat.N.le_lteq; + PeanoNat.Nat.le_lteq; BinPos.Pos.le_lteq; Qminmax.Q.OT.le_lteq; + BinInt.Z.le_lteq; PeanoNat.Nat.le_max_l; BinPos.Pos.le_max_l; + PeanoNat.Nat.le_max_r; BinPos.Pos.le_max_r; BinInt.Z.le_min_l; le_n_S; + ZMicromega.le_neg; BinInt.Z.le_neq; BinPos.Pos.Private_Tac.le_neq_lt; + BinInt.Z.Private_OrderTac.Tac.le_neq_lt; PeanoNat.Nat.le_ngt; + BinInt.Z.le_ngt; BinPos.Pos.le_nlt; le_pred; BinNat.N.le_preorder; + PeanoNat.Nat.le_preorder; BinInt.Z.le_preorder; BinNat.N.le_refl; + PeanoNat.Nat.le_refl; BinPos.Pos.le_refl; + BinInt.Z.Private_OrderTac.Tac.le_refl; BinInt.Z.le_refl; + BinInt.Z.le_sub_le_add_l; BinInt.Z.le_sub_le_add_r; BinNat.N.le_succ_l; + PeanoNat.Nat.le_succ_l; BinPos.Pos.le_succ_l; BinInt.Z.le_succ_l; + BinNat.N.le_succ_r; PeanoNat.Nat.le_succ_r; BinInt.Z.le_succ_r; + BinNat.N.le_trans; PeanoNat.Nat.le_trans; BinPos.Pos.le_trans; + BinInt.Z.le_trans; BinNat.N.le_wd; PeanoNat.Nat.le_wd; BinInt.Z.le_wd; + BinNat.N.leb; BinPos.Pos.leb; BinInt.Z.leb; BinInt.Z.leb_gt; + BinNat.N.leb_le; BinPos.Pos.leb_le; BinInt.Z.leb_le; BinInt.Z.leb_nle; + BinNat.N.leb_spec; BinInt.Z.leb_spec; BinNat.N.leb_spec0; + BinInt.Z.leb_spec0; BinInt.Z.left_induction; Rlimit.limit1_in; + Rlimit.limit_Ropp; Rlimit.limit_in; Rlimit.limit_minus; + Rlimit.limit_mul; Rlimit.limit_plus; + ConstructiveCauchyReals.linear_order_T; + ConstructiveEpsilon.linear_search_conform; + ConstructiveEpsilon.linear_search_from_0_conform; list_ind; list_rec; + list_rect; Ring_polynom.local_mkpow_ok; lt; BinNat.N.lt; BinPos.Pos.lt; + BinInt.Z.lt; BinInt.Z.lt_0_1; RIneq.lt_0_IZR; BinInt.Z.lt_0_sub; + PeanoNat.Nat.lt_0_succ; BinInt.Z.lt_1_2; BinInt.Z.lt_1_l; + BinInt.Z.lt_1_mul_pos; BinPos.Pos.lt_1_succ; + ConstructiveReals.lt_CR_of_Q; RIneq.lt_IZR; BinInt.Z.lt_add_lt_sub_r; + BinInt.Z.lt_add_pos_l; BinInt.Z.lt_add_pos_r; BinPos.Pos.lt_add_r; + BinNat.N.lt_asymm; PeanoNat.Nat.lt_asymm; BinInt.Z.lt_asymm; + BinNat.N.Private_OrderTac.IsTotal.lt_compat; + PeanoNat.Nat.Private_OrderTac.IsTotal.lt_compat; + BinInt.Z.Private_OrderTac.IsTotal.lt_compat; BinNat.N.lt_compat; + PeanoNat.Nat.lt_compat; BinPos.Pos.lt_compat; Qminmax.Q.OT.lt_compat; + BinInt.Z.lt_compat; BinPos.Pos.Private_Tac.lt_eq; + Qminmax.Q.Private_Tac.lt_eq; BinInt.Z.Private_Tac.lt_eq; + BinNat.N.Private_OrderTac.Tac.lt_eq; + PeanoNat.Nat.Private_OrderTac.Tac.lt_eq; + BinInt.Z.Private_OrderTac.Tac.lt_eq; BinNat.N.lt_eq_cases; + PeanoNat.Nat.lt_eq_cases; BinPos.Pos.lt_eq_cases; BinInt.Z.lt_eq_cases; + BinNat.N.lt_exists_pred; PeanoNat.Nat.lt_exists_pred; + BinInt.Z.lt_exists_pred; BinInt.Z.lt_ge_cases; BinPos.Pos.lt_gt; + BinInt.Z.lt_gt; BinInt.Z.lt_gt_cases; BinPos.Pos.lt_iff_add; + BinNat.N.lt_ind; BinInt.Z.lt_ind; BinNat.N.lt_ind_rel; + ConstructiveCauchyReals.lt_inject_Q; BinNat.N.lt_irrefl; + PeanoNat.Nat.lt_irrefl; BinPos.Pos.lt_irrefl; + PeanoNat.Nat.Private_Tac.lt_irrefl; BinPos.Pos.Private_Tac.lt_irrefl; + Qminmax.Q.Private_Tac.lt_irrefl; BinInt.Z.Private_Tac.lt_irrefl; + BinNat.N.Private_OrderTac.Tac.lt_irrefl; + PeanoNat.Nat.Private_OrderTac.Tac.lt_irrefl; + BinInt.Z.Private_OrderTac.Tac.lt_irrefl; BinInt.Z.lt_irrefl; + ZMicromega.lt_le_iff; BinNat.N.lt_le_incl; PeanoNat.Nat.lt_le_incl; + BinInt.Z.lt_le_incl; BinInt.Z.lt_le_pred; PeanoNat.Nat.lt_le_trans; + BinPos.Pos.lt_le_trans; BinInt.Z.lt_le_trans; BinNat.N.lt_lt_succ_r; + PeanoNat.Nat.lt_lt_succ_r; BinInt.Z.lt_lt_succ_r; BinInt.Z.lt_neq; + BinInt.Z.lt_nge; BinPos.Pos.lt_nle; + BinNat.N.Private_OrderTac.IsTotal.lt_strorder; + PeanoNat.Nat.Private_OrderTac.IsTotal.lt_strorder; + BinInt.Z.Private_OrderTac.IsTotal.lt_strorder; BinNat.N.lt_strorder; + PeanoNat.Nat.lt_strorder; BinPos.Pos.lt_strorder; + Qminmax.Q.OT.lt_strorder; BinInt.Z.lt_strorder; + BinInt.Z.lt_sub_lt_add_r; BinNat.N.lt_succ_diag_r; + PeanoNat.Nat.lt_succ_diag_r; BinPos.Pos.lt_succ_diag_r; + BinInt.Z.lt_succ_diag_r; BinNat.N.lt_succ_l; BinInt.Z.lt_succ_l; + BinNat.N.lt_succ_r; PeanoNat.Nat.lt_succ_r; BinPos.Pos.lt_succ_r; + BinInt.Z.lt_succ_r; BinNat.N.Private_OrderTac.IsTotal.lt_total; + PeanoNat.Nat.Private_OrderTac.IsTotal.lt_total; + BinInt.Z.Private_OrderTac.IsTotal.lt_total; BinNat.N.lt_total; + PeanoNat.Nat.lt_total; Qminmax.Q.OT.lt_total; BinPos.Pos.lt_total; + BinInt.Z.lt_total; BinNat.N.lt_trans; PeanoNat.Nat.lt_trans; + BinPos.Pos.lt_trans; PeanoNat.Nat.Private_Tac.lt_trans; + BinPos.Pos.Private_Tac.lt_trans; BinInt.Z.Private_Tac.lt_trans; + BinNat.N.Private_OrderTac.Tac.lt_trans; + PeanoNat.Nat.Private_OrderTac.Tac.lt_trans; + BinInt.Z.Private_OrderTac.Tac.lt_trans; BinInt.Z.lt_trans; + BinNat.N.lt_trichotomy; PeanoNat.Nat.lt_trichotomy; + BinInt.Z.lt_trichotomy; BinNat.N.lt_wd; PeanoNat.Nat.lt_wd; + BinInt.Z.lt_wd; PeanoNat.Nat.lt_wd_obligation_1; BinNat.N.lt_wf; + PeanoNat.Nat.lt_wf; BinInt.Z.lt_wf; BinInt.Z.ltb; BinInt.Z.ltb_ge; + BinInt.Z.ltb_lt; BinInt.Z.ltb_nlt; BinInt.Z.ltb_spec; + BinInt.Z.ltb_spec0; Wf_nat.ltof; ZMicromega.ltof_bdepth_split_l; + ZMicromega.ltof_bdepth_split_r; ZMicromega.makeCuttingPlane; + ZMicromega.makeCuttingPlane_ns_sound; Refl.make_conj; + Refl.make_conj_app; Refl.make_conj_cons; Refl.make_conj_impl; + Refl.make_conj_in; Refl.make_conj_rapp; Refl.make_impl; + Refl.make_impl_map; List.map; RingMicromega.map_Formula; + RingMicromega.map_PExpr; Tauto.map_bformula; RingMicromega.map_option; + RingMicromega.map_option2; BinPos.Pos.mask2cmp; PeanoNat.Nat.max; + BinNat.N.max; BinPos.Pos.max; BinInt.Z.max; BinPos.Pos.max_1_l; + BinInt.Z.max_case; BinPos.Pos.max_case_strong; + BinPos.Pos.Private_Dec.max_case_strong; + BinInt.Z.Private_Dec.max_case_strong; BinInt.Z.max_case_strong; + BinInt.Z.max_comm; max_l; PeanoNat.Nat.max_l; BinPos.Pos.max_l; + BinInt.Z.max_l; BinPos.Pos.max_le_compat_r; BinPos.Pos.max_lub_iff; + BinPos.Pos.max_mono; BinPos.Pos.max_monotone; max_r; PeanoNat.Nat.max_r; + BinPos.Pos.max_r; BinInt.Z.max_r; PeanoNat.Nat.max_spec; + BinPos.Pos.max_spec; BinInt.Z.max_spec; ZMicromega.max_var; + ZMicromega.max_var_acc; ZMicromega.max_var_nformulae; + ZMicromega.max_var_nformulae_mono_aux; + ZMicromega.max_var_nformulae_mono_aux'; + RingMicromega.micomega_sor_setoid; + RingMicromega.micomega_sor_setoid_Reflexive; + RingMicromega.micomega_sor_setoid_Symmetric; + RingMicromega.micomega_sor_setoid_Transitive; BinInt.Z.min; + BinInt.Z.Private_Dec.min_case; BinInt.Z.Private_Dec.min_case_strong; + BinInt.Z.Private_Dec.min_dec; BinInt.Z.min_dec; BinInt.Z.min_l; + BinInt.Z.min_r; BinInt.Z.min_spec; RIneq.minus_IPR; RIneq.minus_IZR; + Ranalysis1.minus_fct; EnvRing.mkPX; Ring_polynom.mkPX; + Ring_polynom.mkPX_ext; EnvRing.mkPX_ok; Ring_polynom.mkPX_ok; + EnvRing.mkPinj; Ring_polynom.mkPinj; Ring_polynom.mkPinj_ext; + EnvRing.mkPinj_ok; Ring_polynom.mkPinj_ok; EnvRing.mkPinj_pred; + Ring_polynom.mkPinj_pred; Ring_polynom.mkVmon; Ring_polynom.mkVmon_ok; + EnvRing.mkX; Ring_polynom.mkX; EnvRing.mkX_ok; Ring_polynom.mkX_ok; + EnvRing.mkXi; Ring_polynom.mkXi; Ring_polynom.mkZmon; + Ring_polynom.mkZmon_ok; EnvRing.mk_X; Ring_polynom.mk_X; Tauto.mk_and; + ZMicromega.mk_eq_pos; Tauto.mk_iff; Tauto.mk_iff_is_bool; Tauto.mk_impl; + Ring_polynom.mk_monpol_list; Tauto.mk_or; Ring_polynom.mkadd_mult; + Ring_polynom.mkadd_mult_ok; ZifyClasses.mkapp; ZifyClasses.mkapp2; + Ring_polynom.mkmult1; Ring_polynom.mkmult1_ok; Ring_polynom.mkmult_c; + Ring_polynom.mkmult_c_ok; Ring_polynom.mkmult_c_pos; + Ring_polynom.mkmult_c_pos_ok; Ring_polynom.mkmult_pow; + Ring_polynom.mkmult_pow_ok; Ring_polynom.mkmult_rec; + Ring_polynom.mkmult_rec_ok; Ring_polynom.mkmultm1; + Ring_polynom.mkmultm1_ok; Ring_polynom.mkopp_pow; + Ring_polynom.mkopp_pow_ok; Ring_polynom.mkpow; Ring_polynom.mkpow_ok; + ZifyClasses.mkrel; BinInt.Z.mod_eq; BinInt.Z.mod_mul; + BinInt.Z.mod_neg_bound; BinInt.Z.mod_pos_bound; BinInt.Z.modulo; + Ring_polynom.mon_of_pol; Ring_polynom.mon_of_pol_ok; Ring_theory.morph0; + Ring_theory.morph1; Ring_theory.morph_add; Ring_theory.morph_eq; + Ring_theory.morph_mul; Ring_theory.morph_opp; Ring_theory.morph_sub; + Nat.mul; BinNat.N.mul; BinPos.Pos.mul; BinInt.Z.mul; BinNat.N.mul_0_l; + BinInt.Z.mul_0_l; BinNat.N.mul_0_r; BinInt.Z.Private_BootStrap.mul_0_r; + BinInt.Z.mul_0_r; BinPos.Pos.mul_1_l; + BinInt.Z.Private_BootStrap.mul_1_l; BinInt.Z.mul_1_l; + BinPos.Pos.mul_1_r; BinInt.Z.mul_1_r; BinPos.Pos.mul_add_distr_l; + BinInt.Z.mul_add_distr_l; BinInt.Z.Private_BootStrap.mul_add_distr_pos; + BinPos.Pos.mul_add_distr_r; BinInt.Z.Private_BootStrap.mul_add_distr_r; + BinInt.Z.mul_add_distr_r; BinPos.Pos.mul_assoc; BinInt.Z.mul_assoc; + BinInt.Z.mul_cancel_l; BinInt.Z.mul_cancel_r; BinNat.N.mul_comm; + BinPos.Pos.mul_comm; BinInt.Z.mul_comm; BinPos.Pos.mul_compare_mono_l; + BinPos.Pos.mul_compare_mono_r; BinInt.Z.mul_div_le; BinInt.Z.mul_eq_0; + Rlimit.mul_factor; Rlimit.mul_factor_gt; Rlimit.mul_factor_gt_f; + Rlimit.mul_factor_wd; BinInt.Z.mul_id_l; BinPos.Pos.mul_le_mono_l; + BinInt.Z.mul_le_mono_nonneg; BinInt.Z.mul_le_mono_nonneg_l; + BinInt.Z.mul_le_mono_nonneg_r; BinInt.Z.mul_le_mono_nonpos_l; + BinInt.Z.mul_le_mono_nonpos_r; BinInt.Z.mul_le_mono_pos_l; + BinInt.Z.mul_le_mono_pos_r; BinPos.Pos.mul_lt_mono_l; + BinInt.Z.mul_lt_mono_neg_l; BinInt.Z.mul_lt_mono_neg_r; + BinInt.Z.mul_lt_mono_nonneg; BinInt.Z.mul_lt_mono_pos_l; + BinInt.Z.mul_lt_mono_pos_r; BinPos.Pos.mul_lt_mono_r; + BinInt.Z.mul_lt_pred; BinInt.Z.mul_neg_neg; BinInt.Z.mul_neg_pos; + BinInt.Z.mul_nonneg_nonneg; BinInt.Z.mul_nonneg_nonpos; + BinInt.Z.mul_opp_comm; BinInt.Z.mul_opp_l; BinInt.Z.mul_opp_opp; + BinInt.Z.Private_BootStrap.mul_opp_r; BinInt.Z.mul_opp_r; + BinInt.Z.mul_pos_cancel_l; BinInt.Z.mul_pos_neg; BinInt.Z.mul_pos_pos; + BinInt.Z.mul_reg_r; BinInt.Z.mul_shuffle0; BinInt.Z.mul_shuffle1; + BinPos.Pos.mul_sub_distr_l; BinPos.Pos.mul_sub_distr_r; + BinNat.N.mul_succ_l; BinPos.Pos.mul_succ_l; BinInt.Z.mul_succ_l; + BinNat.N.mul_succ_r; BinPos.Pos.mul_succ_r; BinInt.Z.mul_succ_r; + BinNat.N.mul_wd; BinInt.Z.mul_wd; BinPos.Pos.mul_xI_r; + BinPos.Pos.mul_xO_r; RIneq.mult_IPR; RIneq.mult_IZR; + Ring_polynom.mult_dev; Ring_polynom.mult_dev_ok; Ranalysis1.mult_fct; + ZMicromega.narrow_interval_lower_bound; Znat.nat_N_Z; + Compare_dec.nat_compare_ge; Compare_dec.nat_compare_le; + Compare_dec.nat_compare_lt; nat_ind; nat_rec; nat_rect; RIneq.neg; + BinInt.Pos2Z.neg_is_neg; ZMicromega.negate; ZMicromega.negate_correct; + negb; Bool.negb_false_iff; Bool.negb_true_iff; Rtopology.neighbourhood; + PeanoNat.Nat.neq_0_lt_0; RelationClasses.neq_Symmetric; + BinPos.Pos.Private_Tac.neq_eq; BinInt.Z.Private_OrderTac.Tac.neq_eq; + BinNat.N.neq_succ_0; PeanoNat.Nat.neq_succ_0; BinNat.N.neq_succ_diag_l; + PeanoNat.Nat.neq_succ_diag_l; BinInt.Z.neq_succ_diag_l; + BinInt.Z.Private_OrderTac.Tac.neq_sym; BinInt.Z.neq_sym; + ZMicromega.nformula_of_cutting_plane; + RingMicromega.nformula_plus_nformula; + RingMicromega.nformula_plus_nformula_correct; + RingMicromega.nformula_times_nformula; + RingMicromega.nformula_times_nformula_correct; BinInt.Z.nle_gt; + BinNat.N.nle_succ_diag_l; PeanoNat.Nat.nle_succ_diag_l; + BinInt.Z.nle_succ_diag_l; PeanoNat.Nat.nlt_0_r; BinPos.Pos.nlt_1_r; + BinInt.Z.nlt_ge; BinNat.N.nlt_succ_diag_l; PeanoNat.Nat.nlt_succ_diag_l; + BinInt.Z.nlt_succ_diag_l; Ranalysis1.no_cond; RingMicromega.norm; + ZMicromega.normZ; EnvRing.norm_aux; Ring_polynom.norm_aux; + EnvRing.norm_aux_PEadd; Ring_polynom.norm_aux_PEadd; + EnvRing.norm_aux_PEopp; Ring_polynom.norm_aux_PEopp; + EnvRing.norm_aux_spec; Ring_polynom.norm_aux_spec; + Ring_polynom.norm_subst; Ring_polynom.norm_subst_ok; + Ring_polynom.norm_subst_spec; RingMicromega.normalise; + ZMicromega.normalise; ZMicromega.normalise_correct; + RingMicromega.normalise_sound; not; RIneq.not_0_IZR; + ZArith_dec.not_Zeq_inf; Classical_Pred_Type.not_all_ex_not; + Classical_Pred_Type.not_all_not_ex; Classical_Prop.not_and_or; + not_eq_sym; Classical_Pred_Type.not_ex_all_not; + BinPos.Pos.Private_Tac.not_ge_lt; + BinNat.N.Private_OrderTac.Tac.not_ge_lt; + PeanoNat.Nat.Private_OrderTac.Tac.not_ge_lt; + BinInt.Z.Private_OrderTac.Tac.not_ge_lt; + PeanoNat.Nat.Private_Tac.not_gt_le; BinPos.Pos.Private_Tac.not_gt_le; + Qminmax.Q.Private_Tac.not_gt_le; BinInt.Z.Private_Tac.not_gt_le; + BinNat.N.Private_OrderTac.Tac.not_gt_le; + PeanoNat.Nat.Private_OrderTac.Tac.not_gt_le; + BinInt.Z.Private_OrderTac.Tac.not_gt_le; + Morphisms_Prop.not_iff_morphism; + Morphisms_Prop.not_iff_morphism_obligation_1; + Classical_Prop.not_imply_elim; Classical_Prop.not_imply_elim2; + BinPos.Pos.Private_Tac.not_neq_eq; + BinInt.Z.Private_OrderTac.Tac.not_neq_eq; Bool.not_true_iff_false; + BinList.nth; Env.nth; List.nth; List.nth_in_or_default; + BinList.nth_jump; Env.nth_jump; BinList.nth_pred_double; + Env.nth_pred_double; Env.nth_spec; Field_theory.num; BinInt.Z.of_N; + BinNat.N.of_nat; BinPos.Pos.of_nat; BinInt.Z.of_nat; + BinPos.Pos.of_nat_succ; BinPos.Pos.of_succ_nat; BinInt.Z.one_succ; + Rtopology.open_set; Rtopology.open_set_P1; Rtopology.open_set_P4; + Rtopology.open_set_P6; BinInt.Z.opp; BinInt.Z.opp_0; RIneq.opp_IZR; + BinInt.Z.Private_BootStrap.opp_add_distr; BinInt.Z.opp_add_distr; + Ranalysis1.opp_fct; BinInt.Z.Private_BootStrap.opp_inj; + BinInt.Z.opp_inj; BinInt.Z.opp_inj_wd; + ConstructiveCauchyReals.opp_inject_Q; BinInt.Z.opp_involutive; + BinInt.Z.opp_le_mono; BinInt.Z.opp_lt_mono; BinInt.Z.opp_nonneg_nonpos; + BinInt.Z.opp_nonpos_nonneg; BinInt.Pos2Z.opp_pos; BinInt.Z.opp_pred; + BinInt.Z.opp_sub_distr; BinInt.Z.opp_succ; BinInt.Z.opp_wd; or_cancel_r; + Tauto.or_clause; Tauto.or_clause_cnf; Tauto.or_clause_cnf_correct; + Tauto.or_clause_correct; Tauto.or_cnf; Tauto.or_cnf_correct; + Tauto.or_cnf_opt; Tauto.or_cnf_opt_cnf_ff; Tauto.or_cnf_opt_cnf_ff_r; + Tauto.or_cnf_opt_correct; or_comm; or_iff_compat_r; + Morphisms_Prop.or_iff_morphism; + Morphisms_Prop.or_iff_morphism_obligation_1; or_ind; orb; Bool.orb_comm; + Bool.orb_true_iff; BinInt.Z.order_induction; BinInt.Z.order_induction_0; + RingMicromega.padd; ZMicromega.padd; BinPos.Pos.peano_ind; + BinInt.Z.peano_ind; BinNat.N.peano_rect; BinPos.Pos.peano_rect; + Morphisms.per_partial_app_morphism; + Morphisms.per_partial_app_morphism_obligation_1; + RingMicromega.pexpr_times_nformula; + RingMicromega.pexpr_times_nformula_correct; Ring_theory.phi_ext1_Proper; + RIneq.plus_IPR; RIneq.plus_IZR; RIneq.plus_IZR_NEG_POS; plus_Sn_m; + plus_n_O; plus_n_Sm; Rtopology.point_adherent; + Morphisms.pointwise_relation; QMicromega.pop2_bop2; + RMicromega.pop2_bop2; ZMicromega.pop2_bop2; RingMicromega.popp; + ZMicromega.popp; RIneq.pos; BinNat.N.pos_div_eucl; + BinInt.Z.pos_div_eucl; BinInt.Z.pos_div_eucl_bound; + BinInt.Z.pos_div_eucl_eq; BinNat.N.pos_div_eucl_spec; + BinInt.Pos2Z.pos_is_pos; BinInt.Pos2Z.pos_le_pos; BinInt.Z.pos_sub; + BinInt.Z.Private_BootStrap.pos_sub_add; BinInt.Z.pos_sub_diag; + BinInt.Z.pos_sub_discr; BinInt.Z.pos_sub_gt; BinInt.Z.pos_sub_lt; + BinInt.Z.pos_sub_opp; BinInt.Z.pos_sub_spec; Znat.positive_N_nat; + BinNums.positive_ind; Znat.positive_nat_Z; BinNums.positive_rec; + BinNums.positive_rect; Rpow_def.pow; BinPos.Pos.pow; BinInt.Z.pow; + BinInt.Z.pow_0_r; BinInt.Z.pow_1_l; BinPos.Pos.pow_1_r; + BinInt.Z.pow_1_r; Ring_theory.pow_N; Field_theory.pow_N_ext; + Ring_theory.pow_N_pow_N; Ring_theory.pow_N_th; BinInt.Z.pow_add_r; + Field_theory.pow_ext; BinInt.Z.pow_gt_1; BinInt.Z.pow_le_mono_r; + BinInt.Z.pow_lt_mono_l; BinInt.Z.pow_lt_mono_r; BinInt.Z.pow_neg_r; + BinInt.Z.pow_nonneg; Ring_theory.pow_pos; BinInt.Z.pow_pos; + Field_theory.pow_pos_0; Field_theory.pow_pos_1; EnvRing.pow_pos_add; + Ring_polynom.pow_pos_add; Ring_theory.pow_pos_add; + Field_theory.pow_pos_add_r; Field_theory.pow_pos_cst; + Field_theory.pow_pos_div; Field_theory.pow_pos_mul_l; + Field_theory.pow_pos_mul_r; BinInt.Z.pow_pos_nonneg; + Field_theory.pow_pos_nz; Ring_theory.pow_pos_succ; + Ring_theory.pow_pos_swap; BinPos.Pos.pow_succ_r; BinInt.Z.pow_succ_r; + BinInt.Z.pow_twice_r; BinInt.Z.pow_wd; Rfunctions.powerRZ; + Ranalysis1.pr_nu; Ranalysis4.pr_nu_var; PeanoNat.Nat.pred; + BinNat.N.pred; BinPos.Pos.pred; BinInt.Z.pred; BinNat.N.pred_0; + PeanoNat.Nat.pred_0; BinPos.Pos.pred_N; BinPos.Pos.pred_N_succ; + BinPos.Pos.pred_double; BinInt.Z.pred_double; + BinPos.Pos.pred_double_succ; BinInt.Z.pred_inj; BinInt.Z.pred_inj_wd; + BinPos.Pos.pred_mask; BinNat.N.pred_succ; PeanoNat.Nat.pred_succ; + BinInt.Z.pred_succ; BinNat.N.pred_wd; PeanoNat.Nat.pred_wd; + BinInt.Z.pred_wd; PeanoNat.Nat.pred_wd_obligation_1; prod_ind; + prod_rect; proj1; proj1_sig; proj2; proj2_sig; + Rtopology.prolongement_C0; Rlimit.prop_eps; Morphisms.proper_prf; + Morphisms.proper_sym_impl_iff; RingMicromega.psub; ZMicromega.psub; + RingMicromega.psubC; QMicromega.qdeduce; QMicromega.qunsat; + BinInt.Z.quotrem; BinInt.Z.quotrem_eq; Ring_polynom.r_list_pow; + Ring_polynom.r_list_pow_rev; Field_theory.radd_ext; + Ring_theory.radd_ext2_Proper; InitialRing.radd_ext3_Proper; + InitialRing.radd_ext4_Proper; EnvRing.radd_ext_Proper; + Field_theory.radd_ext_Proper; InitialRing.radd_ext_Proper; + Ring_polynom.radd_ext_Proper; RMicromega.rdeduce; Field_theory.rdiv1; + Field_theory.rdiv2b; Field_theory.rdiv3b; Field_theory.rdiv4; + Field_theory.rdiv4b; Field_theory.rdiv5; Field_theory.rdiv6; + Field_theory.rdiv7; Field_theory.rdiv7b; Field_theory.rdiv_ext; + Field_theory.rdiv_r_r; Field_theory.rdiv_simpl; + Morphisms.reflexive_eq_dom_reflexive; Morphisms.reflexive_proper; + CMorphisms.reflexive_proper_proxy; Morphisms.reflexive_proper_proxy; + Morphisms.reflexive_reflexive_proxy; RelationClasses.reflexivity; + ConstructiveEpsilon.rel_ls_ind; ConstructiveEpsilon.rel_ls_post; + Relation_Definitions.relation; CMorphisms.respectful; + Morphisms.respectful; Rtopology.restriction_family; List.rev'; + List.rev_append; ZifyClasses.rew_iff; ZifyClasses.rew_iff_rev; + Morphisms.rewrite_relation_eq_dom; BinNat.N.right_induction; + PeanoNat.Nat.right_induction; BinInt.Z.right_induction; + Ring_polynom.ring_correct; Ring_polynom.ring_rw_correct; + Ring_polynom.ring_rw_pow_correct; Ring_tac.ring_subst_niter; + Field_theory.rinv_ext_Proper; OrderedRing.rle_morph_Proper; + RingMicromega.rle_morph_Proper; OrderedRing.rlt_morph_Proper; + RingMicromega.rlt_morph_Proper; OrderedRing.rminus_morph; + OrderedRing.rminus_morph_Proper; RingMicromega.rminus_morph_Proper; + Field_theory.rmul_ext; Ring_theory.rmul_ext2_Proper; + InitialRing.rmul_ext3_Proper; InitialRing.rmul_ext4_Proper; + EnvRing.rmul_ext_Proper; Field_theory.rmul_ext_Proper; + InitialRing.rmul_ext_Proper; Ring_polynom.rmul_ext_Proper; + Field_theory.rmul_reg_l; Ring_theory.ropp_ext2_Proper; + InitialRing.ropp_ext3_Proper; EnvRing.ropp_ext_Proper; + Field_theory.ropp_ext_Proper; Ring_polynom.ropp_ext_Proper; + OrderedRing.ropp_morph_Proper; RingMicromega.ropp_morph_Proper; + Field_theory.ropp_neq_0; OrderedRing.rplus_morph_Proper; + RingMicromega.rplus_morph_Proper; Ring_theory.rpow_pow_N; + Field_theory.rsplit_common; Field_theory.rsplit_left; + Field_theory.rsplit_right; Field_theory.rsub_0_l; Field_theory.rsub_0_r; + EnvRing.rsub_ext_Proper; Field_theory.rsub_ext_Proper; + Ring_polynom.rsub_ext_Proper; OrderedRing.rtimes_morph_Proper; + RingMicromega.rtimes_morph_Proper; Tauto.rtyp; RMicromega.runsat; + InitialRing.same_gen; InitialRing.same_genN; InitialRing.same_genZ; + ConstructiveCauchyReals.scale; ConstructiveCauchyReals.seq; + ConstructiveRcomplete.seq_cv; BinInt.Z.sgn; + ClassicalDedekindReals.sig_forall_dec; ConstructiveLUB.sig_forall_dec_T; + sig_ind; ConstructiveLUB.sig_lub; ClassicalDedekindReals.sig_not_dec; + ConstructiveLUB.sig_not_dec_T; sig_rec; sig_rect; Ring_theory.sign_spec; + Rlimit.single_limit; BinPos.Pos.size_nat; BinPos.Pos.size_nat_monotone; + snd; OrderedRing.sor_setoid; OrderedRing.sor_setoid_Reflexive; + OrderedRing.sor_setoid_Symmetric; OrderedRing.sor_setoid_Transitive; + Field_theory.split; Field_theory.split_aux; Field_theory.split_aux_ok; + Field_theory.split_aux_ok1; Field_theory.split_nz_l; + Field_theory.split_nz_r; Field_theory.split_ok_l; + Field_theory.split_ok_r; BinInt.Z.strong_left_induction; + BinNat.N.strong_right_induction; PeanoNat.Nat.strong_right_induction; + BinInt.Z.strong_right_induction; BinNat.N.sub; BinPos.Pos.sub; + BinInt.Z.sub; BinInt.Z.sub_0_l; BinNat.N.sub_0_r; BinInt.Z.sub_0_r; + BinInt.Z.sub_1_r; BinNat.N.sub_add; BinPos.Pos.sub_add; + BinPos.Pos.sub_add_distr; BinInt.Z.sub_cancel_r; BinPos.Pos.sub_decr; + BinNat.N.sub_diag; BinInt.Z.sub_diag; BinNat.N.sub_gt; + BinInt.Z.sub_le_mono_r; BinInt.Z.sub_lt_mono_r; BinPos.Pos.sub_mask; + BinPos.Pos.sub_mask_add; BinPos.Pos.sub_mask_add_diag_l; + BinPos.Pos.sub_mask_add_diag_r; BinPos.Pos.sub_mask_carry; + BinPos.Pos.sub_mask_carry_spec; BinPos.Pos.sub_mask_diag; + BinPos.Pos.sub_mask_neg_iff; BinPos.Pos.sub_mask_nul_iff; + BinPos.Pos.sub_mask_pos; BinPos.Pos.sub_mask_pos'; + BinPos.Pos.sub_mask_pos_iff; BinPos.Pos.sub_mask_spec; + BinPos.Pos.sub_mask_succ_r; BinInt.Z.sub_move_0_r; BinInt.Z.sub_move_r; + BinInt.Z.sub_opp_r; BinInt.Z.sub_simpl_r; BinPos.Pos.sub_sub_distr; + BinInt.Z.sub_sub_distr; BinNat.N.sub_succ; BinInt.Z.sub_succ_l; + BinNat.N.sub_succ_r; BinInt.Z.sub_succ_r; BinNat.N.sub_wd; + BinInt.Z.sub_wd; BinPos.Pos.sub_xI_xI; BinPos.Pos.sub_xI_xO; + BinPos.Pos.sub_xO_xI; BinPos.Pos.sub_xO_xO; Rtopology.subfamily; + CRelationClasses.subrelation; RelationClasses.subrelation; + CMorphisms.subrelation_proper; Morphisms.subrelation_proper; + CMorphisms.subrelation_refl; Morphisms.subrelation_refl; + CMorphisms.subrelation_respectful; Morphisms.subrelation_respectful; + BinNat.N.succ; BinPos.Pos.succ; BinInt.Z.succ; RIneq.succ_IPR; + BinNat.N.succ_double; BinInt.Z.succ_double; BinNat.N.succ_double_add; + BinPos.Pos.succ_double_mask; BinNat.N.succ_double_mul; + BinInt.Z.succ_double_spec; BinNat.N.succ_inj; PeanoNat.Nat.succ_inj; + BinPos.Pos.succ_inj; BinInt.Z.succ_inj; BinNat.N.succ_inj_wd; + PeanoNat.Nat.succ_inj_wd; BinInt.Z.succ_inj_wd; + PeanoNat.Nat.succ_le_mono; BinInt.Z.succ_le_mono; + PeanoNat.Nat.succ_lt_mono; BinPos.Pos.succ_lt_mono; + BinInt.Z.succ_lt_mono; BinPos.Pos.succ_not_1; BinInt.Z.succ_pred; + BinPos.Pos.succ_pred_double; BinPos.Pos.succ_pred_or; BinNat.N.succ_wd; + PeanoNat.Nat.succ_wd; BinInt.Z.succ_wd; + PeanoNat.Nat.succ_wd_obligation_1; sumbool_rec; sumbool_rect; + RMicromega.sumboolb; BinPos.Pos.switch_Eq; CRelationClasses.symmetry; + RelationClasses.symmetry; Env.tail; Tauto.tauto_checker; + Tauto.tauto_checker_sound; List.tl; BinInt.Z.to_N; BinNat.N.to_nat; + BinPos.Pos.to_nat; BinInt.Z.to_nat; BinInt.Z.to_pos; + Rdefinitions.total_order_T; PeanoNat.Nat.Private_Tac.trans; + BinPos.Pos.Private_Tac.trans; Qminmax.Q.Private_Tac.trans; + BinInt.Z.Private_Tac.trans; BinNat.N.Private_OrderTac.Tac.trans; + PeanoNat.Nat.Private_OrderTac.Tac.trans; + BinInt.Z.Private_OrderTac.Tac.trans; + Morphisms.trans_co_eq_inv_impl_morphism; + Morphisms.trans_co_eq_inv_impl_morphism_obligation_1; + Morphisms.trans_co_impl_morphism; + Morphisms.trans_co_impl_morphism_obligation_1; + CMorphisms.trans_contra_inv_impl_type_morphism; + CMorphisms.trans_contra_inv_impl_type_morphism_obligation_1; + OrdersTac.trans_ord; Morphisms.trans_sym_co_inv_impl_morphism; + Morphisms.trans_sym_co_inv_impl_morphism_obligation_1; + CRelationClasses.transitivity; RelationClasses.transitivity; + InitialRing.triv_div; InitialRing.triv_div_th; BinInt.Z.two_succ; + Ranalysis1.uniqueness_limite; Ranalysis1.uniqueness_step1; + Ranalysis1.uniqueness_step2; Ranalysis1.uniqueness_step3; + ZMicromega.valid_cut_sign; well_founded; well_founded_ind; + well_founded_induction; well_founded_induction_type; + Wf_nat.well_founded_ltof; BinPos.Pos.xI_succ_xO; Tauto.xcnf; + Tauto.xcnf_correct; Tauto.xcnf_iff; Tauto.xcnf_impl; + RingMicromega.xnegate; ZMicromega.xnegate; + RingMicromega.xnegate_correct; ZMicromega.xnegate_correct; + ZMicromega.xnnormalise; ZMicromega.xnnormalise_correct; + RingMicromega.xnormalise; ZMicromega.xnormalise; + RingMicromega.xnormalise_correct; ZMicromega.xnormalise_correct; + Tauto.xor_clause_cnf; RMicromega.z_of_exp; Ring_polynom.zmon_pred; + Ring_polynom.zmon_pred_ok; Acc; BoolSpec; ConstructiveCauchyReals.CReal; + CompareSpec; CompareSpecT; ConstructiveReals.ConstructiveReals; + ConstructiveLUB.DedekindDecCut; SetoidTactics.DefaultRelation; + CRelationClasses.Equivalence; RelationClasses.Equivalence; + Field_theory.FExpr; False; RingMicromega.Formula; Tauto.GFormula; + ZifyClasses.InjTyp; Rlimit.Metric_Space; Ring_polynom.Mon; BinNums.N; + RingMicromega.Op1; RingMicromega.Op2; RelationClasses.PER; + EnvRing.PExpr; Ring_polynom.PExpr; EnvRing.Pol; Ring_polynom.Pol; + RelationClasses.PreOrder; RingMicromega.Psatz; QArith_base.Q; + RMicromega.Rcst; RelationClasses.RewriteRelation; OrderedRing.SOR; + RingMicromega.SORaddon; RelationClasses.StrictOrder; + BinPos.Pos.SubMaskSpec; True; BinNums.Z; ZMicromega.ZArithProof; + ZMicromega.Zdivide_pol; Znumtheory.Zis_gcd; + Field_theory.almost_field_theory; Ring_theory.almost_ring_theory; and; + ConstructiveEpsilon.before_witness; bool; comparison; + Ring_theory.div_theory; eq; ex; Rtopology.family; + Field_theory.field_theory; Tauto.kind; le; Field_theory.linear; list; + BinPos.Pos.mask; nat; RIneq.negreal; option; or; OrdersTac.ord; + BinNums.positive; RIneq.posreal; Ring_theory.power_theory; prod; + Bool.reflect; ConstructiveEpsilon.rel_ls; Ring_theory.ring_eq_ext; + Ring_theory.ring_morph; Ring_theory.ring_theory; Field_theory.rsplit; + Ring_theory.semi_morph; Ring_theory.semi_ring_theory; sig; sigT; + Ring_theory.sign_theory; Ring_theory.sring_eq_ext; sum; sumbool; sumor; + VarMap.t; unit; Acc_intro; BoolSpecT; ConstructiveCauchyReals.mkCReal; + CompEq; CompEqT; ConstructiveReals.Build_ConstructiveReals; + ConstructiveLUB.Build_DedekindDecCut; + SetoidTactics.Build_DefaultRelation; CRelationClasses.Build_Equivalence; + RelationClasses.Build_Equivalence; Field_theory.FEO; + RingMicromega.Build_Formula; Tauto.TT; ZifyClasses.mkinj; + Rlimit.Build_Metric_Space; Ring_polynom.mon0; BinNums.N0; + RingMicromega.Equal; RingMicromega.OpEq; RelationClasses.Build_PER; + EnvRing.PEc; Ring_polynom.PEO; EnvRing.Pc; Ring_polynom.Pc; + RelationClasses.Build_PreOrder; RingMicromega.PsatzLet; + QArith_base.Qmake; RMicromega.C0; RelationClasses.Build_RewriteRelation; + OrderedRing.mk_SOR_theory; RingMicromega.mk_SOR_addon; + RelationClasses.Build_StrictOrder; BinPos.Pos.SubIsNul; I; BinNums.Z0; + ZMicromega.DoneProof; ZMicromega.Zdiv_Pc; Znumtheory.Zis_gcd_intro; + Field_theory.mk_afield; Ring_theory.mk_art; conj; + ConstructiveEpsilon.stop; true; Eq; Ring_theory.mkdiv_th; eq_refl; + ex_intro; Rtopology.mkfamily; Field_theory.mk_field; Tauto.isProp; le_n; + Field_theory.mk_linear; nil; BinPos.Pos.IsNul; O; RIneq.mknegreal; Some; + or_introl; OrdersTac.OEQ; BinNums.xI; RIneq.mkposreal; + Ring_theory.mkpow_th; pair; Bool.ReflectT; ConstructiveEpsilon.Rstop; + Ring_theory.mk_reqe; Ring_theory.mkmorph; Ring_theory.mk_rt; + Field_theory.mk_rsplit; Ring_theory.mkRmorph; Ring_theory.mk_srt; exist; + existT; Ring_theory.mksign_th; Ring_theory.mk_seqe; inl; left; inleft; + VarMap.Empty; tt; BoolSpecF; CompLt; CompLtT; Field_theory.FEI; + Tauto.FF; Ring_polynom.zmon; BinNums.Npos; RingMicromega.NonEqual; + RingMicromega.OpNEq; EnvRing.PEX; Ring_polynom.PEI; EnvRing.Pinj; + Ring_polynom.Pinj; RingMicromega.PsatzIn; RMicromega.C1; + BinPos.Pos.SubIsPos; BinNums.Zpos; ZMicromega.RatProof; + ZMicromega.Zdiv_Pinj; ConstructiveEpsilon.next; false; Lt; Tauto.isBool; + le_S; cons; BinPos.Pos.IsPos; S; None; or_intror; OrdersTac.OLT; + BinNums.xO; Bool.ReflectF; ConstructiveEpsilon.Rnext; inr; right; + inright; VarMap.Elt; CompGt; CompGtT; Field_theory.FEc; Tauto.X; + Ring_polynom.vmon; RingMicromega.Strict; RingMicromega.OpLe; + EnvRing.PEadd; Ring_polynom.PEc; EnvRing.PX; Ring_polynom.PX; + RingMicromega.PsatzSquare; RMicromega.CQ; BinPos.Pos.SubIsNeg; + BinNums.Zneg; ZMicromega.CutProof; ZMicromega.Zdiv_PX; Gt; + BinPos.Pos.IsNeg; OrdersTac.OLE; BinNums.xH; VarMap.Branch; + Field_theory.FEX; Tauto.A; RingMicromega.NonStrict; RingMicromega.OpGe; + EnvRing.PEsub; Ring_polynom.PEX; RingMicromega.PsatzMulC; RMicromega.CZ; + ZMicromega.SplitProof; Field_theory.FEadd; Tauto.AND; + RingMicromega.OpLt; EnvRing.PEmul; Ring_polynom.PEadd; + RingMicromega.PsatzMulE; RMicromega.CPlus; ZMicromega.EnumProof; + Field_theory.FEsub; Tauto.OR; RingMicromega.OpGt; EnvRing.PEopp; + Ring_polynom.PEsub; RingMicromega.PsatzAdd; RMicromega.CMinus; + ZMicromega.ExProof; Field_theory.FEmul; Tauto.NOT; EnvRing.PEpow; + Ring_polynom.PEmul; RingMicromega.PsatzC; RMicromega.CMult; + Field_theory.FEopp; Tauto.IMPL; Ring_polynom.PEopp; + RingMicromega.PsatzZ; RMicromega.CPow; Field_theory.FEinv; Tauto.IFF; + Ring_polynom.PEpow; RMicromega.CInv; Field_theory.FEdiv; Tauto.EQ; + RMicromega.COpp; Field_theory.FEpow; }} + Spilled_1 = 3375 + T = __TIME__ + Query assignments: + S = {{ Nat.add; eq; nat; O; }} + Spilled_1 = 4 + T = prod `x` (global (indt «nat»)) c0 \ + app + [global (indt «eq»), X0 c0, + app [global (const «Nat.add»), c0, global (indc «O»)], c0] + _uvk_18_ = c0 \ + X0 c0 + Syntactic constraints: + {c0} : decl c0 `x` (global (indt «nat»)) ?- evar (X0 c0) (X1 c0) (X0 c0) /* suspended on X0 */ + {c0} : decl c0 `x` (global (indt «nat»)) + ?- evar (X2 c0) (sort (typ «test.test.30»)) (X1 c0) /* suspended on X2, X1 */ + Universe constraints: + UNIVERSES: + {test.test.30} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α8 + WEAK CONSTRAINTS: + + + Query assignments: + Decl = record Rec (sort (typ «test.test.31»)) BuildRec + (field [] f (sort (typ «test.test.32»)) c0 \ end-record) + _uvk_27_ = «test.test.31» + _uvk_28_ = «test.test.32» + Universe constraints: + UNIVERSES: + {test.test.32 test.test.31} |= + ALGEBRAIC UNIVERSES: + {test.test.32 test.test.31} + FLEXIBLE UNIVERSES: + test.test.32 + test.test.31 + SORTS: + + WEAK CONSTRAINTS: + + + Module + Test + := Struct + Record Rec@{u u0} : Type@{u} := BuildRec + { f : Type@{u0} }. + (* u u0 |= u0 < u *) + Definition f : Rec@{u u0} -> Type@{u0}. + (* u u0 |= u0 < u *) + End + + Test.f@{test.test.33 + test.test.34} + : Test.Rec@{test.test.33 test.test.34} -> Type@{test.test.34} + (* {test.test.34 test.test.33} |= test.test.34 < test.test.33 *) + Query assignments: + LP = «Coq.ZArith.Znat» + MP = «Coq.ZArith.Znat.N2Z» diff --git a/tests/test_API_env.v b/tests/API_env.t/test.v similarity index 100% rename from tests/test_API_env.v rename to tests/API_env.t/test.v diff --git a/tests/API_module.t/run.t b/tests/API_module.t/run.t new file mode 100644 index 000000000..cd92fa74f --- /dev/null +++ b/tests/API_module.t/run.t @@ -0,0 +1,59 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "dune", line 6, characters 0-42: + 6 | (coq.theory + 7 | (name test) + 8 | (theories elpi)) + Query assignments: + L = [gref (indt «Empty_set»), gref (const «Empty_set_rect»), + gref (const «Empty_set_ind»), gref (const «Empty_set_rec»), + gref (const «Empty_set_sind»), gref (indt «unit»), + gref (const «unit_rect»), gref (const «unit_ind»), + gref (const «unit_rec»), gref (const «unit_sind»), + gref (indt «bool»), gref (const «bool_rect»), + gref (const «bool_ind»), gref (const «bool_rec»), + gref (const «bool_sind»), gref (const «andb»), gref (const «orb»), + gref (const «implb»), gref (const «xorb»), gref (const «negb»), + gref (const «andb_prop»), gref (const «andb_true_intro»), + gref (indt «eq_true»), gref (const «eq_true_rect»), + gref (const «eq_true_ind»), gref (const «eq_true_rec»), + gref (const «eq_true_sind»), gref (const «is_true»), + gref (const «eq_true_ind_r»), gref (const «eq_true_rec_r»), + gref (const «eq_true_rect_r»), gref (indt «BoolSpec»), + gref (const «BoolSpec_ind»), gref (const «BoolSpec_sind»), + gref (indt «nat»), gref (const «nat_rect»), gref (const «nat_ind»), + gref (const «nat_rec»), gref (const «nat_sind»), + gref (indt «option»), gref (const «option_rect»), + gref (const «option_ind»), gref (const «option_rec»), + gref (const «option_sind»), gref (const «option_map»), + gref (indt «sum»), gref (const «sum_rect»), gref (const «sum_ind»), + gref (const «sum_rec»), gref (const «sum_sind»), gref (indt «prod»), + gref (const «prod_rect»), gref (const «prod_ind»), + gref (const «prod_rec»), gref (const «prod_sind»), + gref (const «fst»), gref (const «snd»), + gref (const «surjective_pairing»), + gref (const «injective_projections»), gref (const «pair_equal_spec»), + gref (const «curry»), gref (const «uncurry»), + gref (const «rew_pair»), gref (indt «list»), + gref (const «list_rect»), gref (const «list_ind»), + gref (const «list_rec»), gref (const «list_sind»), + gref (const «length»), gref (const «app»), gref (indt «comparison»), + gref (const «comparison_rect»), gref (const «comparison_ind»), + gref (const «comparison_rec»), gref (const «comparison_sind»), + gref (const «comparison_eq_stable»), gref (const «CompOpp»), + gref (const «CompOpp_involutive»), gref (const «CompOpp_inj»), + gref (const «CompOpp_iff»), gref (indt «CompareSpec»), + gref (const «CompareSpec_ind»), gref (const «CompareSpec_sind»), + gref (indt «CompareSpecT»), gref (const «CompareSpecT_rect»), + gref (const «CompareSpecT_ind»), gref (const «CompareSpecT_rec»), + gref (const «CompareSpecT_sind»), gref (const «CompareSpec2Type»), + gref (const «CompSpec»), gref (const «CompSpecT»), + gref (const «CompSpec2Type»), gref (const «ID»), gref (const «id»), + gref (const «IDProp»), gref (const «idProp»)] + MP = «Coq.Init.Datatypes» + test.test.X.i + File "./test.v", line 19, characters 0-1079: + Error: The elpi tactic/command modules failed without giving a specific error + message. Please report this inconvenience to the authors of the program. + + [1] diff --git a/tests/test_API_module.v b/tests/API_module.t/test.v similarity index 100% rename from tests/test_API_module.v rename to tests/API_module.t/test.v diff --git a/tests/API_new_pred.t/run.t b/tests/API_new_pred.t/run.t new file mode 100644 index 000000000..52fe05fc7 --- /dev/null +++ b/tests/API_new_pred.t/run.t @@ -0,0 +1,5 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query q X0 + Query r X0 + Result r 1 diff --git a/tests/test_API_new_pred.v b/tests/API_new_pred.t/test.v similarity index 100% rename from tests/test_API_new_pred.v rename to tests/API_new_pred.t/test.v diff --git a/tests/API_notations.t/run.t b/tests/API_notations.t/run.t new file mode 100644 index 000000000..7a7adae3b --- /dev/null +++ b/tests/API_notations.t/run.t @@ -0,0 +1,77 @@ + $ . ../setup-project.sh + $ dune build test.vo + «test.test.abbr» + Query assignments: + A = «test.test.abbr» + _uvk_1_ = X0 + _uvk_2_ = c0 \ + X1 c0 + _uvk_3_ = c0 \ c1 \ + X2 c0 c1 + Syntactic constraints: + {c0 c1} : decl c1 `y` (X1 c0), decl c0 `x` X0 + ?- evar (X2 c0 c1) (X3 c0 c1) (X2 c0 c1) /* suspended on X2 */ + {c0 c1} : decl c1 `y` (X1 c0), decl c0 `x` X0 + ?- evar (X4 c0 c1) (sort (typ «test.test.3»)) (X3 c0 c1) /* suspended on X4, X3 */ + {c0} : decl c0 `x` X0 ?- evar (X1 c0) (sort (typ «test.test.2»)) (X1 c0) /* suspended on X1 */ + evar (X0) (sort (typ «test.test.1»)) (X0) /* suspended on X0 */ + Universe constraints: + UNIVERSES: + {test.test.3 test.test.2 test.test.1} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α1 + α2 + α3 + WEAK CONSTRAINTS: + + + Notation abbr _elpi_ctx_entry_2_was_x_ _elpi_ctx_entry_1_ := + (_elpi_ctx_entry_2_was_x_ = _elpi_ctx_entry_2_was_x_) + Expands to: Notation test.test.abbr + 4 = 4 + : Prop + Query assignments: + _uvk_16_ = X0 + _uvk_17_ = c0 \ + X1 c0 + _uvk_18_ = c0 \ c1 \ + X2 c0 c1 + Syntactic constraints: + {c0 c1} : decl c1 `y` (X1 c0), decl c0 `x` X0 + ?- evar (X2 c0 c1) (X3 c0 c1) (X2 c0 c1) /* suspended on X2 */ + {c0 c1} : decl c1 `y` (X1 c0), decl c0 `x` X0 + ?- evar (X4 c0 c1) (sort (typ «test.test.6»)) (X3 c0 c1) /* suspended on X4, X3 */ + {c0} : decl c0 `x` X0 ?- evar (X1 c0) (sort (typ «test.test.5»)) (X1 c0) /* suspended on X1 */ + evar (X0) (sort (typ «test.test.4»)) (X0) /* suspended on X0 */ + Universe constraints: + UNIVERSES: + {test.test.6 test.test.5 test.test.4} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α4 + α5 + α6 + WEAK CONSTRAINTS: + + + Notation abbr2 _elpi_ctx_entry_1_was_x_ := + (fun H => _elpi_ctx_entry_1_was_x_ = _elpi_ctx_entry_1_was_x_) + Expands to: Notation test.test.abbr2 + (fun _ : nat => 2 = 2) 3 + : Prop + fun `H` X0 c0 \ + app [global (indt «eq»), X1 c0, fun `x` X2 c1 \ c1, fun `x` X2 c1 \ c1] + Query assignments: + Spilled_1 = «test.test.abbr2» + T = fun `H` X0 c0 \ + app [global (indt «eq»), X1 c0, fun `x` X2 c1 \ c1, fun `x` X2 c1 \ c1] + _uvk_31_ = X2 + Query assignments: + Spilled_1 = «test.test.abbr2» diff --git a/tests/test_API_notations.v b/tests/API_notations.t/test.v similarity index 100% rename from tests/test_API_notations.v rename to tests/API_notations.t/test.v diff --git a/tests/API_section.t/run.t b/tests/API_section.t/run.t new file mode 100644 index 000000000..d1713ad43 --- /dev/null +++ b/tests/API_section.t/run.t @@ -0,0 +1,25 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query assignments: + CA = «a» + CB = «b» + CC = «c» + d : nat + + d is not universe polymorphic + Expands to: Variable d + eq_refl : e2 = 3 + : e2 = 3 + Query assignments: + X = «x» + fx : nat -> nat + : nat -> nat + opaque_3 : nat + + opaque_3 is not universe polymorphic + opaque_3 is opaque + Expands to: Constant test.test.opaque_3 + foo : nat + : nat + bar : bool -> nat + : bool -> nat diff --git a/tests/test_API_section.v b/tests/API_section.t/test.v similarity index 100% rename from tests/test_API_section.v rename to tests/API_section.t/test.v diff --git a/tests/API_typecheck.t/run.t b/tests/API_typecheck.t/run.t new file mode 100644 index 000000000..6eb63121d --- /dev/null +++ b/tests/API_typecheck.t/run.t @@ -0,0 +1,129 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query assignments: + BO = fix `add` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]] + GR = «Nat.add» + TY = prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat») + c2 + global (indt «nat») + z + nat + Query assignments: + Spilled_1 = c0 \ c1 \ c2 \ + nat + Spilled_2 = c0 \ c1 \ c2 \ + z + T = global (indt «nat») + c2 + global (indt «nat») + z + nat + Query assignments: + Spilled_1 = c0 \ c1 \ c2 \ + nat + Spilled_2 = c0 \ c1 \ c2 \ + z + T = global (indt «nat») + Illegal application (Non-functional construction): + The expression "Prop" of type "Type" + cannot be applied to the term + "Prop" : "Type" + Query assignments: + E = Illegal application (Non-functional construction): + The expression "Prop" of type "Type" + cannot be applied to the term + "Prop" : "Type" + Unable to unify "bool" with "nat". + Query assignments: + Msg = Unable to unify "bool" with "nat". + Query assignments: + Cons = global (indc «cons») + GRCons = indc «cons» + GRList = indt «list» + GRNat = indt «nat» + GRNil = indc «nil» + GRZero = indc «O» + L = app + [global (indc «cons»), global (indt «nat»), global (indc «O»), + app [global (indc «nil»), global (indt «nat»)]] + LE = app + [global (indc «cons»), global (indt «nat»), global (indc «O»), + app [global (indc «nil»), global (indt «nat»)]] + List = global (indt «list») + Nat = global (indt «nat») + Nil = global (indc «nil») + Zero = global (indc «O») + Universe constraints: + UNIVERSES: + {test.test.4 test.test.3 test.test.2 test.test.1} |= + test.test.3 < test.test.2 + test.test.4 < test.test.1 + Set <= test.test.3 + Set <= test.test.4 + test.test.3 <= list.u0 + test.test.4 <= list.u0 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α1 := Type + α2 := Type + WEAK CONSTRAINTS: + + + global (indt «nat») + Query assignments: + T = global (indt «nat») + _uvk_5_ = global (indt «nat») + _uvk_6_ = global (indt «nat») + Universe constraints: + UNIVERSES: + {test.test.9 test.test.8 test.test.7 test.test.6 test.test.5} |= + Set < test.test.7 + test.test.8 < test.test.6 + test.test.9 < test.test.5 + Set <= test.test.8 + Set <= test.test.9 + test.test.8 <= list.u0 + test.test.9 <= list.u0 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α3 := Type + α4 := Type + α5 := Type + WEAK CONSTRAINTS: + + + «test.test.10» + Query assignments: + U = «test.test.10» + Universe constraints: + UNIVERSES: + {test.test.10} |= Set <= test.test.10 + ALGEBRAIC UNIVERSES: + {test.test.10} + FLEXIBLE UNIVERSES: + test.test.10 + SORTS: + + WEAK CONSTRAINTS: + + + Unable to unify "Set" with "Prop" (universe inconsistency: Cannot enforce Set + <= Prop). + Query assignments: + E = Unable to unify "Set" with "Prop" (universe inconsistency: Cannot enforce Set + <= Prop). diff --git a/tests/test_API_typecheck.v b/tests/API_typecheck.t/test.v similarity index 100% rename from tests/test_API_typecheck.v rename to tests/API_typecheck.t/test.v diff --git a/tests/COQ_ELPI_ATTRIBUTES.t/run.t b/tests/COQ_ELPI_ATTRIBUTES.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/COQ_ELPI_ATTRIBUTES.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_COQ_ELPI_ATTRIBUTES.v b/tests/COQ_ELPI_ATTRIBUTES.t/test.v similarity index 100% rename from tests/test_COQ_ELPI_ATTRIBUTES.v rename to tests/COQ_ELPI_ATTRIBUTES.t/test.v diff --git a/tests/HOAS.t/run.t b/tests/HOAS.t/run.t new file mode 100644 index 000000000..2ea56f541 --- /dev/null +++ b/tests/HOAS.t/run.t @@ -0,0 +1,1027 @@ + $ . ../setup-project.sh + $ dune build test.vo + {c0} : decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0) + (prod `_` (global (indt «bool»)) c1 \ global (indt «True»)) + (X1 c0) /* suspended on X0, X1 */ + EVARS: + ?X2==[x |- bool -> True] (goal evar) {?Goal} + ?X1==[ |- => fun x : nat => ?Goal] (goal evar) + + SHELF:|| + FUTURE GOALS STACK: + || + + Coq-Elpi mapping: + RAW: + ?X2 <-> c0 \ X0 c0 + ELAB: + ?X2 <-> X1 + + {c0} : decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0) + (prod `_` (global (indt «bool»)) c1 \ global (indt «True»)) + (X1 c0) /* suspended on X0, X1 */ + H + [nabla c1 \ + seal + (goal + [decl c1 `H` + (prod `b` + (prod `b` (global (indt «bool»)) c2 \ + app [global (indt «eq»), global (indt «bool»), c2, c2]) c2 \ + global (indt «True»))] (X0 c1) + (prod `b` (global (indt «bool»)) c2 \ + app [global (indt «eq»), global (indt «bool»), c2, c2]) (X1 c1) [])] + [str fun, str in, str as, int 4, str end, str match, str return, str =>, + str :, str :=, str {, str }, str ;, str ,, str |, str x, int 1, str H, + trm + (fun `x` (global (indt «False»)) c0 \ + match c0 (fun `y` (global (indt «False»)) c1 \ global (indt «nat»)) + [])] + Query assignments: + T = sort (typ «test.test.3») + U = «test.test.3» + Query assignments: + U = «test.test.4» + Universe constraints: + UNIVERSES: + {test.test.4} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + U = «foo» + Query assignments: + X = c0 \ c1 \ c2 \ + X0 c0 c1 c2 + _uvk_19_ = global (indt «nat») + Syntactic constraints: + {c0 c1 c2 c3 c4 c5 c6} : + decl c6 `z` (app [global (const «N»), c5]), + decl c5 `x` (global (indt «nat»)), + decl c4 `a` (global (indt «bool»)) + ?- evar (X0 c4 c5 c6) (X1 c4 c5 c6) (X0 c4 c5 c6) /* suspended on X0 */ + {c0 c1 c2 c3 c4 c5 c6} : + decl c6 `z` (app [global (const «N»), c5]), + decl c5 `x` (global (indt «nat»)), + decl c4 `a` (global (indt «bool»)) + ?- evar (X2 c4 c5 c6) (sort (typ «test.test.9»)) (X1 c4 c5 c6) /* suspended on X2, X1 */ + Universe constraints: + UNIVERSES: + {test.test.9 test.test.8} |= Set <= test.test.8 + test.test.8 <= test.test.8 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α3 := Type + α4 + WEAK CONSTRAINTS: + + + ---------------------------------- + {c0 c1} : decl c1 `a` (global (indt «bool»)) + ?- evar X0 (sort (typ «test.test.10»)) X1 /* suspended on X0, X1 */ + {c0 c1} : decl c1 `a` (global (indt «bool»)) ?- evar (X2 c1) X1 (X2 c1) /* suspended on X2 */ + EVARS: + ?X10==[ |- Type] (internal placeholder) {?elpi_evar} + ?X9==[a |- ?elpi_evar] (internal placeholder) {?e0} + ?X8==[a |- => ?elpi_evar] (internal placeholder) + + SHELF: + FUTURE GOALS STACK:?X10 + ?X9 + + Coq-Elpi mapping: + RAW: + ?X9 <-> c0 \ X2 c0 + ?X10 <-> X0 + ELAB: + ?X9 <-> X2 + ?X10 <-> X1 + + X2 c0 : X1 + Query assignments: + TY = X1 + X = c0 \ c1 \ + X2 c0 + Syntactic constraints: + {c0 c1} : decl c1 `a` (global (indt «bool»)) + ?- evar X0 (sort (typ «test.test.10»)) X1 /* suspended on X0, X1 */ + {c0 c1} : decl c1 `a` (global (indt «bool»)) ?- evar (X2 c1) X1 (X2 c1) /* suspended on X2 */ + Universe constraints: + UNIVERSES: + {test.test.10} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α5 + WEAK CONSTRAINTS: + + + Raw term: + app + [global (const «add»), primitive (uint63 2000000003333002), + primitive (uint63 1)] + Nice term: add 2000000003333002 1 + Red: + 2000000003333003 + Raw term: + app + [global (const «add»), primitive (float64 24000000000000), + primitive (float64 1)] + Nice term: 24000000000000 + 1 + Red: 24000000000001 + Query assignments: + C = «Nat.add» + F = TODO + T = app + [fix `add` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]], + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T1 = app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T2 = app + [fix `plus` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]], + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + _uvk_35_ = global (indt «nat») + _uvk_36_ = c0 \ + global (indt «nat») + _uvk_37_ = c0 \ c1 \ + global (indt «nat») + _uvk_38_ = c0 \ + global (indt «nat») + _uvk_39_ = c0 \ c1 \ + global (indt «nat») + _uvk_40_ = c0 \ c1 \ c2 \ + global (indt «nat») + _uvk_41_ = c0 \ c1 \ c2 \ + global (indt «nat») + Query assignments: + C = «Nat.add» + F = TODO + T = app + [fun `n` (global (indt «nat»)) c0 \ + fun `m` (global (indt «nat»)) c1 \ + match c0 (fun `n` (global (indt «nat»)) c2 \ global (indt «nat»)) + [c1, + fun `p` (global (indt «nat»)) c2 \ + app + [global (indc «S»), + app + [fix `add` 0 + (prod `n` (global (indt «nat»)) c3 \ + prod `m` (global (indt «nat»)) c4 \ global (indt «nat»)) + c3 \ + fun `n` (global (indt «nat»)) c4 \ + fun `m` (global (indt «nat»)) c5 \ + match c4 + (fun `n` (global (indt «nat»)) c6 \ global (indt «nat»)) + [c5, + fun `p` (global (indt «nat»)) c6 \ + app [global (indc «S»), app [c3, c6, c5]]], c2, c1]]], + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T1 = app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T2 = app + [fun `n` (global (indt «nat»)) c0 \ + fun `m` (global (indt «nat»)) c1 \ + match c0 (fun `n` (global (indt «nat»)) c2 \ global (indt «nat»)) + [c1, + fun `p` (global (indt «nat»)) c2 \ + app + [global (indc «S»), + app + [fix `plus` 0 + (prod `n` (global (indt «nat»)) c3 \ + prod `m` (global (indt «nat»)) c4 \ global (indt «nat»)) + c3 \ + fun `n` (global (indt «nat»)) c4 \ + fun `m` (global (indt «nat»)) c5 \ + match c4 + (fun `n` (global (indt «nat»)) c6 \ global (indt «nat»)) + [c5, + fun `p` (global (indt «nat»)) c6 \ + app [global (indc «S»), app [c3, c6, c5]]], c2, c1]]], + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + _uvk_42_ = global (indt «nat») + _uvk_43_ = c0 \ + global (indt «nat») + _uvk_44_ = c0 \ c1 \ + global (indt «nat») + _uvk_45_ = c0 \ c1 \ + global (indt «nat») + _uvk_46_ = c0 \ c1 \ c2 \ + global (indt «nat») + _uvk_47_ = c0 \ c1 \ c2 \ + global (indt «nat») + _uvk_48_ = c0 \ c1 \ c2 \ + global (indt «nat») + _uvk_49_ = c0 \ c1 \ c2 \ c3 \ + global (indt «nat») + _uvk_50_ = c0 \ c1 \ c2 \ c3 \ + global (indt «nat») + _uvk_51_ = c0 \ c1 \ c2 \ c3 \ + global (indt «nat») + _uvk_52_ = c0 \ c1 \ c2 \ c3 \ + global (indt «nat») + Query assignments: + C = «Nat.add» + F = TODO + T = match (app [global (indc «S»), global (indc «O»)]) + (fun `n` (global (indt «nat»)) c0 \ global (indt «nat»)) + [app [global (indc «S»), app [global (indc «S»), global (indc «O»)]], + fun `p` (global (indt «nat»)) c0 \ + app + [global (indc «S»), + app + [fix `add` 0 + (prod `n` (global (indt «nat»)) c1 \ + prod `m` (global (indt «nat»)) c2 \ global (indt «nat»)) c1 \ + fun `n` (global (indt «nat»)) c2 \ + fun `m` (global (indt «nat»)) c3 \ + match c2 + (fun `n` (global (indt «nat»)) c4 \ global (indt «nat»)) + [c3, + fun `p` (global (indt «nat»)) c4 \ + app [global (indc «S»), app [c1, c4, c3]]], c0, + app + [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]]] + T1 = app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T2 = match (app [global (indc «S»), global (indc «O»)]) + (fun `_` (global (indt «nat»)) c0 \ global (indt «nat»)) + [app [global (indc «S»), app [global (indc «S»), global (indc «O»)]], + fun `p` (global (indt «nat»)) c0 \ + app + [global (indc «S»), + app + [fix `plus` 0 + (prod `n` (global (indt «nat»)) c1 \ + prod `m` (global (indt «nat»)) c2 \ global (indt «nat»)) c1 \ + fun `n` (global (indt «nat»)) c2 \ + fun `m` (global (indt «nat»)) c3 \ + match c2 + (fun `n` (global (indt «nat»)) c4 \ global (indt «nat»)) + [c3, + fun `p` (global (indt «nat»)) c4 \ + app [global (indc «S»), app [c1, c4, c3]]], c0, + app + [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]]] + _uvk_53_ = c0 \ + global (indt «nat») + _uvk_54_ = global (indt «nat») + _uvk_55_ = c0 \ + global (indt «nat») + _uvk_56_ = c0 \ c1 \ + global (indt «nat») + _uvk_57_ = c0 \ c1 \ c2 \ + global (indt «nat») + _uvk_58_ = c0 \ c1 \ + global (indt «nat») + _uvk_59_ = c0 \ c1 \ c2 \ + global (indt «nat») + _uvk_60_ = c0 \ c1 \ c2 \ c3 \ + global (indt «nat») + _uvk_61_ = c0 \ c1 \ c2 \ c3 \ + global (indt «nat») + Query assignments: + C = «Nat.add» + F = TODO + T = app + [global (indc «S»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T1 = app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + T2 = app + [global (indc «S»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + test.test.P.p1 1 global (const «P.x») + @P.p1 + X0 global (const «P.x») + P.p1 P.x + some + (fun `A` (sort (typ «P.foo.u0»)) c0 \ + fun `f` (app [global (indt «P.foo»), c0]) c1 \ + app [primitive (proj test.test.P.p1 1), c1]) + test.test.P.p2 2 global (const «P.x») + @P.p2 + X0 global (const «P.x») + P.p2 P.x + some + (fun `A` (sort (typ «P.foo.u0»)) c0 \ + fun `f` (app [global (indt «P.foo»), c0]) c1 \ + app [primitive (proj test.test.P.p1 1), c1]) + some (pglobal (const «toto») «test.test.19 test.test.20») + prod `T1` (sort (typ «test.test.19»)) c0 \ + prod `T2` (sort (typ «test.test.20»)) c1 \ prod `x` c0 c2 \ c0 + Query assignments: + Body = some (pglobal (const «toto») «test.test.19 test.test.20») + C = «titi» + Term = prod `T1` (sort (typ «test.test.19»)) c0 \ + prod `T2` (sort (typ «test.test.20»)) c1 \ prod `x` c0 c2 \ c0 + Universe constraints: + UNIVERSES: + {test.test.20 test.test.19} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + pglobal (const «toto») X0 + pglobal (const «toto») «u1 u2» + toto + Query assignments: + Spilled_1 = toto + _uvk_62_ = X0 + _uvk_63_ = «test.test.23 test.test.24» + Universe constraints: + UNIVERSES: + {test.test.24 test.test.23} |= + ALGEBRAIC UNIVERSES: + {test.test.24 test.test.23} + FLEXIBLE UNIVERSES: + test.test.24 + test.test.23 + SORTS: + + WEAK CONSTRAINTS: + + + app + [pglobal (const «t») X0, global (indt «nat»), + pglobal (const «fnat») X1] + app + [pglobal (const «t») «test.test.29», global (indt «nat»), + pglobal (const «fnat») «»] + Query assignments: + T = app + [pglobal (const «t») «test.test.29», global (indt «nat»), + pglobal (const «fnat») «»] + Ty = global (indt «nat») + _uvk_64_ = «test.test.29» + _uvk_65_ = «» + Universe constraints: + UNIVERSES: + {test.test.29} |= Set <= test.test.29 + Set = test.test.29 + ALGEBRAIC UNIVERSES: + {test.test.29} + FLEXIBLE UNIVERSES: + test.test.29 := Set + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + A4 = «test.test.36» + A5 = «test.test.37» + A6 = «test.test.38» + A7 = «test.test.39» + A8 = «test.test.40» + Arity = prod `T` (sort (typ «test.test.30»)) c0 \ sort (typ «test.test.30») + Arity1 = prod `T` (sort (typ «test.test.31»)) c0 \ sort (typ «test.test.31») + Arity2 = prod `T` (sort (typ «test.test.32»)) c0 \ sort (typ «test.test.32») + Arity4 = prod `T` (sort (typ «test.test.36»)) c0 \ sort (typ «test.test.36») + Arity5 = prod `T` (sort (typ «test.test.37»)) c0 \ sort (typ «test.test.37») + B = «Build_F» + B1 = «test.test.43» + B2 = «test.test.44» + BTy2 = prod `T` (sort (typ «test.test.42»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.42», c0] + BTy3 = prod `T` (sort (typ «test.test.43»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.43», c0] + BoN = none + BoT = some + (fun `T` (sort (typ «test.test.45»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.45», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.45», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + BoT1 = some + (fun `T` (sort (typ «test.test.46»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.46», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.46», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + BoT2 = some + (fun `T` (sort (typ «test.test.47»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.47», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.47», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + BoT4 = some + (fun `T` (sort (typ «test.test.49»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.49», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.49», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + BoT5 = some + (fun `T` (sort (typ «test.test.50»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.50», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.50», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + BoT6 = some + (fun `T` (sort (typ «test.test.64»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.64», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.64», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + BoT7 = some + (fun `T` (sort (typ «test.test.66»)) c0 \ + fun `f` (app [pglobal (indt «F») «test.test.66», c0]) c1 \ + match c1 + (fun `f` (app [pglobal (indt «F») «test.test.66», c0]) c2 \ c0) + [fun `t` c0 c2 \ c2]) + C1 = «test.test.54» + C2 = «test.test.55» + C3 = «test.test.58» + C4 = «test.test.59» + C5 = «test.test.62» + C6 = «test.test.63» + D1 = «test.test.49» + D2 = «test.test.50» + D3 = «test.test.51» + D4 = X0 + E5 = «test.test.66» + E6 = «test.test.67» + GRB = indc «Build_F» + GRF = indt «F» + GRn = const «n» + GRt = const «t» + I = «test.test.30» + I2 = «test.test.41» + I3 = «test.test.45» + I4 = «» + Ind = «F» + K = [«Build_F»] + KTys = [prod `T` (sort (typ «test.test.30»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.30», c0]] + KTys1 = [prod `T` (sort (typ «test.test.31»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.31», c0]] + KTys3 = [prod `T` (sort (typ «test.test.33»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.33», c0]] + KTys4 = [prod `T` (sort (typ «test.test.36»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.36», c0]] + KTys6 = [prod `T` (sort (typ «test.test.38»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.38», c0]] + N = «n» + T = «t» + TyB = prod `T` (sort (typ «test.test.41»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.41», c0] + TyB2 = prod `T` (sort (typ «test.test.56»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.56», c0] + TyB3 = prod `T` (sort (typ «test.test.58»)) c0 \ + prod `t` c0 c1 \ app [pglobal (indt «F») «test.test.58», c0] + TyF = prod `T` (sort (typ «test.test.30»)) c0 \ sort (typ «test.test.30») + TyF2 = prod `T` (sort (typ «test.test.52»)) c0 \ sort (typ «test.test.52») + TyF3 = prod `T` (sort (typ «test.test.54»)) c0 \ sort (typ «test.test.54») + TyN = global (indt «nat») + TyT = prod `T` (sort (typ «test.test.45»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.45», c0]) c1 \ c0 + TyT1 = prod `T` (sort (typ «test.test.46»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.46», c0]) c1 \ c0 + TyT3 = prod `T` (sort (typ «test.test.48»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.48», c0]) c1 \ c0 + TyT4 = prod `T` (sort (typ «test.test.49»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.49», c0]) c1 \ c0 + TyT5 = prod `T` (sort (typ «test.test.51»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.51», c0]) c1 \ c0 + TyT6 = prod `T` (sort (typ «test.test.60»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.60», c0]) c1 \ c0 + TyT7 = prod `T` (sort (typ «test.test.62»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.62», c0]) c1 \ c0 + Tyt = prod `T` (sort (typ «test.test.45»)) c0 \ + prod `f` (app [pglobal (indt «F») «test.test.45», c0]) c1 \ c0 + Universe constraints: + UNIVERSES: + {test.test.67 test.test.66 test.test.65 test.test.64 test.test.63 + test.test.62 test.test.61 test.test.60 test.test.59 test.test.58 + test.test.57 test.test.56 test.test.55 test.test.54 test.test.53 + test.test.52 test.test.51 test.test.50 test.test.49 test.test.48 + test.test.47 test.test.46 test.test.45 test.test.44 test.test.43 + test.test.42 test.test.41 test.test.40 test.test.39 test.test.38 + test.test.37 test.test.36 test.test.35 test.test.34 test.test.33 + test.test.32 test.test.31 test.test.30} |= + ALGEBRAIC UNIVERSES: + {test.test.45 test.test.44 test.test.43 test.test.42 test.test.41 + test.test.40 test.test.39 test.test.38 test.test.37 test.test.36 + test.test.35 test.test.34 test.test.33 test.test.32 test.test.31 + test.test.30} + FLEXIBLE UNIVERSES: + test.test.45 + test.test.44 + test.test.43 + test.test.42 + test.test.41 + test.test.40 + test.test.39 + test.test.38 + test.test.37 + test.test.36 + test.test.35 + test.test.34 + test.test.33 + test.test.32 + test.test.31 + test.test.30 + SORTS: + + WEAK CONSTRAINTS: + + + «test.test.68» + parameter T explicit (sort (typ «test.test.68»)) c0 \ + record F (sort (typ «test.test.68»)) Build_F + (field [coercion off, canonical tt] t c0 c1 \ end-record) + «test.test.68» + parameter T explicit (sort (typ «test.test.68»)) c0 \ + record F (sort (typ «test.test.68»)) Build_F + (field [coercion off, canonical tt] t c0 c1 \ end-record) + parameter T explicit (sort (typ «test.test.69»)) c0 \ + record F (sort (typ «test.test.69»)) Build_F + (field [coercion off, canonical tt] t c0 c1 \ end-record) + Query assignments: + Decl = parameter T explicit (sort (typ «test.test.68»)) c0 \ + record F (sort (typ «test.test.68»)) Build_F + (field [coercion off, canonical tt] t c0 c1 \ end-record) + Decl1 = parameter T explicit (sort (typ «test.test.68»)) c0 \ + record F (sort (typ «test.test.68»)) Build_F + (field [coercion off, canonical tt] t c0 c1 \ end-record) + Decl2 = parameter T explicit (sort (typ «test.test.69»)) c0 \ + record F (sort (typ «test.test.69»)) Build_F + (field [coercion off, canonical tt] t c0 c1 \ end-record) + GRF = indt «F» + I = «test.test.68» + Ind = «F» + Universe constraints: + UNIVERSES: + {test.test.69 test.test.68} |= + ALGEBRAIC UNIVERSES: + {test.test.69 test.test.68} + FLEXIBLE UNIVERSES: + test.test.69 + test.test.68 + SORTS: + + WEAK CONSTRAINTS: + + + «test.test.70» «test.test.71» + Universe constraints: UNIVERSES: + {test.test.71 test.test.70} |= + ALGEBRAIC UNIVERSES: + {test.test.71 test.test.70} + FLEXIBLE UNIVERSES: + test.test.71 + test.test.70 + SORTS: + + WEAK CONSTRAINTS: + + + Universe constraints: UNIVERSES: + {test.test.71 test.test.70} |= + test.test.70 = test.test.71 + ALGEBRAIC UNIVERSES: + {test.test.71 test.test.70} + FLEXIBLE UNIVERSES: + test.test.71 + test.test.70 := test.test.71 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + GRF = indt «F» + I1 = «test.test.70» + I2 = «test.test.71» + Universe constraints: + UNIVERSES: + {test.test.71 test.test.70} |= test.test.70 = test.test.71 + ALGEBRAIC UNIVERSES: + {test.test.71 test.test.70} + FLEXIBLE UNIVERSES: + test.test.71 + test.test.70 := test.test.71 + SORTS: + + WEAK CONSTRAINTS: + + + «test.test.72» «» + Universe constraints: UNIVERSES: + {test.test.72} |= + ALGEBRAIC UNIVERSES: + {test.test.72} + FLEXIBLE UNIVERSES: + test.test.72 + SORTS: + + WEAK CONSTRAINTS: + + + different universe instance lengths + Universe constraints: UNIVERSES: + {test.test.72} |= + ALGEBRAIC UNIVERSES: + {test.test.72} + FLEXIBLE UNIVERSES: + test.test.72 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + E = different universe instance lengths + GRF = indt «F» + GRfnat = const «fnat» + I1 = «test.test.72» + I2 = «» + Universe constraints: + UNIVERSES: + {test.test.72} |= + ALGEBRAIC UNIVERSES: + {test.test.72} + FLEXIBLE UNIVERSES: + test.test.72 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + GRF = indt «F» + I1 = «test.test.73» + I2 = «test.test.73» + U = «test.test.73» + UL1 = [«test.test.73»] + Universe constraints: + UNIVERSES: + {test.test.73} |= + ALGEBRAIC UNIVERSES: + {test.test.73} + FLEXIBLE UNIVERSES: + test.test.73 + SORTS: + + WEAK CONSTRAINTS: + + + Cannot enforce test.test.74 = test.test.75 because test.test.74 + < test.test.75 + Query assignments: + E = Cannot enforce test.test.74 = test.test.75 because test.test.74 + < test.test.75 + GRF = indt «F» + I1 = «test.test.74» + I2 = «test.test.75» + L1 = «test.test.74» + L2 = «test.test.75» + U1 = «test.test.74» + U2 = «test.test.75» + Universe constraints: + UNIVERSES: + {test.test.75 test.test.74} |= test.test.74 < test.test.75 + ALGEBRAIC UNIVERSES: + {test.test.75 test.test.74} + FLEXIBLE UNIVERSES: + test.test.75 + test.test.74 + SORTS: + + WEAK CONSTRAINTS: + + + Universe constraints: UNIVERSES: + {test.test.79 test.test.78} |= + test.test.78 < test.test.79 + ALGEBRAIC UNIVERSES: + {test.test.79 test.test.78} + FLEXIBLE UNIVERSES: + test.test.79 + test.test.78 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + GRF = indt «F2» + I1 = «test.test.78» + I2 = «test.test.79» + L1 = «test.test.78» + L2 = «test.test.79» + U1 = «test.test.78» + U2 = «test.test.79» + Universe constraints: + UNIVERSES: + {test.test.79 test.test.78} |= + test.test.78 < test.test.79 + test.test.78 <= test.test.79 + ALGEBRAIC UNIVERSES: + {test.test.79 test.test.78} + FLEXIBLE UNIVERSES: + test.test.79 + test.test.78 + SORTS: + + WEAK CONSTRAINTS: + + + Universe constraints: UNIVERSES: + {test.test.81 test.test.80} |= + test.test.80 < test.test.81 + ALGEBRAIC UNIVERSES: + {test.test.81} + FLEXIBLE UNIVERSES: + test.test.81 + test.test.80 + SORTS: + + WEAK CONSTRAINTS: + + + Cannot enforce test.test.81 = test.test.80 because test.test.80 + < test.test.81 + Query assignments: + E = Cannot enforce test.test.81 = test.test.80 because test.test.80 + < test.test.81 + GRF = indt «F» + I1 = «test.test.80» + I2 = «test.test.81» + L1 = «test.test.80» + L2 = «test.test.81» + U1 = «test.test.80» + U2 = «test.test.81» + Universe constraints: + UNIVERSES: + {test.test.81 test.test.80} |= test.test.80 < test.test.81 + ALGEBRAIC UNIVERSES: + {test.test.81} + FLEXIBLE UNIVERSES: + test.test.81 + test.test.80 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + GR = indt «nat» + Query assignments: + GR = indt «F» + I = «test.test.82» + Universe constraints: + UNIVERSES: + {test.test.82} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + test.test.82 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + GR = indt «F» + pglobal (indt «F») «test.test.84» + «test.test.84» + pglobal (indc «Build_F») «test.test.84» + Query assignments: + GR = indt «F» + GR1 = indc «Build_F» + I = «test.test.84» + Spilled_1 = pglobal (indc «Build_F») «test.test.84» + Spilled_2 = pglobal (indt «F») «test.test.84» + Universe constraints: + UNIVERSES: + {test.test.84} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + test.test.84 + SORTS: + + WEAK CONSTRAINTS: + + + «test.test.85 test.test.85» + Query assignments: + I = «test.test.85 test.test.85» + U = «test.test.85» + Universe constraints: + UNIVERSES: + {test.test.85} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + Universe constraints: + ------------------ + Universe constraints: UNIVERSES: + {test.test.87 test.test.86} |= + test.test.86 < test.test.87 + ALGEBRAIC UNIVERSES: + {test.test.87 test.test.86} + FLEXIBLE UNIVERSES: + test.test.87 + test.test.86 + SORTS: + + WEAK CONSTRAINTS: + + + Universe constraints: UNIVERSES: + {test.test.87 test.test.86} |= + test.test.86 < test.test.87 + ALGEBRAIC UNIVERSES: + {test.test.87 test.test.86} + FLEXIBLE UNIVERSES: + test.test.87 + test.test.86 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + Body = sort (typ «test.test.86») + LX = «test.test.86» + LY = «test.test.87» + Type = sort (typ «test.test.87») + UX = «test.test.86» + UY = «test.test.87» + Universe constraints: + UNIVERSES: + {test.test.87 test.test.86} |= test.test.86 < test.test.87 + ALGEBRAIC UNIVERSES: + {test.test.87 test.test.86} + FLEXIBLE UNIVERSES: + test.test.87 + test.test.86 + SORTS: + + WEAK CONSTRAINTS: + + + poly@{u u0} : Type@{u0} + (* u u0 |= u < u0 *) + + poly is universe polymorphic + poly is transparent + Expands to: Constant test.test.poly + poly@{Set + test.test.88} + : Type@{test.test.88} + (* {test.test.88} |= Set < test.test.88 *) + Box not a defined object. + sort (typ «Set») + Query assignments: + U = «test.test.89» + Universe constraints: + UNIVERSES: + {test.test.89} |= Set = test.test.89 + ALGEBRAIC UNIVERSES: + {test.test.89} + FLEXIBLE UNIVERSES: + test.test.89 := Set + SORTS: + + WEAK CONSTRAINTS: + + + Inductive tree@{u} (A : Type@{u}) : Type@{max(Set,u)} := + leaf : A -> tree@{u} A | node : A -> list (tree@{u} A) -> tree@{u} A. + (* u |= Set <= list.u0 + u <= list.u0 *) + + Arguments tree A%type_scope + Arguments leaf A%type_scope _ + Arguments node A%type_scope _ _%list_scope + parameter A explicit (sort (typ «test.test.98»)) c0 \ + inductive tree tt (arity (sort (typ «test.test.99»))) c1 \ + [constructor leaf (arity (prod `_` c0 c2 \ c1)), + constructor node + (arity + (prod `_` c0 c2 \ prod `_` (app [global (indt «list»), c1]) c3 \ c1))] + Universe constraints: UNIVERSES: + {test.test.103 test.test.102 test.test.101 + test.test.100 test.test.99 test.test.98} |= + test.test.98 < test.test.100 + test.test.99 < test.test.101 + Set <= list.u0 + Set <= test.test.99 + Set <= test.test.103 + test.test.98 <= list.u0 + test.test.98 <= test.test.99 + test.test.98 <= test.test.102 + test.test.98 <= test.test.103 + test.test.99 <= list.u0 + test.test.99 <= test.test.102 + test.test.99 <= test.test.103 + test.test.102 <= test.test.99 + test.test.103 <= test.test.99 + ALGEBRAIC UNIVERSES: + {test.test.98} + FLEXIBLE UNIVERSES: + test.test.98 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + D = parameter A explicit (sort (typ «M.tree.u0»)) c0 \ + inductive tree tt (arity (sort (typ «M.tree.u1»))) c1 \ + [constructor leaf (arity (prod `_` c0 c2 \ c1)), + constructor node + (arity + (prod `_` c0 c2 \ prod `_` (app [global (indt «list»), c1]) c3 \ c1))] + I = «tree» + _uvk_66_ = X0 + Universe constraints: + UNIVERSES: + {test.test.103 test.test.102 test.test.101 test.test.100} |= + M.tree.u0 < test.test.100 + M.tree.u1 < test.test.101 + Set <= list.u0 + Set <= M.tree.u1 + Set <= test.test.103 + M.tree.u0 <= test.test.102 + M.tree.u0 <= test.test.103 + M.tree.u1 <= test.test.102 + M.tree.u1 <= test.test.103 + test.test.102 <= M.tree.u1 + test.test.103 <= M.tree.u1 + ALGEBRAIC UNIVERSES: + {M.tree.u0} + FLEXIBLE UNIVERSES: + M.tree.u0 + SORTS: + + WEAK CONSTRAINTS: + + + parameter A maximal (sort (typ «test.test.105»)) c0 \ + parameter x explicit (prod `_` c0 c1 \ c0) c1 \ + record c (sort prop) Build_c end-record + File "./test.v", line 127, characters 0-34: + Warning: Use of “Require” inside a module is fragile. It is not recommended + to use this functionality in finished proof scripts. + [require-in-module,fragile,default] + File "./test.v", line 131, characters 0-34: + Warning: Use of “Require” inside a module is fragile. It is not recommended + to use this functionality in finished proof scripts. + [require-in-module,fragile,default] diff --git a/tests/test_HOAS.v b/tests/HOAS.t/test.v similarity index 100% rename from tests/test_HOAS.v rename to tests/HOAS.t/test.v diff --git a/tests/arg_HOAS.t/run.t b/tests/arg_HOAS.t/run.t new file mode 100644 index 000000000..90a39b8ee --- /dev/null +++ b/tests/arg_HOAS.t/run.t @@ -0,0 +1,2587 @@ + $ . ../setup-project.sh + $ dune build test.vo + ----<<---- enter: + coq.say raw: + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + raw: + parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))] + ---->>---- exit: + coq.say raw: + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) + c6 \ app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app + [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))])) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) + c6 \ app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app + [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + typed: + parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))] + ---->>---- exit: + coq.say typed: + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + ----<<---- enter: + coq.env.add-indt + (parameter A1 maximal (sort (typ «test.test.2»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.3»)) c2 \ + parameter B2 explicit (sort (typ «test.test.4»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.7»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.3»)) c3 \ + parameter B2 explicit (sort (typ «test.test.4»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + X0 + ---->>---- exit: + coq.env.add-indt + (parameter A1 maximal (sort (typ «foo1.u0»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «foo1.u1»)) c2 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ «foo1.u3»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «foo1.u1»)) c3 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «foo1.u1»)) c3 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + «foo1» + foo1 ?A2 ?B1 ?B2 ?n : Type + : Type + where + ?A1 : [ |- Type] + ?A2 : [ |- ?A1] + ?B1 : [ |- Type] + ?B2 : [ |- Type] + ?n : [ |- nat] + a_k1 ?A2 ?B1 ?B2 3 ?f : foo1 ?A2 ?B1 ?B2 3 + : foo1 ?A2 ?B1 ?B2 3 + where + ?A1 : [ |- Type] + ?A2 : [ |- ?A1] + ?B1 : [ |- Type] + ?B2 : [ |- Type] + ?f : [ |- foo1 ?A2 (?B1 * ?B1) ?B2 3] + ----<<---- enter: + coq.say raw: + (parameter A1 maximal X0 c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ X1)) c2 \ + parameter B2 explicit (sort (typ X2)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ X3))) c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ X4)) c3 \ + parameter B2 explicit (sort (typ X5)) c4 \ + arity + (prod `x` (X6 c0 c1 c2 c3 c4) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ X7)) c3 \ + parameter B2 explicit (sort (typ X8)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + raw: + parameter A1 maximal X0 c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ X1)) c2 \ + parameter B2 explicit (sort (typ X2)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ X3))) c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ X4)) c3 \ + parameter B2 explicit (sort (typ X5)) c4 \ + arity + (prod `x` (X6 c0 c1 c2 c3 c4) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ X7)) c3 \ + parameter B2 explicit (sort (typ X8)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))] + ---->>---- exit: + coq.say raw: + (parameter A1 maximal X0 c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ X1)) c2 \ + parameter B2 explicit (sort (typ X2)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ X3))) c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ X4)) c3 \ + parameter B2 explicit (sort (typ X5)) c4 \ + arity + (prod `x` (X6 c0 c1 c2 c3 c4) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ X7)) c3 \ + parameter B2 explicit (sort (typ X8)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + ----<<---- enter: + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (parameter A1 maximal X0 c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ X1)) c2 \ + parameter B2 explicit (sort (typ X2)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ X3))) c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ X4)) c3 \ + parameter B2 explicit (sort (typ X5)) c4 \ + arity + (prod `x` (X6 c0 c1 c2 c3 c4) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) + c6 \ app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ X7)) c3 \ + parameter B2 explicit (sort (typ X8)) c4 \ + arity + (prod `_` c0 c5 \ + app + [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + X9) Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (parameter A1 maximal X0 c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.41»)) c2 \ + parameter B2 explicit (sort (typ «test.test.44»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.47»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.52»)) c3 \ + parameter B2 explicit (sort (typ «test.test.54»)) c4 \ + arity + (prod `x` (X6 c0 c1 c2 c3 c4) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) + c6 \ app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.61»)) c3 \ + parameter B2 explicit (sort (typ «test.test.63»)) c4 \ + arity + (prod `_` c0 c5 \ + app + [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + (parameter A1 maximal (sort (typ «test.test.40»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.42»)) c2 \ + parameter B2 explicit (sort (typ «test.test.45»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.48»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.53»)) c3 \ + parameter B2 explicit (sort (typ «test.test.55»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) + c6 \ app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.62»)) c3 \ + parameter B2 explicit (sort (typ «test.test.64»)) c4 \ + arity + (prod `_` c0 c5 \ + app + [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (parameter A1 maximal (sort (typ «test.test.40»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.42»)) c2 \ + parameter B2 explicit (sort (typ «test.test.45»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.48»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.53»)) c3 \ + parameter B2 explicit (sort (typ «test.test.55»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.62»)) c3 \ + parameter B2 explicit (sort (typ «test.test.64»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + typed: + parameter A1 maximal (sort (typ «test.test.40»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.42»)) c2 \ + parameter B2 explicit (sort (typ «test.test.45»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.48»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.53»)) c3 \ + parameter B2 explicit (sort (typ «test.test.55»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.62»)) c3 \ + parameter B2 explicit (sort (typ «test.test.64»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))] + ---->>---- exit: + coq.say typed: + (parameter A1 maximal (sort (typ «test.test.40»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.42»)) c2 \ + parameter B2 explicit (sort (typ «test.test.45»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.48»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.53»)) c3 \ + parameter B2 explicit (sort (typ «test.test.55»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.62»)) c3 \ + parameter B2 explicit (sort (typ «test.test.64»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + ----<<---- enter: + coq.env.add-indt + (parameter A1 maximal (sort (typ «test.test.40»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «test.test.42»)) c2 \ + parameter B2 explicit (sort (typ «test.test.45»)) c3 \ + arity + (prod `_` (global (indt «nat»)) c4 \ sort (typ «test.test.48»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.53»)) c3 \ + parameter B2 explicit (sort (typ «test.test.55»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.62»)) c3 \ + parameter B2 explicit (sort (typ «test.test.64»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + X10 + ---->>---- exit: + coq.env.add-indt + (parameter A1 maximal (sort (typ «foo1.u0»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «foo1.u1»)) c2 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ «foo1.u3»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «test.test.53»)) c3 \ + parameter B2 explicit (sort (typ «test.test.55»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «test.test.62»)) c3 \ + parameter B2 explicit (sort (typ «test.test.64»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))]) + «foo1» + foo1 ?A2 ?B1 ?B2 ?n : Type + : Type + where + ?A1 : [ |- Type] + ?A2 : [ |- ?A1] + ?B1 : [ |- Type] + ?B2 : [ |- Type] + ?n : [ |- nat] + a_k1 ?A2 ?B1 ?B2 3 ?f : foo1 ?A2 ?B1 ?B2 3 + : foo1 ?A2 ?B1 ?B2 3 + where + ?A1 : [ |- Type] + ?A2 : [ |- ?A1] + ?B1 : [ |- Type] + ?B2 : [ |- Type] + ?f : [ |- foo1 ?A2 (?B1 * ?B1) ?B2 3] + Query assignments: + D = parameter A explicit (sort (typ «t.u0»)) c0 \ + inductive t tt + (parameter y explicit (global (indt «nat»)) c1 \ + arity (sort (typ «test.test.82»))) c1 \ + [constructor K + (parameter y explicit (global (indt «nat»)) c2 \ + parameter x explicit c0 c3 \ + parameter n maximal (global (indt «nat»)) c4 \ + arity (prod `_` (app [c1, c4]) c5 \ app [c1, c2]))] + I = «t» + Universe constraints: + UNIVERSES: + {test.test.82} |= Set <= test.test.82 + t.u0 <= test.test.82 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + ----<<---- enter: + coq.say raw: + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + raw: + record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record) + ---->>---- exit: + coq.say raw: + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ + end-record))) Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ + end-record))) Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + typed: + record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record) + ---->>---- exit: + coq.say typed: + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + ----<<---- enter: + coq.env.add-indt + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + X0 + ---->>---- exit: + coq.env.add-indt + (record foo (sort (typ «Set»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + «foo» + ----<<---- enter: + coq.say raw: + (record foo (sort (typ X0)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), X1 c0, app [c0, global (indc «O»)], + global (indc «O»)]) c1 \ end-record)) + raw: + record foo (sort (typ X0)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), X1 c0, app [c0, global (indc «O»)], + global (indc «O»)]) c1 \ end-record) + ---->>---- exit: + coq.say raw: + (record foo (sort (typ X0)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), X1 c0, app [c0, global (indc «O»)], + global (indc «O»)]) c1 \ end-record)) + ----<<---- enter: + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (record foo (sort (typ X0)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), X1 c0, app [c0, global (indc «O»)], + global (indc «O»)]) c1 \ end-record)) X2) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (record foo (sort (typ «test.test.85»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), X1 c0, app [c0, global (indc «O»)], + global (indc «O»)]) c1 \ end-record)) + (record foo (sort (typ «test.test.86»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ + end-record))) Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (record foo (sort (typ «test.test.86»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + typed: + record foo (sort (typ «test.test.86»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record) + ---->>---- exit: + coq.say typed: + (record foo (sort (typ «test.test.86»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + ----<<---- enter: + coq.env.add-indt + (record foo (sort (typ «test.test.86»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + X3 + ---->>---- exit: + coq.env.add-indt + (record foo (sort (typ «foo.u0»)) Build_foo + (field [coercion off, canonical tt] f + (prod `_` (global (indt «nat»)) c0 \ global (indt «nat»)) c0 \ + field [coercion off, canonical tt] _ + (app + [global (indt «eq»), global (indt «nat»), + app [c0, global (indc «O»)], global (indc «O»)]) c1 \ end-record)) + «foo» + ----<<---- enter: + coq.say raw: + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) + raw: + parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record) + ---->>---- exit: + coq.say raw: + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record))) Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record))) Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) + typed: + parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record) + ---->>---- exit: + coq.say typed: + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) + ----<<---- enter: + coq.env.add-indt + (parameter A explicit (sort (typ «test.test.88»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.88»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) X0 + ---->>---- exit: + coq.env.add-indt + (parameter A explicit (sort (typ «foo.u0»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «foo.u0»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) «foo» + Query assignments: + I = «foo» + ----<<---- enter: + coq.say raw: + (parameter A explicit X0 c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ X1)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), X2 c0 c1 c3, c1, c1]) c4 \ c0) + c3 \ + field [coercion off, canonical ff] x + (let `w` (X3 c0 c1 c2 c3) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` (X4 c0 c1 c2 c3 c4) c5 \ + app + [global (indt «eq»), X5 c0 c1 c2 c3 c4 c5, app [c2, c5, c5], + c5]) c4 \ end-record)) + raw: + parameter A explicit X0 c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ X1)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), X2 c0 c1 c3, c1, c1]) c4 \ c0) + c3 \ + field [coercion off, canonical ff] x + (let `w` (X3 c0 c1 c2 c3) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` (X4 c0 c1 c2 c3 c4) c5 \ + app + [global (indt «eq»), X5 c0 c1 c2 c3 c4 c5, app [c2, c5, c5], c5]) + c4 \ end-record) + ---->>---- exit: + coq.say raw: + (parameter A explicit X0 c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ X1)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), X2 c0 c1 c3, c1, c1]) c4 \ c0) + c3 \ + field [coercion off, canonical ff] x + (let `w` (X3 c0 c1 c2 c3) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` (X4 c0 c1 c2 c3 c4) c5 \ + app + [global (indt «eq»), X5 c0 c1 c2 c3 c4 c5, app [c2, c5, c5], + c5]) c4 \ end-record)) + ----<<---- enter: + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (parameter A explicit X0 c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ X1)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), X2 c0 c1 c3, c1, c1]) c4 \ + c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (X3 c0 c1 c2 c3) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` (X4 c0 c1 c2 c3 c4) c5 \ + app + [global (indt «eq»), X5 c0 c1 c2 c3 c4 c5, + app [c2, c5, c5], c5]) c4 \ end-record)) X6) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (parameter A explicit X0 c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.95»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `a` c0 c3 \ + prod `_` (app [global (indt «eq»), X2 c0 c1 c3, c1, c1]) c4 \ + c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (X3 c0 c1 c2 c3) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` (X4 c0 c1 c2 c3 c4) c5 \ + app + [global (indt «eq»), X5 c0 c1 c2 c3 c4 c5, + app [c2, c5, c5], c5]) c4 \ end-record)) + (parameter A explicit (sort (typ «test.test.94»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.96»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `elpi_ctx_entry_4_` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record))) Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (parameter A explicit (sort (typ «test.test.94»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.96»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `elpi_ctx_entry_4_` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) + typed: + parameter A explicit (sort (typ «test.test.94»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.96»)) Build_foo + (field [coercion off, canonical tt] a + (prod `_` c0 c2 \ prod `_` c0 c3 \ c0) c2 \ + field [coercion reversible, canonical tt] z + (prod `elpi_ctx_entry_4_` c0 c3 \ + prod `_` (app [global (indt «eq»), c0, c1, c1]) c4 \ c0) c3 \ + field [coercion off, canonical ff] x + (let `w` (global (indt «nat»)) + (app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record) + ---->>---- exit: + coq.say typed: + (parameter A explicit (sort (typ «test.test.94»)) c0 \ + parameter B explicit c0 c1 \ + record foo (sort (typ «test.test.96»)) Build_foo + ...TRUNCATED BY DUNE... + app [global (indc «S»), global (indc «O»)]]]) c4 \ + prod `x` c0 c5 \ + app [global (indt «eq»), c0, app [c2, c5, c5], c5]) c4 \ + end-record)) «foo» + Query assignments: + I = «foo» + ----<<---- enter: + coq.arity->term + (parameter P explicit (sort (typ «test.test.99»)) c0 \ + parameter w explicit c0 c1 \ + parameter n explicit (global (indt «nat»)) c2 \ + arity (global (indt «nat»))) X0 + ---->>---- exit: + coq.arity->term + (parameter P explicit (sort (typ «test.test.99»)) c0 \ + parameter w explicit c0 c1 \ + parameter n explicit (global (indt «nat»)) c2 \ + arity (global (indt «nat»))) + (prod `P` (sort (typ «test.test.99»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck + (fun `P` (sort (typ «test.test.99»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «test.test.99»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»))) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck + (fun `P` (sort (typ «test.test.99»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «test.test.99»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»))) + illtyped definition + ----<<---- enter: + coq.env.add-const x1 + (fun `P` (sort (typ «test.test.99»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «test.test.99»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»)) X1 X2 + ---->>---- exit: + coq.env.add-const x1 + (fun `P` (sort (typ «x1.u0»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «x1.u0»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»)) X1 «x1» + x1 : forall P : Type, P -> nat -> nat + : forall P : Type, P -> nat -> nat + eq_refl : x1 = (fun (P : Type) (_ : P) (n : nat) => n + 1) + : x1 = (fun (P : Type) (_ : P) (n : nat) => n + 1) + ----<<---- enter: + coq.arity->term + (parameter n explicit (global (indt «nat»)) c0 \ + arity (sort (typ «test.test.102»))) X0 + ---->>---- exit: + coq.arity->term + (parameter n explicit (global (indt «nat»)) c0 \ + arity (sort (typ «test.test.102»))) + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.102»)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-ty + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.102»)) X1) + illtyped axiom + ---->>---- exit: + std.assert-ok! + (coq.typecheck-ty + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.102»)) + (typ «test.test.103»)) illtyped axiom + ----<<---- enter: + coq.env.add-axiom y + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.102»)) X2 + ---->>---- exit: + coq.env.add-axiom y + (prod `n` (global (indt «nat»)) c0 \ sort (typ «y.u0»)) «y» + y : nat -> Type + : nat -> Type + ----<<---- enter: + coq.arity->term + (parameter P explicit (sort (typ X0)) c0 \ + parameter w explicit c0 c1 \ + parameter n explicit (global (indt «nat»)) c2 \ arity (X1 c0 c1 c2)) X2 + ---->>---- exit: + coq.arity->term + (parameter P explicit (sort (typ X0)) c0 \ + parameter w explicit c0 c1 \ + parameter n explicit (global (indt «nat»)) c2 \ arity (X3 c0 c1 c2)) + (prod `P` (sort (typ X0)) c0 \ + prod `w` c0 c1 \ prod `n` (global (indt «nat»)) (X3 c0 c1)) + ----<<---- enter: + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `P` (sort (typ X0)) c0 \ + prod `w` c0 c1 \ prod `n` (global (indt «nat»)) (X3 c0 c1)) X4 X5) + illtyped arity + ---->>---- exit: + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `P` (sort (typ «test.test.105»)) c0 \ + prod `w` c0 c1 \ prod `n` (global (indt «nat»)) (X6 c0 c1)) + (typ «test.test.108») + (prod `P` (sort (typ «test.test.106»)) c0 \ + prod `w` c0 c1 \ prod `n` (global (indt «nat»)) c2 \ X7 c0 c1 c2)) + illtyped arity + ----<<---- enter: + std.assert-ok! + (coq.elaborate-skeleton + (fun `P` (sort (typ X8)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «test.test.106»)) c0 \ + prod `w` c0 c1 \ prod `n` (global (indt «nat»)) c2 \ X7 c0 c1 c2) X9) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.elaborate-skeleton + (fun `P` (sort (typ «test.test.109»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «test.test.106»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»)) + (fun `P` (sort (typ «test.test.110»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]])) + illtyped definition + ----<<---- enter: + coq.env.add-const x1 + (fun `P` (sort (typ «test.test.110»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «test.test.106»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»)) X10 X11 + ---->>---- exit: + coq.env.add-const x1 + (fun `P` (sort (typ «x1.u1»)) c0 \ + fun `w` c0 c1 \ + fun `n` (global (indt «nat»)) c2 \ + app + [global (const «Nat.add»), c2, + app [global (indc «S»), global (indc «O»)]]) + (prod `P` (sort (typ «x1.u0»)) c0 \ + prod `w` c0 c1 \ + prod `n` (global (indt «nat»)) c2 \ global (indt «nat»)) X10 «x1» + x1 : forall P : Type, P -> nat -> nat + : forall P : Type, P -> nat -> nat + eq_refl : x1 = (fun (P : Type) (_ : P) (n : nat) => n + 1) + : x1 = (fun (P : Type) (_ : P) (n : nat) => n + 1) + ----<<---- enter: + coq.arity->term + (parameter n explicit (global (indt «nat»)) c0 \ + arity (sort (typ «test.test.113»))) X0 + ---->>---- exit: + coq.arity->term + (parameter n explicit (global (indt «nat»)) c0 \ + arity (sort (typ «test.test.113»))) + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.113»)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-ty + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.113»)) X1) + illtyped axiom + ---->>---- exit: + std.assert-ok! + (coq.typecheck-ty + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.113»)) + (typ «test.test.114»)) illtyped axiom + ----<<---- enter: + coq.env.add-axiom y + (prod `n` (global (indt «nat»)) c0 \ sort (typ «test.test.113»)) X2 + ---->>---- exit: + coq.env.add-axiom y + (prod `n` (global (indt «nat»)) c0 \ sort (typ «y.u0»)) «y» + y : nat -> Type + : nat -> Type + ----<<---- enter: + coq.arity->term + (parameter n explicit (global (indt «nat»)) c0 \ + arity (global (indt «nat»))) X0 + ---->>---- exit: + coq.arity->term + (parameter n explicit (global (indt «nat»)) c0 \ + arity (global (indt «nat»))) + (prod `n` (global (indt «nat»)) c0 \ global (indt «nat»)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck + (fun `n` (global (indt «nat»)) c0 \ app [global (indc «S»), c0]) + (prod `n` (global (indt «nat»)) c0 \ global (indt «nat»))) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck + (fun `n` (global (indt «nat»)) c0 \ app [global (indc «S»), c0]) + (prod `n` (global (indt «nat»)) c0 \ global (indt «nat»))) + illtyped definition + ----<<---- enter: + coq.env.add-const x + (fun `n` (global (indt «nat»)) c0 \ app [global (indc «S»), c0]) + (prod `n` (global (indt «nat»)) c0 \ global (indt «nat»)) X1 X2 + ---->>---- exit: + coq.env.add-const x + (fun `n` (global (indt «nat»)) c0 \ app [global (indc «S»), c0]) + (prod `n` (global (indt «nat»)) c0 \ global (indt «nat»)) X1 «x» + ----<<---- enter: + coq.say raw: + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record)) + raw: + record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record) + ---->>---- exit: + coq.say raw: + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record)) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record))) Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record))) Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record)) + typed: + record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record) + ---->>---- exit: + coq.say typed: + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record)) + ----<<---- enter: + coq.env.add-indt + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record)) X0 + ---->>---- exit: + coq.env.add-indt + (record foo (sort prop) Build_foo + (field [coercion off, canonical tt] bar (global (indt «True»)) c0 \ + end-record)) «foo» + parameter A1 maximal (sort (typ «foo1.u0»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «foo1.u1»)) c2 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ «foo1.u3»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «foo1.u1»)) c3 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «foo1.u1»)) c3 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))] + Query assignments: + D = parameter A1 maximal (sort (typ «foo1.u0»)) c0 \ + parameter A2 explicit c0 c1 \ + inductive foo1 tt + (parameter B1 explicit (sort (typ «foo1.u1»)) c2 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c3 \ + arity (prod `_` (global (indt «nat»)) c4 \ sort (typ «foo1.u3»))) + c2 \ + [constructor a_k1 + (parameter B1 explicit (sort (typ «foo1.u1»)) c3 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c4 \ + arity + (prod `x` (global (indt «nat»)) c5 \ + prod `_` + (app + [c2, app [global (indt «prod»), c3, c3], c4, + app + [global (indc «S»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]]) c6 \ + app [c2, c3, c4, c5])), + constructor a_k2 + (parameter B1 explicit (sort (typ «foo1.u1»)) c3 \ + parameter B2 explicit (sort (typ «foo1.u2»)) c4 \ + arity + (prod `_` c0 c5 \ + app [c2, c3, c4, app [global (indc «S»), global (indc «O»)]]))] + I = «inductive_nup.foo1» + foo1 ?A2 ?B1 ?B2 ?n : Type + : Type + where + ?A1 : [ |- Type] + ?A2 : [ |- ?A1] + ?B1 : [ |- Type] + ?B2 : [ |- Type] + ?n : [ |- nat] + a_k1 ?A2 ?B1 ?B2 3 ?f : foo1 ?A2 ?B1 ?B2 3 + : foo1 ?A2 ?B1 ?B2 3 + where + ?A1 : [ |- Type] + ?A2 : [ |- ?A1] + ?B1 : [ |- Type] + ?B2 : [ |- Type] + ?f : [ |- foo1 ?A2 (?B1 * ?B1) ?B2 3] + Query assignments: + I = «inductive_nup.r» + R = parameter A explicit (sort (typ «r.u0»)) c0 \ + parameter a explicit c0 c1 \ + record r (sort (typ «r.u0»)) R + (field [coercion reversible, canonical tt] f (prod `_` c0 c2 \ c0) c2 \ + field [coercion off, canonical tt] g c0 c3 \ + field [coercion off, canonical tt] p + (app [global (indt «eq»), c0, c1, c3]) c4 \ end-record) + Record r (A : Type) (a : A) : Type := R { f : A -> A; g : A; p : a = g }. + + Arguments r A%type_scope a + Arguments R A%type_scope a f%function_scope g p + ----<<---- enter: coq.say raw: (inductive X1 tt (arity (sort prop)) c0 \ []) + raw: inductive X1 tt (arity (sort prop)) c0 \ [] + ---->>---- exit: coq.say raw: (inductive X1 tt (arity (sort prop)) c0 \ []) + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl (inductive X1 tt (arity (sort prop)) c0 \ [])) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl (inductive X1 tt (arity (sort prop)) c0 \ [])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: (inductive X1 tt (arity (sort prop)) c0 \ []) + typed: inductive X1 tt (arity (sort prop)) c0 \ [] + ---->>---- exit: + coq.say typed: (inductive X1 tt (arity (sort prop)) c0 \ []) + ----<<---- enter: + coq.env.add-indt (inductive X1 tt (arity (sort prop)) c0 \ []) X0 + ---->>---- exit: + coq.env.add-indt (inductive X1 tt (arity (sort prop)) c0 \ []) «X1» + X1 : Prop + + X1 is not universe polymorphic + Expands to: Inductive test.test.X1 + ----<<---- enter: + coq.say raw: + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ []) + (upoly-decl [«test.test.131»] tt [] tt) + raw: inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ [] + upoly-decl [«test.test.131»] tt [] tt + ---->>---- exit: + coq.say raw: + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ []) + (upoly-decl [«test.test.131»] tt [] tt) + ----<<---- enter: coq.univ.print + Universe constraints: UNIVERSES: + {eu1} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + eu1 + SORTS: + + WEAK CONSTRAINTS: + + + ---->>---- exit: coq.univ.print + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ [])) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ [])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ []) + typed: inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ [] + ---->>---- exit: + coq.say typed: + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ []) + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.131»] tt [] tt) X0 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.131»] tt [] tt) + (get-option coq:udecl (upoly-decl [«test.test.131»] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.131»] tt [] tt) => + coq.env.add-indt + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ []) X1 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.131»] tt [] tt) => + coq.env.add-indt + (inductive X3 tt (arity (sort (typ «test.test.131»))) c0 \ []) «X3» + ----<<---- enter: + coq.say raw: + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ []) + (upoly-decl-cumul [auto «test.test.139»] tt [] tt) + raw: inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ [] + upoly-decl-cumul [auto «test.test.139»] tt [] tt + ---->>---- exit: + coq.say raw: + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ []) + (upoly-decl-cumul [auto «test.test.139»] tt [] tt) + ----<<---- enter: coq.univ.print + Universe constraints: UNIVERSES: + {eu2} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + eu2 + SORTS: + + WEAK CONSTRAINTS: + + + ---->>---- exit: coq.univ.print + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ [])) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ [])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ []) + typed: inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ [] + ---->>---- exit: + coq.say typed: + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ []) + ----<<---- enter: + coq.upoly-decl->attribute + (upoly-decl-cumul [auto «test.test.139»] tt [] tt) X0 + ---->>---- exit: + coq.upoly-decl->attribute + (upoly-decl-cumul [auto «test.test.139»] tt [] tt) + (get-option coq:udecl-cumul + (upoly-decl-cumul [auto «test.test.139»] tt [] tt)) + ----<<---- enter: + get-option coq:udecl-cumul + (upoly-decl-cumul [auto «test.test.139»] tt [] tt) => + coq.env.add-indt + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ []) X1 + ---->>---- exit: + get-option coq:udecl-cumul + (upoly-decl-cumul [auto «test.test.139»] tt [] tt) => + coq.env.add-indt + (inductive X4 tt (arity (sort (typ «test.test.139»))) c0 \ []) «X4» + X3@{eu1} : Type@{eu1} + (* eu1 |= *) + + X3 is universe polymorphic + Expands to: Inductive test.test.X3 + X4@{eu2} : Type@{eu2} + (* *eu2 |= *) + + X4 is universe polymorphic + Expands to: Inductive test.test.X4 + Query assignments: + GR = indt «X3» + Universe constraints: + UNIVERSES: + {test.test.147} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + test.test.147 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + GR = indt «X4» + Universe constraints: + UNIVERSES: + {test.test.148} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + test.test.148 + SORTS: + + WEAK CONSTRAINTS: + + + ----<<---- enter: + coq.say raw: + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ []) + (upoly-decl [«test.test.149»] ff [] ff) + raw: inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ [] + upoly-decl [«test.test.149»] ff [] ff + ---->>---- exit: + coq.say raw: + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ []) + (upoly-decl [«test.test.149»] ff [] ff) + ----<<---- enter: coq.univ.print + Universe constraints: UNIVERSES: + {eu3} |= + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + eu3 + SORTS: + + WEAK CONSTRAINTS: + + + ---->>---- exit: coq.univ.print + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ [])) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ [])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ []) + typed: inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ [] + ---->>---- exit: + coq.say typed: + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ []) + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.149»] ff [] ff) X0 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.149»] ff [] ff) + (get-option coq:udecl (upoly-decl [«test.test.149»] ff [] ff)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.149»] ff [] ff) => + coq.env.add-indt + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ []) X1 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.149»] ff [] ff) => + coq.env.add-indt + (inductive X5 tt (arity (sort (typ «test.test.149»))) c0 \ []) «X5» + X5@{eu3} : Type@{eu3} + (* eu3 |= *) + + X5 is universe polymorphic + Expands to: Inductive test.test.X5 + ----<<---- enter: + coq.say raw: + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))]) + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff) + raw: + inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))] + upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff + ---->>---- exit: + coq.say raw: + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))]) + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff) + ----<<---- enter: coq.univ.print + Universe constraints: UNIVERSES: + {eu5 eu4} |= eu4 < eu5 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + eu5 + eu4 + SORTS: + + WEAK CONSTRAINTS: + + + ---->>---- exit: coq.univ.print + ----<<---- enter: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))])) + Illtyped inductive declaration + ---->>---- exit: + std.assert-ok! + (coq.typecheck-indt-decl + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))]) + typed: + inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))] + ---->>---- exit: + coq.say typed: + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))]) + ----<<---- enter: + coq.upoly-decl->attribute + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff) X0 + ---->>---- exit: + coq.upoly-decl->attribute + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff) + (get-option coq:udecl + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff)) + ----<<---- enter: + get-option coq:udecl + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff) => + coq.env.add-indt + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))]) + X1 + ---->>---- exit: + get-option coq:udecl + (upoly-decl [«test.test.157», «test.test.158»] ff + [lt «test.test.157» «test.test.158»] ff) => + coq.env.add-indt + (inductive X6 tt (arity (sort (typ «test.test.158»))) c0 \ + [constructor K (arity (prod `u` (sort (typ «test.test.157»)) c1 \ c0))]) + «X6» + X6@{eu4 eu5} : Type@{eu5} + (* eu4 eu5 |= eu4 < eu5 *) + + X6 is universe polymorphic + Expands to: Inductive test.test.X6 + ----<<---- enter: + coq.say raw: (inductive X8 tt (arity (sort (typ X0))) c0 \ []) + (upoly-decl [] tt [] tt) + raw: inductive X8 tt (arity (sort (typ X0))) c0 \ [] upoly-decl [] tt [] tt + ---->>---- exit: + coq.say raw: (inductive X8 tt (arity (sort (typ X0))) c0 \ []) + (upoly-decl [] tt [] tt) + ----<<---- enter: coq.univ.print + Universe constraints: + ---->>---- exit: coq.univ.print + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (inductive X8 tt (arity (sort (typ X0))) c0 \ []) X1) + Illtyped inductive declaration + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-indt-decl-skeleton + (inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ []) + (inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ [])) + Illtyped inductive declaration + ----<<---- enter: + coq.say typed: + (inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ []) + typed: inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ [] + ---->>---- exit: + coq.say typed: + (inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ []) + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X2 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-indt + (inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ []) X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-indt + (inductive X8 tt (arity (sort (typ «test.test.173»))) c0 \ []) «X8» + X8@{u} : Type@{u} + (* u |= *) + + X8 is universe polymorphic + Expands to: Inductive test.test.X8 + ----<<---- enter: + coq.arity->term + (parameter T explicit (sort (typ «test.test.181»)) c0 \ + parameter x explicit c0 c1 \ arity c0) X0 + ---->>---- exit: + coq.arity->term + (parameter T explicit (sort (typ «test.test.181»)) c0 \ + parameter x explicit c0 c1 \ arity c0) + (prod `T` (sort (typ «test.test.181»)) c0 \ prod `x` c0 c1 \ c0) + ----<<---- enter: + std.assert-ok! + (coq.typecheck + (fun `T` (sort (typ «test.test.181»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.181»)) c0 \ prod `x` c0 c1 \ c0)) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck + (fun `T` (sort (typ «test.test.181»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.181»)) c0 \ prod `x` c0 c1 \ c0)) + illtyped definition + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X1 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f1 + (fun `T` (sort (typ «test.test.181»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.181»)) c0 \ prod `x` c0 c1 \ c0) X2 X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f1 + (fun `T` (sort (typ «test.test.181»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.181»)) c0 \ prod `x` c0 c1 \ c0) X2 + «f1» + f1@{u} : forall T : Type@{u}, T -> T + (* u |= *) + + f1 is universe polymorphic + Arguments f1 T%type_scope x + f1 is transparent + Expands to: Constant test.test.f1 + ----<<---- enter: + coq.arity->term + (parameter T explicit (sort (typ «test.test.182»)) c0 \ + parameter T1 explicit (sort (typ «test.test.182»)) c1 \ + parameter x explicit c0 c2 \ arity c0) X0 + ---->>---- exit: + coq.arity->term + (parameter T explicit (sort (typ «test.test.182»)) c0 \ + parameter T1 explicit (sort (typ «test.test.182»)) c1 \ + parameter x explicit c0 c2 \ arity c0) + (prod `T` (sort (typ «test.test.182»)) c0 \ + prod `T1` (sort (typ «test.test.182»)) c1 \ prod `x` c0 c2 \ c0) + ----<<---- enter: + std.assert-ok! + (coq.typecheck + (fun `T` (sort (typ «test.test.182»)) c0 \ + fun `T1` (sort (typ «test.test.182»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.182»)) c0 \ + prod `T1` (sort (typ «test.test.182»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck + (fun `T` (sort (typ «test.test.182»)) c0 \ + fun `T1` (sort (typ «test.test.182»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.182»)) c0 \ + prod `T1` (sort (typ «test.test.182»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.182»] ff [] tt) X1 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.182»] ff [] tt) + (get-option coq:udecl (upoly-decl [«test.test.182»] ff [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.182»] ff [] tt) => + coq.env.add-const f2 + (fun `T` (sort (typ «test.test.182»)) c0 \ + fun `T1` (sort (typ «test.test.182»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.182»)) c0 \ + prod `T1` (sort (typ «test.test.182»)) c1 \ prod `x` c0 c2 \ c0) X2 X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.182»] ff [] tt) => + coq.env.add-const f2 + (fun `T` (sort (typ «test.test.182»)) c0 \ + fun `T1` (sort (typ «test.test.182»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.182»)) c0 \ + prod `T1` (sort (typ «test.test.182»)) c1 \ prod `x` c0 c2 \ c0) X2 + «f2» + f2@{u} : forall T : Type@{u}, Type@{u} -> T -> T + (* u |= *) + + f2 is universe polymorphic + Arguments f2 (T T1)%type_scope x + f2 is transparent + Expands to: Constant test.test.f2 + ----<<---- enter: + coq.arity->term + (parameter T explicit (sort (typ X0)) c0 \ + parameter x explicit c0 c1 \ arity (X1 c0 c1)) X2 + ---->>---- exit: + coq.arity->term + (parameter T explicit (sort (typ X0)) c0 \ + parameter x explicit c0 c1 \ arity (X3 c0 c1)) + (prod `T` (sort (typ X0)) c0 \ prod `x` c0 (X3 c0)) + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `T` (sort (typ X0)) c0 \ prod `x` c0 (X3 c0)) X4 X5) illtyped arity + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `T` (sort (typ «test.test.183»)) c0 \ prod `x` c0 (X6 c0)) + (typ «test.test.185») + (prod `T` (sort (typ «test.test.183»)) c0 \ prod `x` c0 c1 \ X7 c0 c1)) + illtyped arity + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (fun `T` (sort (typ X8)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.183»)) c0 \ prod `x` c0 c1 \ X7 c0 c1) + X9) illtyped definition + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton + (fun `T` (sort (typ «test.test.186»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.183»)) c0 \ prod `x` c0 c1 \ c0) + (fun `T` (sort (typ «test.test.183»)) c0 \ fun `x` c0 c1 \ c1)) + illtyped definition + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X10 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f3 + (fun `T` (sort (typ «test.test.183»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.183»)) c0 \ prod `x` c0 c1 \ c0) X11 X12 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f3 + (fun `T` (sort (typ «test.test.183»)) c0 \ fun `x` c0 c1 \ c1) + (prod `T` (sort (typ «test.test.183»)) c0 \ prod `x` c0 c1 \ c0) X11 + «f3» + f3@{u} : forall T : Type@{u}, T -> T + (* u |= *) + + f3 is universe polymorphic + Arguments f3 T%type_scope x + f3 is transparent + Expands to: Constant test.test.f3 + ----<<---- enter: + coq.arity->term + (parameter T explicit (sort (typ «test.test.187»)) c0 \ + parameter T1 explicit (sort (typ «test.test.187»)) c1 \ + parameter x explicit c0 c2 \ arity (X0 c0 c1 c2)) X1 + ---->>---- exit: + coq.arity->term + (parameter T explicit (sort (typ «test.test.187»)) c0 \ + parameter T1 explicit (sort (typ «test.test.187»)) c1 \ + parameter x explicit c0 c2 \ arity (X2 c0 c1 c2)) + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ prod `x` c0 (X2 c0 c1)) + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ prod `x` c0 (X2 c0 c1)) + X3 X4) illtyped arity + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ prod `x` c0 (X5 c0 c1)) + (typ «test.test.189») + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ + prod `x` c0 c2 \ X6 c0 c1 c2)) illtyped arity + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton + (fun `T` (sort (typ «test.test.187»)) c0 \ + fun `T1` (sort (typ «test.test.187»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ + prod `x` c0 c2 \ X6 c0 c1 c2) X7) illtyped definition + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton + (fun `T` (sort (typ «test.test.187»)) c0 \ + fun `T1` (sort (typ «test.test.187»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ prod `x` c0 c2 \ c0) + (fun `T` (sort (typ «test.test.187»)) c0 \ + fun `T1` (sort (typ «test.test.187»)) c1 \ fun `x` c0 c2 \ c2)) + illtyped definition + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.187»] ff [] tt) X8 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.187»] ff [] tt) + (get-option coq:udecl (upoly-decl [«test.test.187»] ff [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.187»] ff [] tt) => + coq.env.add-const f4 + (fun `T` (sort (typ «test.test.187»)) c0 \ + fun `T1` (sort (typ «test.test.187»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ prod `x` c0 c2 \ c0) X9 X10 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.187»] ff [] tt) => + coq.env.add-const f4 + (fun `T` (sort (typ «test.test.187»)) c0 \ + fun `T1` (sort (typ «test.test.187»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.187»)) c0 \ + prod `T1` (sort (typ «test.test.187»)) c1 \ prod `x` c0 c2 \ c0) X9 + «f4» + f4@{u} : forall T : Type@{u}, Type@{u} -> T -> T + (* u |= *) + + f4 is universe polymorphic + Arguments f4 (T T1)%type_scope x + f4 is transparent + Expands to: Constant test.test.f4 + ----<<---- enter: + coq.arity->term + (parameter T explicit (sort (typ «uuu»)) c0 \ + parameter T1 explicit (sort (typ «uuu»)) c1 \ + parameter x explicit c0 c2 \ arity (X0 c0 c1 c2)) X1 + ---->>---- exit: + coq.arity->term + (parameter T explicit (sort (typ «uuu»)) c0 \ + parameter T1 explicit (sort (typ «uuu»)) c1 \ + parameter x explicit c0 c2 \ arity (X2 c0 c1 c2)) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 (X2 c0 c1)) + ----<<---- enter: + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 (X2 c0 c1)) X3 X4) + illtyped arity + ---->>---- exit: + std.assert-ok! + (coq.elaborate-ty-skeleton + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 (X5 c0 c1)) + (typ «test.test.194») + (prod `T` (sort (typ «test.test.191»)) c0 \ + prod `T1` (sort (typ «test.test.192»)) c1 \ + prod `x` c0 c2 \ X6 c0 c1 c2)) illtyped arity + ----<<---- enter: + std.assert-ok! + (coq.elaborate-skeleton + (fun `T` (sort (typ «uuu»)) c0 \ + fun `T1` (sort (typ «uuu»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.191»)) c0 \ + prod `T1` (sort (typ «test.test.192»)) c1 \ + prod `x` c0 c2 \ X6 c0 c1 c2) X7) illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.elaborate-skeleton + (fun `T` (sort (typ «uuu»)) c0 \ + fun `T1` (sort (typ «uuu»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.191»)) c0 \ + prod `T1` (sort (typ «test.test.192»)) c1 \ prod `x` c0 c2 \ c0) + (fun `T` (sort (typ «test.test.195»)) c0 \ + fun `T1` (sort (typ «test.test.196»)) c1 \ fun `x` c0 c2 \ c2)) + illtyped definition + ----<<---- enter: + coq.env.add-const f5 + (fun `T` (sort (typ «test.test.195»)) c0 \ + fun `T1` (sort (typ «test.test.196»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «test.test.191»)) c0 \ + prod `T1` (sort (typ «test.test.192»)) c1 \ prod `x` c0 c2 \ c0) X8 X9 + ---->>---- exit: + coq.env.add-const f5 + (fun `T` (sort (typ «f5.u2»)) c0 \ + fun `T1` (sort (typ «f5.u3»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «f5.u0»)) c0 \ + prod `T1` (sort (typ «f5.u1»)) c1 \ prod `x` c0 c2 \ c0) X8 «f5» + ----<<---- enter: + coq.arity->term + (parameter T explicit (sort (typ «uuu»)) c0 \ + parameter T1 explicit (sort (typ «test.test.197»)) c1 \ + parameter x explicit c0 c2 \ arity c0) X0 + ---->>---- exit: + coq.arity->term + (parameter T explicit (sort (typ «uuu»)) c0 \ + parameter T1 explicit (sort (typ «test.test.197»)) c1 \ + parameter x explicit c0 c2 \ arity c0) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.197»)) c1 \ prod `x` c0 c2 \ c0) + ----<<---- enter: + std.assert-ok! + (coq.typecheck + (fun `T` (sort (typ «uuu»)) c0 \ + fun `T1` (sort (typ «test.test.197»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.197»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck + (fun `T` (sort (typ «uuu»)) c0 \ + fun `T1` (sort (typ «test.test.197»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.197»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.197»] ff [] tt) X1 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.197»] ff [] tt) + (get-option coq:udecl (upoly-decl [«test.test.197»] ff [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.197»] ff [] tt) => + coq.env.add-const f6 + (fun `T` (sort (typ «uuu»)) c0 \ + fun `T1` (sort (typ «test.test.197»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.197»)) c1 \ prod `x` c0 c2 \ c0) X2 X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.197»] ff [] tt) => + coq.env.add-const f6 + (fun `T` (sort (typ «uuu»)) c0 \ + fun `T1` (sort (typ «test.test.197»)) c1 \ fun `x` c0 c2 \ c2) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.197»)) c1 \ prod `x` c0 c2 \ c0) X2 + «f6» + f6@{uuux} : forall T : Type@{uuu}, Type@{uuux} -> T -> T + (* uuux |= *) + + f6 is universe polymorphic + Arguments f6 (T T1)%type_scope x + f6 is transparent + Expands to: Constant test.test.f6 + ----<<---- enter: + coq.arity->term + (arity + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0)) X0 + ---->>---- exit: + coq.arity->term + (arity + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0)) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0) + ----<<---- enter: + std.assert-ok! + (coq.typecheck (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X1 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f7 (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0) X2 X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f7 (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0) X2 «f7» + ----<<---- enter: coq.arity->term (arity X0) X1 + ---->>---- exit: coq.arity->term (arity X1) X1 + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! (coq.elaborate-ty-skeleton X1 X2 X3) illtyped arity + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! (coq.elaborate-ty-skeleton X1 (typ «test.test.198») (X4)) + illtyped arity + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (pglobal (const «f6») «Set») (X4) X5) + illtyped definition + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0) + (pglobal (const «f6») «Set»)) illtyped definition + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X6 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f8 (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0) X7 X8 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f8 (pglobal (const «f6») «Set») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «Set»)) c1 \ prod `x` c0 c2 \ c0) X7 «f8» + ----<<---- enter: + coq.arity->term + (arity + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0)) X0 + ---->>---- exit: + coq.arity->term + (arity + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0)) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0) + ----<<---- enter: + std.assert-ok! + (coq.typecheck (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X1 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f7' (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0) X2 X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f7' (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0) X2 «f7'» + ----<<---- enter: coq.arity->term (arity X0) X1 + ---->>---- exit: coq.arity->term (arity X1) X1 + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! (coq.elaborate-ty-skeleton X1 X2 X3) illtyped arity + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! (coq.elaborate-ty-skeleton X1 (typ «test.test.199») (X4)) + illtyped arity + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (pglobal (const «f6») «uuu») (X4) X5) + illtyped definition + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0) + (pglobal (const «f6») «uuu»)) illtyped definition + ----<<---- enter: coq.upoly-decl->attribute (upoly-decl [] tt [] tt) X6 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [] tt [] tt) + (get-option coq:udecl (upoly-decl [] tt [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f8' (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0) X7 X8 + ---->>---- exit: + get-option coq:udecl (upoly-decl [] tt [] tt) => + coq.env.add-const f8' (pglobal (const «f6») «uuu») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «uuu»)) c1 \ prod `x` c0 c2 \ c0) X7 «f8'» + ----<<---- enter: + coq.arity->term + (arity + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0)) X0 + ---->>---- exit: + coq.arity->term + (arity + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0)) + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0) + ----<<---- enter: + std.assert-ok! + (coq.typecheck (pglobal (const «f6») «test.test.200») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ---->>---- exit: + std.assert-ok! + (coq.typecheck (pglobal (const «f6») «test.test.200») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0)) + illtyped definition + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.200»] ff [] tt) X1 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.200»] ff [] tt) + (get-option coq:udecl (upoly-decl [«test.test.200»] ff [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.200»] ff [] tt) => + coq.env.add-const f7'' (pglobal (const «f6») «test.test.200») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0) X2 X3 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.200»] ff [] tt) => + coq.env.add-const f7'' (pglobal (const «f6») «test.test.200») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.200»)) c1 \ prod `x` c0 c2 \ c0) X2 + «f7''» + ----<<---- enter: coq.arity->term (arity X0) X1 + ---->>---- exit: coq.arity->term (arity X1) X1 + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! (coq.elaborate-ty-skeleton X1 X2 X3) illtyped arity + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! (coq.elaborate-ty-skeleton X1 (typ «test.test.202») (X4)) + illtyped arity + ----<<---- enter: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (pglobal (const «f6») «test.test.201») (X4) X5) + illtyped definition + ---->>---- exit: + get-option coq:keepunivs tt => + std.assert-ok! + (coq.elaborate-skeleton (pglobal (const «f6») «test.test.201») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.201»)) c1 \ prod `x` c0 c2 \ c0) + (pglobal (const «f6») «test.test.201»)) illtyped definition + ----<<---- enter: + coq.upoly-decl->attribute (upoly-decl [«test.test.201»] ff [] tt) X6 + ---->>---- exit: + coq.upoly-decl->attribute (upoly-decl [«test.test.201»] ff [] tt) + (get-option coq:udecl (upoly-decl [«test.test.201»] ff [] tt)) + ----<<---- enter: + get-option coq:udecl (upoly-decl [«test.test.201»] ff [] tt) => + coq.env.add-const f8'' (pglobal (const «f6») «test.test.201») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.201»)) c1 \ prod `x` c0 c2 \ c0) X7 X8 + ---->>---- exit: + get-option coq:udecl (upoly-decl [«test.test.201»] ff [] tt) => + coq.env.add-const f8'' (pglobal (const «f6») «test.test.201») + (prod `T` (sort (typ «uuu»)) c0 \ + prod `T1` (sort (typ «test.test.201»)) c1 \ prod `x` c0 c2 \ c0) X7 + «f8''» + const-decl D + (some + (fun `i` (global (indt «I»)) c0 \ + fun `l` (app [global (indt «L»), c0]) c1 \ global (indt «True»))) + (parameter i maximal (global (indt «I»)) c0 \ + parameter l maximal (app [global (indt «L»), c0]) c1 \ arity (sort prop)) + const-decl D + (some + (fun `i` (global (indt «I»)) c0 \ + fun `H` (app [global (indt «L»), c0]) c1 \ global (indt «True»))) + (parameter i maximal (global (indt «I»)) c0 \ + parameter H maximal (app [global (indt «L»), c0]) c1 \ arity (sort prop)) + const-decl D + (some + (fun `i` (global (indt «I»)) c0 \ + fun `H` (app [global (indt «L»), c0]) c1 \ + fun `n` (global (indt «nat»)) c2 \ global (indt «True»))) + (parameter i maximal (global (indt «I»)) c0 \ + parameter H maximal (app [global (indt «L»), c0]) c1 \ + parameter n explicit (global (indt «nat»)) c2 \ arity (sort prop)) diff --git a/tests/test_arg_HOAS.v b/tests/arg_HOAS.t/test.v similarity index 100% rename from tests/test_arg_HOAS.v rename to tests/arg_HOAS.t/test.v diff --git a/tests/cache_async.t/run.t b/tests/cache_async.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/cache_async.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_cache_async.v b/tests/cache_async.t/test.v similarity index 100% rename from tests/test_cache_async.v rename to tests/cache_async.t/test.v diff --git a/tests/checker.t/run.t b/tests/checker.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/checker.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_checker.v b/tests/checker.t/test.v similarity index 100% rename from tests/test_checker.v rename to tests/checker.t/test.v diff --git a/tests/ctx_cache.t/run.t b/tests/ctx_cache.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/ctx_cache.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_ctx_cache.v b/tests/ctx_cache.t/test.v similarity index 94% rename from tests/test_ctx_cache.v rename to tests/ctx_cache.t/test.v index 976b93a78..d8eb392f1 100644 --- a/tests/test_ctx_cache.v +++ b/tests/ctx_cache.t/test.v @@ -30,7 +30,7 @@ Notation t := nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat * nat )%type. -Time Goal +(*Time*) Goal forall (x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 : t), forall (x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 : t), forall (x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 : t), @@ -39,9 +39,9 @@ forall (x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 : t), True. intros. Optimize Heap. -Time elpi perf nocache 3000. +(*Time*) elpi perf nocache 3000. Optimize Heap. -Time elpi perf cache 3000. +(*Time*) elpi perf cache 3000. trivial. Qed. diff --git a/tests/dune b/tests/dune new file mode 100644 index 000000000..c49811c04 --- /dev/null +++ b/tests/dune @@ -0,0 +1,7 @@ +(cram + (applies_to :whole_subtree) + (deps + %{bin:coqc} + %{bin:coqdep} + (package coq-elpi) + setup-project.sh)) diff --git a/tests/elaborator.t/run.t b/tests/elaborator.t/run.t new file mode 100644 index 000000000..d78391bdb --- /dev/null +++ b/tests/elaborator.t/run.t @@ -0,0 +1,9 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, external file elpi_elaborator.elpi is required + from root elpi_elpi and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-63: + Error: No LoadPath found for elpi_elpi. + + [1] diff --git a/tests/test_elaborator.v b/tests/elaborator.t/test.v similarity index 98% rename from tests/test_elaborator.v rename to tests/elaborator.t/test.v index 74a2cd3b4..ef11ea15b 100644 --- a/tests/test_elaborator.v +++ b/tests/elaborator.t/test.v @@ -1,4 +1,4 @@ -From unreleased Extra Dependency "elpi_elaborator.elpi" as elab. +From elpi_elpi Extra Dependency "elpi_elaborator.elpi" as elab. From Coq Require Import PrimInt63 PrimFloat. From elpi Require Import elpi. diff --git a/tests/example_abs_evars.t/run.t b/tests/example_abs_evars.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/example_abs_evars.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/example_abs_evars.t/test.v b/tests/example_abs_evars.t/test.v new file mode 100644 index 000000000..96fb4e4c3 --- /dev/null +++ b/tests/example_abs_evars.t/test.v @@ -0,0 +1,117 @@ +From elpi Require Import elpi. + +(** Closing a term with holes with binders *) + +(* + +The operation consists in replacing all occurrences of the same hole +in a term by a bound variable. + +We first traverse the term and count how many distinct hole are there +and replace them by a placeholder to be later abstracted. +Once we know how many binders we need, we generate the spine of binders +and replace the placeholders by the bound variables. + +This example is interesting because it uses the constraint store +to attach data to holes, in particular if the hole has been seen before, +and to attach to each hole a unique number. + +*) + +Elpi Tactic abs_evars. +Elpi Accumulate lp:{{ + +% we add a new constructor to terms to represent terms to be abstracted +type abs int -> term. + +% bind back abstracted subterms +pred bind i:int, i:int, i:term, o:term. +bind I M T T1 :- M > I, !, + T1 = {{ forall x, lp:(B x) }}, + N is I + 1, + pi x\ % we allocate the fresh symbol for (abs M) + (copy (abs N) x :- !) => % we schedule the replacement (abs M) -> x + bind N M T (B x). +bind M M T T1 :- copy T T1. % we perform all the replacements + +% for a term with M holes, returns a term with M variables to fill these holes +% the clause see is only generated for a term if it hasn't been seen before +% the term might need to be typechecked first or main generates extra holes for the +% type of the parameters +pred abs-evars i:term, o:term, o:int. +abs-evars T1 T3 M :- std.do! [ + % we put (abs N) in place of each occurrence of the same hole + (pi T Ty N N' M \ fold-map T N (abs M) M :- var T, not (seen? T _), !, coq.typecheck T Ty ok, fold-map Ty N _ N', M is N' + 1, seen! T M) => + (pi T N M \ fold-map T N (abs M) N :- var T, seen? T M, !) => + fold-map T1 0 T2 M, + % we abstract M holes (M abs nodes) + bind 0 M T2 T3, + % cleanup constraint store + purge-seen!, +]. + +% all constraints are also on _ so that they share +% a variable with the constraint to purge the store + +% we query if the hole was seen before, and if so +% we fetch its number +pred seen? i:term, o:int. +seen? X Y :- declare_constraint (seen? X Y) [X,_]. + +% we declare it is now seen and label it with a number +pred seen! i:term, i:int. +seen! X Y :- declare_constraint (seen! X Y) [X,_]. + +% to empty the store +pred purge-seen!. +purge-seen! :- declare_constraint purge-seen! [_]. + +constraint seen? seen! purge-seen! { + % a succesful query, give the label back via M + rule (seen! X N) \ (seen? X M) <=> (M = N). + % an unsuccesful query + rule \ (seen? X _) <=> false. + + rule purge-seen! \ (seen! _ _). + rule \ purge-seen!. +} + +% if we pass an argument this is what we use to refine the goal +solve (goal _ _ _ _ [trm T] as G) GL :- + std.assert-ok! (coq.elaborate-ty-skeleton T _ T1) "illtyped", + std.assert! (abs-evars T1 ClosedT1 _) "closure fails", + refine ClosedT1 G GL. + +% if we pass no argument, then we abstract the goal. +% the first subgoal is a proof of the abstracted goal, while +% the other goals are for the abstracted premises +solve (goal _ _ T _ [] as G) GL :- + std.assert! (abs-evars T ClosedT N) "closure fails", + coq.mk-app {{ (fun x : lp:ClosedT => x) _ }} {coq.mk-n-holes N} R, + refine R G GL. + +}}. +Elpi Typecheck. +Elpi Export abs_evars. + +Fail Lemma test : forall x, x = x. +Lemma test : abs_evars (forall x, x = x). +intros t x; reflexivity. +Abort. + +Lemma test : abs_evars (forall x y, x = y). +intros t x y; symmetry. +Abort. + +Lemma test : True. +assert (abs_evars (tt = _)) as H. + intro x; destruct x; reflexivity. +Abort. + +Lemma test : exists x, x = tt. +econstructor. +(* it is silly, but shows the code above performs the abstraction *) +elpi abs_evars. + now intros []. +exact tt. +Qed. diff --git a/tests/example_curry_howard_tactics.t/run.t b/tests/example_curry_howard_tactics.t/run.t new file mode 100644 index 000000000..1d5ea1576 --- /dev/null +++ b/tests/example_curry_howard_tactics.t/run.t @@ -0,0 +1,12 @@ + $ . ../setup-project.sh + $ dune build test.vo + goal X0 c0 c1 c2 c3 is + + [decl c3 `H` (app [global (const «lt»), c0, c1]), + decl c2 `z` (global (indt «nat»)), decl c1 `y` (global (indt «nat»)), + decl c0 `x` (global (indt «nat»))] + ------- + + prod `_` (app [global (const «lt»), c1, c2]) c4 \ + app [global (const «lt»), c0, c2] + 3 diff --git a/tests/example_curry_howard_tactics.t/test.v b/tests/example_curry_howard_tactics.t/test.v new file mode 100644 index 000000000..7e984143b --- /dev/null +++ b/tests/example_curry_howard_tactics.t/test.v @@ -0,0 +1,90 @@ +From elpi Require Import elpi. + +(* Tactics + + The entry point of a tactic is called solve + and the goal is made of a proof context, a type + to inhabit and the corresponding evar to assign *) + +Elpi Tactic id. +Elpi Accumulate lp:{{ + solve (goal Ctx Ev Ty _ _) _ :- + coq.say "goal" Ev "is\n" Ctx "\n-------\n" Ty. +}}. +Elpi Typecheck. + + +Lemma l0 x y z (H : x < y) : y < z -> x < z. +Proof. +elpi id. +Abort. + +(* Things are wired up in such a way that assigning a + "wrong" value to Ev fails *) + +Elpi Tactic silly. +Elpi Accumulate lp:{{ + solve (goal _ Ev _ _ _) _ :- Ev = {{true}}. + solve (goal _ Ev _ _ _) _ :- Ev = {{3}}. +}}. +Elpi Typecheck. + +Lemma l1 : nat. +Proof. +elpi silly. +Show Proof. +Qed. + +(* Now we write "intro" in Curry-Howard style *) + +Elpi Tactic intro. +Elpi Accumulate lp:{{ + solve (goal _ _ _ _ [str S] as G) GS :- + coq.string->name S N, + refine (fun N Src_ Tgt_) G GS. +}}. +Elpi Typecheck. + +Lemma l2 x y z (H : x < y) : y < z -> x < z. +Proof. +elpi intro H1. +Abort. + +(* Now let's write a little automation *) + +Elpi Tactic auto. +Elpi Accumulate lp:{{ + shorten coq.ltac.{ open , or , repeat }. + + pred intro i:name, i:goal, o:list sealed-goal. + intro S G GS :- refine (fun S Src_ Tgt_) G GS. + + % Ex falso + pred exf i:goal, o:list sealed-goal. + exf (goal Ctx _ Ty _ _ as G) [] :- + std.exists Ctx (x\ sigma w\ x = decl V w {{False}}), + refine {{ match lp:V in False return lp:Ty with end }} G []. + + % Constructor + pred kon i:goal, o:list sealed-goal. + kon (goal _ _ Ty _ _ as G) GS :- + coq.safe-dest-app Ty (global (indt GR)) _, + coq.env.indt GR _ _ _ _ Ks Kt, + std.exists2 Ks Kt (k\ t\ + coq.saturate t (global (indc k)) P, + refine P G GS). + + % entry point; we assert no goals are left + solve G [] :- + repeat (or [open exf, open kon, open (intro `H`)]) (seal G) []. + +}}. +Elpi Typecheck. + +Lemma l3 : forall P : Prop, (False -> P) /\ (False \/ True). +Proof. +elpi auto. +Qed. + + + diff --git a/tests/example_data_base.t/run.t b/tests/example_data_base.t/run.t new file mode 100644 index 000000000..16d66d862 --- /dev/null +++ b/tests/example_data_base.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + The Db contains [phone_prefix USA 1] + Phone prefix for USA is 1 + The Db contains + [phone_prefix USA 1, phone_prefix France 33, phone_prefix Italy 39] + Phone prefix for France is 33 + sweet! + brr + yummy! diff --git a/tests/example_data_base.t/test.v b/tests/example_data_base.t/test.v new file mode 100644 index 000000000..dbe9a11d8 --- /dev/null +++ b/tests/example_data_base.t/test.v @@ -0,0 +1,93 @@ +From elpi Require Import elpi. + +(** Data bases are accumulated by name, hence can be shared among multiple + commands or across successive executions of the same command. + + Let's start with a db containing international phone prefixes *) + +Elpi Db phonebook.db lp:{{ + pred phone_prefix o:string, o:int. + phone_prefix "USA" 1. +}}. + +Elpi Command print_db. +Elpi Accumulate Db phonebook.db. +Elpi Accumulate lp:{{ + main [] :- std.findall (phone_prefix S_ N_) L, !, coq.say "The Db contains" L. + main [str S] :- coq.say "Phone prefix for" S "is" {phone_prefix S}, !. + main [str S] :- coq.error "No prefix for" S. +}}. +Elpi Typecheck. + +Elpi print_db. +Elpi print_db USA. +Fail Elpi print_db Italy. + +Elpi Command add_db. +Elpi Accumulate Db phonebook.db. +Elpi Accumulate lp:{{ + main [str S, int N] :- + coq.elpi.accumulate _ "phonebook.db" (clause _ _ (phone_prefix S N)). +}}. +Elpi Typecheck. + +Elpi add_db France 33. +Elpi add_db Italy 39. +Elpi print_db. +Elpi print_db France. + +(** Data bases don't need to be that simple, they can contain + arbitrary clauses, in particular conditional ones. *) + +Elpi Db food.db lp:{{ + + pred sweet o:string. + sweet "apricot". + + pred tasty o:string. + tasty "salmon". + +}}. +Elpi Command add_recipy. +Elpi Accumulate Db food.db. +Elpi Accumulate lp:{{ + pred test-sweetness i:argument, o:prop. + test-sweetness (str X) (sweet X). + + pred test-tastiness i:argument, o:prop. + test-tastiness (str X) (tasty X). + + main [str Name|Ingredients] :- + std.map Ingredients test-sweetness SweetConditions, + % trick: ":-" accepts a list of propositions on the RHS + coq.elpi.accumulate _ "food.db" (clause _ _ (sweet Name :- SweetConditions)), + + std.map Ingredients test-tastiness TastyConditions, + std.forall TastyConditions (i\ + coq.elpi.accumulate _ "food.db" (clause _ _ (tasty Name :- i))). +}}. +Elpi Typecheck. + +Elpi Command is_sweet. +Elpi Accumulate Db food.db. +Elpi Accumulate lp:{{ + main [str Name] :- if (sweet Name) (coq.say "sweet!") (coq.say "brr"). +}}. +Elpi Typecheck. + +Elpi Command is_tasty. +Elpi Accumulate Db food.db. +Elpi Accumulate lp:{{ + main [str Name] :- if (tasty Name) (coq.say "yummy!") (coq.say "bohf"). +}}. +Elpi Typecheck. + +Elpi add_recipy "pie" "potato" "salmon". +Elpi add_recipy "jam" "apricot". +Elpi add_recipy "tart" "jam". + +Elpi is_sweet "tart". +Elpi is_sweet "pie". +Elpi is_tasty "pie". + + diff --git a/tests/example_fuzzer.t/run.t b/tests/example_fuzzer.t/run.t new file mode 100644 index 000000000..db24cf4a9 --- /dev/null +++ b/tests/example_fuzzer.t/run.t @@ -0,0 +1,35 @@ + $ . ../setup-project.sh + $ dune build test.vo + DEBUG: attempt at fuzzing binary op: global (indc «PLUS») + DEBUG: attempt at fuzzing binary op: global (const «Nat.add») + DEBUG: attempt at fuzzing binary op: global (indc «AND») + DEBUG: fuzzed! + DEBUG: attempt at fuzzing binary op: global (const «andb») + DEBUG: attempt at fuzzing binary op: global (indc «OR») + DEBUG: fuzzed! + DEBUG: attempt at fuzzing binary op: global (const «orb») + DEBUG: attempt at fuzzing binary op: global (indc «EQ») + DEBUG: attempt at fuzzing binary op: global (const «Nat.eqb») + Inductive eval1 : forall T : ty, Exp T -> Val T -> Prop := + E_Num1 : forall n : nat, eval1 N (NUM n) (iNv n) + | E_Bool1 : forall b : bool, eval1 B (BOOL b) (iBv b) + | E_Plus1 : forall (e1 e2 : Exp N) (n1 n2 : nat), + eval1 N e1 (iNv n1) -> + eval1 N e2 (iNv n2) -> eval1 N (PLUS e1 e2) (iNv (n1 + n2)) + | E_AND1 : forall (e1 e2 : Exp B) (b1 b2 : bool), + eval1 B e1 (iBv b1) -> + eval1 B e2 (iBv b2) -> eval1 B (AND e1 e2) (iBv (b1 && b2)) + | E_OR1 : forall (e1 e2 : Exp B) (b1 b2 : bool), + eval1 B e1 (iBv b1) -> + eval1 B e2 (iBv b2) -> eval1 B (AND e1 e2) (iBv (b1 || b2)) + | E_EQ1 : forall (e1 e2 : Exp N) (n1 n2 : nat), + eval1 N e1 (iNv n1) -> + eval1 N e2 (iNv n2) -> eval1 B (EQ e1 e2) (iBv (Nat.eqb n1 n2)). + + Arguments eval1 T _ _ + Arguments E_Num1 n%nat_scope + Arguments E_Bool1 b%bool_scope + Arguments E_Plus1 e1 e2 (n1 n2)%nat_scope _ _ + Arguments E_AND1 e1 e2 (b1 b2)%bool_scope _ _ + Arguments E_OR1 e1 e2 (b1 b2)%bool_scope _ _ + Arguments E_EQ1 e1 e2 (n1 n2)%nat_scope _ _ diff --git a/tests/example_fuzzer.t/test.v b/tests/example_fuzzer.t/test.v new file mode 100644 index 000000000..0c4b010e4 --- /dev/null +++ b/tests/example_fuzzer.t/test.v @@ -0,0 +1,99 @@ +From elpi Require Import elpi. + +(** Intrinsically typed data type and semantics, from software foundations. + + We devise a command to fuzz the semantics by flipping some operators. + We do it by locally checking that the fuzzing produces welltyped terms, + reducing a bit the nondeterminism of the fuzzer. +*) + +Inductive ty := B | N. + +Inductive Exp : ty -> Type := +| NUM : nat -> Exp N +| BOOL : bool -> Exp B +| PLUS : Exp N -> Exp N -> Exp N +| AND : Exp B -> Exp B -> Exp B +| OR : Exp B -> Exp B-> Exp B +| EQ : Exp N -> Exp N -> Exp B. + +Inductive Val : ty -> Set := + | iNv : nat -> Val N + | iBv : bool -> Val B. + +Inductive eval : forall {T: ty}, Exp T -> Val T -> Prop := + | E_Num n : + eval (NUM n) (iNv n) + | E_Bool b : + eval (BOOL b) (iBv b) + | E_Plus e1 e2 n1 n2 : + eval e1 (iNv n1) -> + eval e2 (iNv n2) -> + eval (PLUS e1 e2) (iNv (n1 + n2)) + | E_AND e1 e2 b1 b2 : + eval e1 (iBv b1) -> + eval e2 (iBv b2) -> + eval (AND e1 e2) (iBv (b1 && b2)) + | E_OR e1 e2 b1 b2 : + eval e1 (iBv b1) -> + eval e2 (iBv b2) -> + eval (OR e1 e2) (iBv (b1 || b2)) + | E_EQ e1 e2 n1 n2 : + eval e1 (iNv n1) -> + eval e2 (iNv n2) -> + eval (EQ e1 e2) (iBv (Nat.eqb n1 n2)). + +Elpi Command fuzz. +Elpi Accumulate lp:{{ + +pred fuzz i:term, o:term. + +% fuzzin rule: we look for a Coq term (?Op ?A ?B) and we turn it in (AND ?A ?B) +% only if the new term is well typed. +fuzz {{ lp:Op lp:A lp:B }} Fuzzed :- + coq.say "DEBUG: attempt at fuzzing binary op:" Op, + fuzz A A1, fuzz B B1, + Fuzzed = {{ AND lp:A1 lp:B1 }}, + coq.typecheck Fuzzed _ ok, % we don't care about the type, only that it is ok + coq.say "DEBUG: fuzzed!". + +% rule for the dependent function space +fuzz (prod N S T) (prod N S1 T1) :- + fuzz S S1, + % we load the context with types for x and y, as well as the fact that + % we fuzz x to y + pi x y\ decl x N S => decl y N S1 => fuzz x y => fuzz (T x) (T1 y). + +% rule for application +fuzz (app L) (app L1) :- std.map L fuzz L1. + +% rule for global constants +fuzz (global X) (global X). + +% TODO: we should have clauses for all other type formers... + +pred rename-constructors i:constructor, o:pair constructor string. +rename-constructors C (pr C C1) :- + coq.gref->id (indc C) S, + C1 is S ^ "1". + +main [str IN, str OUT ] :- + % locate the inductive + coq.locate IN (indt I), + % fetch all its data, in particulat the types of the constructors + coq.env.indt I B NP NPU A KN KT, + % fuzz all constructor types + std.map KT fuzz KT1, + % we rename them, otherwise Coq complains the names are already used + std.map KN rename-constructors KN1, + % declare the new inductive + coq.build-indt-decl (pr I OUT) B NP NPU A KN1 KT1 Decl, + coq.env.add-indt Decl _. + +}}. +Elpi Typecheck. + +Elpi fuzz eval eval1. + +(* let's print our new, broken, semantics ;-) *) +Print eval1. \ No newline at end of file diff --git a/tests/example_generalize.t/run.t b/tests/example_generalize.t/run.t new file mode 100644 index 000000000..905e1e780 --- /dev/null +++ b/tests/example_generalize.t/run.t @@ -0,0 +1,3 @@ + $ . ../setup-project.sh + $ dune build test.vo + 3 + 7 ===> fun (x : ?e) (x0 : ?e0) => S (S x0) + S (S (S (S (S (S x))))) diff --git a/tests/example_generalize.t/test.v b/tests/example_generalize.t/test.v new file mode 100644 index 000000000..158f9baa5 --- /dev/null +++ b/tests/example_generalize.t/test.v @@ -0,0 +1,39 @@ +From elpi Require Import elpi. + +(** Abstract a term over something, like the generalize tactic *) + +Elpi Command generalize. +Elpi Accumulate lp:{{ + +% we add a new constructor to terms to represent terms to be abstracted +type abs int -> term. + +% example rule, abstracts all 1s. We place it at the beginning of fold-map, see +% coq-lib.elpi for the full definition of fold-map +:before "fold-map:start" +fold-map {{ 1 }} N (abs M) M :- !, M is N + 1. + +% bind back abstracted subterms +pred bind i:int, i:term, o:term. +bind M T T1 :- M > 0, + T1 = {{ fun x => lp:(B x) }}, % we build a Coq "fun .. => " + N is M - 1, + pi x\ % we allocate the fresh symbol for (abs M) + (copy (abs M) x :- !) => % we schedule the replacement (abs M) -> x + bind N T (B x). +bind 0 T T1 :- copy T T1. % we perform all the replacements + +main [trm T] :- std.do! [ + fold-map T 0 T1 M, + bind M T1 T2, + coq.say {coq.term->string T} "===>" {coq.term->string T2}, +]. + + +}}. +Elpi Typecheck. + +Elpi generalize (3 + 7). +(* prints: + (3 + 7) ===> (fun (x : ?e) (x0 : ?e0) => S (S x0) + S (S (S (S (S (S x)))))) +*) diff --git a/tests/example_import_projections.t/run.t b/tests/example_import_projections.t/run.t new file mode 100644 index 000000000..54a6e0899 --- /dev/null +++ b/tests/example_import_projections.t/run.t @@ -0,0 +1,23 @@ + $ . ../setup-project.sh + $ dune build test.vo + Notation p2 := (p2 nat 3 x) + test.test.p1 nat 3 x : nat + : nat + p1 : forall (T : Type) (t : T), r T t -> nat + : forall (T : Type) (t : T), r T t -> nat + eq_refl : test.test.p1 bool false (Build bool false 3 eq_refl eq_refl) = 3 + : test.test.p1 bool false (Build bool false 3 eq_refl eq_refl) = 3 + test.f1 _ x + : bool + File "./test.v", line 48, characters 0-21: + Warning: Trying to mask the absolute name "test.test.p1"! + [masking-absolute-name,deprecated-since-8.8,deprecated,default] + File "./test.v", line 48, characters 0-21: + Warning: Trying to mask the absolute name "test.test.p2"! + [masking-absolute-name,deprecated-since-8.8,deprecated,default] + File "./test.v", line 57, characters 0-70: + Warning: Trying to mask the absolute name "test.test.p1"! + [masking-absolute-name,deprecated-since-8.8,deprecated,default] + File "./test.v", line 57, characters 0-70: + Warning: Trying to mask the absolute name "test.test.p2"! + [masking-absolute-name,deprecated-since-8.8,deprecated,default] diff --git a/tests/example_import_projections.t/test.v b/tests/example_import_projections.t/test.v new file mode 100644 index 000000000..5f44e339f --- /dev/null +++ b/tests/example_import_projections.t/test.v @@ -0,0 +1,73 @@ +From elpi Require Import elpi. + +(* "import" a record instance by naming it's applied projections *) + +Elpi Command import.projections. +Elpi Accumulate lp:{{ +main [str S] :- + coq.locate S GR, + coq.env.typeof GR Ty, + main-import-projections (global GR) Ty. +main [trm TSkel] :- + % input terms are not elaborated yet + std.assert-ok! (coq.elaborate-skeleton TSkel Ty T) "input term illtyped", + main-import-projections T Ty. + +pred main-import-projections i:term, i:term. +main-import-projections T Ty :- + std.assert! (coq.safe-dest-app Ty (global (indt I)) Args) "not an inductive term", + std.assert! (coq.env.record? I PrimProjs) "not a record", + coq.env.indt I _ _ NParams _ _ _, + std.assert! (std.length Args NParams) "the record is not fully appplied", + coq.env.projections I Ps, % get the projections generated by Coq + if (PrimProjs = tt) + (std.forall Ps (declare-abbrev {std.append {coq.mk-n-holes NParams} [T]})) + (std.forall Ps (declare-abbrev {std.append Args [T]})). + +pred declare-abbrev i:list term, i:option constant. +declare-abbrev _ none. +declare-abbrev Args (some Proj) :- + coq.gref->id (const Proj) ID, % get the short name of the projection + OnlyParsing = tt, + coq.mk-app (global (const Proj)) Args T, % handles the case Args = [] + @local! => coq.notation.add-abbreviation ID 0 T OnlyParsing _. +}}. +Elpi Typecheck. +Elpi Export import.projections. (* make the command available *) + +(**************************** usage examples *********************************) + +Record r T (t : T) := Build { + p1 : nat; + p2 : t = t; + _ : p2 = refl_equal; +}. + +Section test. +Variable x : r nat 3. +import.projections x. +Print p2. (* Notation p2 := (readme.p2 nat 3 x) *) +Check p1 : nat. (* check p1 is already applied to x *) +End test. + +Fail Check p1 : nat. (* the abbreviation is gone *) +Check p1 : forall (T : Type) (t : T), r T t -> nat. (* p1 points again to the original projection *) + +Module test. +import.projections (Build bool false 3 (refl_equal _) (refl_equal _)). +Check refl_equal _ : p1 = 3. (* check the value of p1 is 3 *) +End test. + +Set Primitive Projections. +Unset Auto Template Polymorphism. +Record r1 (A : Type) : Type := { + f1 : A; + f2 : nat; +}. + +Section test2. +Variable x : r1 bool. +import.projections x. +Unset Printing Primitive Projection Parameters. +Check f1. (* there is an _, hence it is the primitive projection *) +End test2. diff --git a/tests/example_record_expansion.t/run.t b/tests/example_record_expansion.t/run.t new file mode 100644 index 000000000..2f6ec5be5 --- /dev/null +++ b/tests/example_record_expansion.t/run.t @@ -0,0 +1,50 @@ + $ . ../setup-project.sh + $ dune build test.vo + f = + fun (b : bool) (t : r) => + let q := negb b in + fix rec (l1 l2 : list t) {struct l1} : bool := + match l1 with + | nil => match l2 with + | nil => b + | (_ :: _)%list => q + end + | (x :: xs)%list => + match l2 with + | nil => q + | (y :: ys)%list => (op t x y && rec xs ys)%bool + end + end + : bool -> forall t : r, list t -> list t -> bool + + Arguments f b%bool_scope t (l1 l2)%list_scope + expanded_f = + fun (b : bool) (T : Type) => + let X := T in + fun op : T -> X -> bool => + let q := negb b in + fix rec (l1 l2 : list T) {struct l1} : bool := + match l1 with + | nil => match l2 with + | nil => b + | (_ :: _)%list => q + end + | (x :: xs)%list => + match l2 with + | nil => q + | (y :: ys)%list => (op x y && rec xs ys)%bool + end + end + : bool -> forall T : Type, (T -> T -> bool) -> list T -> list T -> bool + + Arguments expanded_f b%bool_scope T%type_scope op%function_scope + (l1 l2)%list_scope + expanded_g = + fun T : Type => + let X := T in + fun (op : T -> X -> bool) (l s : list T) (h : bool) => + (forall (x : T) (y : X), op x y = false) /\ expanded_f true T op l s = h + : forall T : Type, (T -> T -> bool) -> list T -> list T -> bool -> Prop + + Arguments expanded_g T%type_scope op%function_scope + (l s)%list_scope h%bool_scope diff --git a/tests/example_record_expansion.t/test.v b/tests/example_record_expansion.t/test.v new file mode 100644 index 000000000..64e192b3b --- /dev/null +++ b/tests/example_record_expansion.t/test.v @@ -0,0 +1,203 @@ +From elpi Require Import elpi. + +(** + This file sketches a procedure to translate a term abstracted over + a specific record to a term abstracted over the components of that record. + + Example: + + Record r := mk { proj1 : T1; proj2 : T2 }. + Definition f (x : r) := Body(proj1 x,proj2 x). + + Is expanded to: + + Definition f1 v1 v2 := Body(v1,v2). + + And recursively, if g uses f, then g1 must use f1... + + The idea is to take "f", replace "(x : r)" with as many abstractions as + needed in order to write "mk v1 v2", then replace "x" with "mk v1 v2", finally + fire iota reductions such as "proj1 (mk v1 v2) = v1" to obtain "f1". + + Then record a global replacement "f x = f1 v2 v2" whenever "x = mk v1 v2". + +*) + +Elpi Db record.expand.db lp:{{ + % This data base will contain all the expansions performed previously. + % For example, if f was expandded to f1 we would have this clause: + + % copy (app[f, R | L]) (app[f1, V1, V2 | L1]) :- + % copy R (app[k, V1, V2]), std.map L copy L1. + +}}. + +Elpi Command record.expand. +Elpi Accumulate Db record.expand.db. +Elpi Accumulate lp:{{ + +% This builds a clause to replace "proji (k y1..yn)" by "yi" +pred build-iotared-clause i:term, i:(pair constant term), o:prop. +build-iotared-clause T (pr Proj Var) + (pi L AppVar\ copy(app [global (const Proj),T|L]) AppVar :- coq.mk-app Var L AppVar). + +% The core algorithm ---------------------------------------------------------- + +% It is idiomatic in λProlog to perform a single recursion over the data and +% perform multiple tasks while going. Here we both obtain the expanded term +% and the clause that records that expansion. Indeed the binders introduced +% in the new term (standing for the record fialds) and the quantifications +% introduced in the clause are very similar. + +% missing in std +pred cons_assoc_opt i:option A, i:B, i:list (pair A B), o:list (pair A B). +cons_assoc_opt none _ X X. +cons_assoc_opt (some A) B X [pr A B|X]. + +% a package of data that we need to carry but rarely fully access +kind info type. +type info + inductive % the record to expand + -> gref % the term being expanded + -> gref % the term being expanded and its expanded name + -> list (option constant) % canonical projections + -> constructor % record constructor + -> term % record constructor type + -> info. + +% This predicate turns the OldBo in "fun x : r => OldBo" into +% "fun v1 v2 => NewBo". It is fueled by "KTY" (corresponding to the type +% of the record constructor). In parallel it consumes the list of projections, +% so that it can record that the i-th projection should be replaced by +% the variable standing for the i-th record field (accumulator called Iota) +pred expand-abstraction + i:info, + i:term, % the varibale binding the record in the input term + + % fuel + i:term, % the type of the record constructor + i:list (option constant), % projections + + i:term, o:term, % the Old and New body + + i:term, % constructor applied to all arguments treated so far + i:list (pair constant term), % iota rules for reductions so far + + % used by expand-spine, accumulated here + i:list term, i:list term, % variables for the head of the clause (LHS and RHS) + i:list prop, o:prop. % accumulator for the premises of the clause, and the clause + +expand-abstraction Info Rec (prod N S F) [P|PS] OldBo (fun N S Bo) KArgs Iota AccL AccR Premises (pi x\ Clause x) :- + pi x\ + expand-abstraction Info Rec + (F x) PS OldBo (Bo x) {coq.mk-app KArgs [x]} {cons_assoc_opt P x Iota} AccL [x|AccR] Premises (Clause x). + +expand-abstraction Info Rec (let N S B F) [P|PS] OldBo (let N S B Bo) KArgs Iota AccL AccR Premises Clause :- + pi x\ % a let in is not a real argument to KArgs, but may need a "iota" redex, since the projection could exist + expand-abstraction Info Rec + (F x) PS OldBo (Bo x) KArgs {cons_assoc_opt P x Iota} AccL AccR Premises Clause. + +expand-abstraction Info Rec _ [] OldBo Result ExpandedRecord Iota AccL AccR Premises Clause :- + % generate all substitutions + std.map Iota (build-iotared-clause ExpandedRecord) IotaClauses, + ExpansionClause = copy Rec ExpandedRecord, + % eta expand the record to obtain a new body (that typechecks) + ExpansionClause => copy OldBo NewBo, + % continue, but schedule iota reductions (pre-existing projections became iota redexes) + IotaClauses => + expand-spine Info NewBo Result AccL AccR [ExpansionClause|Premises] Clause. + +% This predicate travrses the spine of lambdas. When it finds an abstraction +% on the record R is calls expand-abstraction. Finally it copies the term, +% applying all substitutions accumulated while descending the spine. +pred expand-spine + i:info, + i:term, o:term, % input and output term + i:list term, i:list term, % variables for the LHS and RHS of the clause head + i:list prop, o:prop. % premises and final clause + +% if we find a lambda over the record R we expand +expand-spine (info R _ _ Projs K KTY as Info) (fun _ (global (indt R)) Bo) Result AccL AccR Premises (pi r\ Clause r) :- !, + pi r\ expand-abstraction Info r KTY Projs (Bo r) Result (global (indc K)) [] [r|AccL] AccR Premises (Clause r). + +% otherwise we traverse the spine +expand-spine Info (fun Name Ty Bo) (fun Name Ty1 Bo1) AccL AccR Premises (pi x y\ Clause x y) :- !, + copy Ty Ty1, + pi x y\ copy x y => expand-spine Info (Bo x) (Bo1 y) [x|AccL] [y|AccR] [copy x y|Premises] (Clause x y). +expand-spine Info (let Name Ty V Bo) (let Name Ty1 V1 Bo1) AccL AccR Premises (pi x y\ Clause x y) :- !, + copy Ty Ty1, + copy V V1, + pi x y\ copy x y => expand-spine Info (Bo x) (Bo1 y) [x|AccL] [y|AccR] [copy x y|Premises] (Clause x y). + +% at the end of the spine we fire the iota redexes and complete the clause +expand-spine (info _ GR NGR _ _ _) X Y AccL AccR Premises Clause :- + copy X Y, + % we build "app[f,x1..xn|rest]" + (pi rest1\ coq.mk-app (global GR) {std.append {std.rev AccL} rest1} (L rest1)), + (pi rest2\ coq.mk-app (global NGR) {std.append {std.rev AccR} rest2} (R rest2)), + % we can now build the clause "copy (app[f,L1..Ln|Rest1]) (app[f1,R1..Rn|Rest2])" + % here we quantify only the tails, the other variables were quantified during + % expand-* + Clause = (pi rest1 rest2\ copy (L rest1) (R rest2) :- [!, std.map rest1 copy rest2 | Premises]). + +% The entry point of the main algorithm, just fetchs some data and passes initial +% values for the accumulators. +pred expand i:inductive, i:gref, i:gref, i:term, o:term, o:prop. +expand R GR NGR X Y Clause :- + std.assert! (coq.env.indt R tt 0 0 _ [K] [KTY]) "record is too complex for this example", + coq.env.projections R Projs, + expand-spine (info R GR NGR Projs K KTY) X Y [] [] [] Clause. + +% This simply dispatches between global references ---------------------------- + +% The only cleverness is that "expand" also builds the clause to be added to +% the data base, and that clause has to mention the name of the constant to be +% generated. Since we don't know it yet (Coq tells us in response to coq.env.add-const) +% we postulate a name for that constant "nc" and later replace it with the real one "NC" +pred expand-gref i:inductive, i:gref, i:string, o:prop. +expand-gref Record (const C) Name Clause :- !, + std.assert! (coq.env.const C (some Bo) _) "only transparent constants can be expanded", + (pi nc\ expand Record (const C) nc Bo NewBo (NClause nc)), + std.assert-ok! (coq.typecheck NewBo _) "illtyped", + coq.env.add-const Name NewBo _ _ NC, + Clause = NClause (const NC). + +expand-gref _ (indt _) _ _ :- coq.error "Not implemented yet". + +expand-gref _ (indc _) _ _ :- coq.error "It makes no sense to expand a constructor alone, expand the inductive instead". + +% Entry point ----------------------------------------------------------------- +main [str R, str In, str Prefix] :- !, + std.assert! (coq.locate R (indt Record)) "The first argument must be a record name", + std.assert! (coq.locate In GR) "The second argument must be a global term", + NewName is Prefix ^ {coq.gref->id GR}, + + expand-gref Record GR NewName Clause, + + % We want our clauses to take precensence over the structural ones of "copy" + coq.elpi.accumulate _ "record.expand.db" (clause _ (before "copy:start") Clause). + +main _ :- coq.error "usage: Elpi record.expand record_name global_term prefix". +}}. +Elpi Typecheck. + +Record r := { T :> Type; X := T; op : T -> X -> bool }. + +Definition f b (t : r) (q := negb b) := fix rec (l1 l2 : list t) := + match l1, l2 with + | nil, nil => b + | cons x xs, cons y ys => andb (op _ x y) (rec xs ys) + | _, _ => q + end. + +Elpi record.expand r f "expanded_". +Print f. +Print expanded_f. + +(* so that we can see the new "copy" clause *) +Elpi Print record.expand. + +Definition g t l s h := (forall x y, op t x y = false) /\ f true t l s = h. + +Elpi record.expand r g "expanded_". +Print expanded_g. diff --git a/tests/example_record_to_sigma.t/run.t b/tests/example_record_to_sigma.t/run.t new file mode 100644 index 000000000..83ec68397 --- /dev/null +++ b/tests/example_record_to_sigma.t/run.t @@ -0,0 +1,13 @@ + $ . ../setup-project.sh + $ dune build test.vo + foo = + {f1 : Type & {f2 : f1 -> Type & forall t : f1, f2 t -> bool}} + : Type + mk_foo = + fun (f1 : Type) (f2 : f1 -> Type) (f3 : forall t : f1, f2 t -> bool) => + existT (fun f4 : Type => {f5 : f4 -> Type & forall t : f4, f5 t -> bool}) f1 + (existT (fun f4 : f1 -> Type => forall t : f1, f4 t -> bool) f2 f3) + : forall (f1 : Type) (f2 : f1 -> Type), + (forall t : f1, f2 t -> bool) -> foo + + Arguments mk_foo f1%type_scope (f2 f3)%function_scope diff --git a/tests/example_record_to_sigma.t/test.v b/tests/example_record_to_sigma.t/test.v new file mode 100644 index 000000000..ac968ea9e --- /dev/null +++ b/tests/example_record_to_sigma.t/test.v @@ -0,0 +1,67 @@ +From elpi Require Import elpi. + +(* Define a command to turn records into nested sigma types, suggested + by M. Maggesi for the UniMath library *) +Elpi Command UM.expand. +Elpi Accumulate lp:{{ + +% From a record declaration to an iterated sigma type +pred wrap-fields-ty i:record-decl, o:term. +wrap-fields-ty (field _ _ Ty _\ end-record) Ty. +wrap-fields-ty (field _ Proj Ty Fields) {{ sigT lp:F }} :- + coq.string->name Proj Name, + F = fun Name Ty Bo, + pi x\ decl x Name Ty => wrap-fields-ty (Fields x) (Bo x). + +% From a record declaration to a function building the iterated pairs +% [wrap-fields-bo Rec Acc SigmaTypeDef SigmaTypeName Builder BuilderType] +% Builder = fun arg1 .. argn => existT arg1 (existT arg2 (.. argn) ..) +% Acc gathers arg1 .. argn while building the fun +% SigmaTypeDef is used to fill in the implicit arguments of existT +% SigmaTypeName is used for BuilderType = forall arg1 .. argn, SigmaTypeName +pred wrap-fields-bo i:record-decl, i:list term, i:term, i:term, o:term, o:term. +wrap-fields-bo end-record Acc SigTy Sig T Sig :- + std.rev Acc Args, + wrap-fields-bo.aux Args SigTy T. +wrap-fields-bo (field _ Proj Ty Fields) Acc SigTy Sig (fun Name Ty Bo) (prod Name Ty Tgt) :- + coq.string->name Proj Name, + pi x\ decl x Name Ty => wrap-fields-bo (Fields x) [x|Acc] SigTy Sig (Bo x) (Tgt x). + +wrap-fields-bo.aux [Last] _ Last. +wrap-fields-bo.aux [X|XS] {{ sigT lp:F }} {{ existT lp:F lp:X lp:Rest }} :- + F = fun _ _ G, + wrap-fields-bo.aux XS (G X) Rest. + +% We declare the type and its constructor. +% Missing features: +% - parameters are not supported +% - projections are not synthesized +main [indt-decl (record Name _Sort Kname Fields)] :- + wrap-fields-ty Fields T, + std.assert-ok! (coq.typecheck T Ty) "oops, wrap-fields-ty is bugged", + coq.env.add-const Name T Ty _ C, + wrap-fields-bo Fields [] T (global (const C)) K KTy, + std.assert-ok! (coq.typecheck K KTy) "oops, wrap-fields-bo is bugged", + coq.env.add-const Kname K KTy _ _. + +}}. +Elpi Typecheck. +Elpi Export UM.expand. + +(* From now on UM.expand is a regular command taking as the only argument + a record declaration. *) + +UM.expand Record foo := mk_foo { + f1 : Type; + f2 : f1 -> Type; + f3 : forall t : f1, f2 t -> bool +}. + +Print foo. +(* foo = {f1 : Type & {f2 : f1 -> Type & forall t : f1, f2 t -> bool}} : Type *) + +Print mk_foo. +(* mk_foo = fun (f1 : Type) (f2 : f1 -> Type) (f3 : forall t : f1, f2 t -> bool) => + existT (fun f4 : Type => {f5 : f4 -> Type & forall t : f4, f5 t -> bool}) f1 + (existT (fun f4 : f1 -> Type => forall t : f1, f4 t -> bool) f2 f3) + : forall (f1 : Type) (f2 : f1 -> Type), (forall t : f1, f2 t -> bool) -> foo *) diff --git a/tests/example_reduction_surgery.t/run.t b/tests/example_reduction_surgery.t/run.t new file mode 100644 index 000000000..331317cca --- /dev/null +++ b/tests/example_reduction_surgery.t/run.t @@ -0,0 +1,3 @@ + $ . ../setup-project.sh + $ dune build test.vo + (eq_refl : 2 = (let z := 1 in S z)) diff --git a/tests/example_reduction_surgery.t/test.v b/tests/example_reduction_surgery.t/test.v new file mode 100644 index 000000000..94ac3b0b6 --- /dev/null +++ b/tests/example_reduction_surgery.t/test.v @@ -0,0 +1,42 @@ +(** + This file mocks up a reduction tactic unfolding only constants + from a given module. +*) + +From elpi Require Import elpi. + +Elpi Tactic reduce. +Elpi Accumulate lp:{{ + +pred gref->redflag i:gref, o:coq.redflag. +gref->redflag (const C) (coq.redflags.const C). + +solve (goal _ _ Ty _ [str M] as G) GS :- + coq.locate-module M MP, + coq.env.module MP GREFS, + std.map-filter GREFS (x\r\x = gref r, r = (const _)) CONSTANTS, + std.map CONSTANTS (gr\r\ coq.env.transitive-dependencies gr _ r) DEPS, + std.fold DEPS {coq.gref.set.empty} coq.gref.set.union ALLDEPS, + std.append CONSTANTS {coq.gref.set.elements ALLDEPS} All, + std.map-filter All gref->redflag DELTAFLAGS, + coq.redflags.add coq.redflags.nored + [ coq.redflags.beta, coq.redflags.fix, coq.redflags.match | DELTAFLAGS ] + F, + @redflags! F => coq.reduction.cbv.norm Ty Ty1, + refine {{ _ : lp:Ty1 }} G GS. % to leave a vmcast one needs to call ltac1 + +}}. +Elpi Typecheck. + + +Module ToRed. +Definition x := 1. +Definition y := 1. +Definition alias := plus. +End ToRed. + +Goal ToRed.x + ToRed.y = let z := 1 in S z. +elpi reduce "ToRed". +match goal with |- 2 = let z := 1 in S z => trivial end. +Show Proof. +Abort. diff --git a/tests/example_reflexive_tactic.t/run.t b/tests/example_reflexive_tactic.t/run.t new file mode 100644 index 000000000..0f9702665 --- /dev/null +++ b/tests/example_reflexive_tactic.t/run.t @@ -0,0 +1,24 @@ + $ . ../setup-project.sh + $ dune build test.vo + normP : + forall {T : Type} {e : T} {op : T -> T -> T} {gamma : list T} {t1 t2 : lang}, + (forall a b c : T, op a (op b c) = op (op a b) c) -> + (forall a : T, op e a = a) -> + (forall a : T, op a e = a) -> + norm t1 = norm t2 -> interp T e op gamma t1 = interp T e op gamma t2 + + normP is not universe polymorphic + Arguments normP {T}%type_scope {e} {op}%function_scope + {gamma}%list_scope {t1 t2} (p1 p2 p3)%function_scope + H + normP is transparent + Expands to: Constant test.test.normP + (fun x y z t : Z => + normP Z.add_assoc Z.add_0_l Z.add_0_r + (eq_refl + <: + norm (add (add (var 0) (var 1)) (add (add (var 2) zero) (var 3))) = + norm (add (add (var 0) (add (var 1) (var 2))) (var 3)))) + Debug: In environment + x, y, z, t : Z + Unable to unify "var 1" with "var 0". diff --git a/tests/example_reflexive_tactic.t/test.v b/tests/example_reflexive_tactic.t/test.v new file mode 100644 index 000000000..b2ca18694 --- /dev/null +++ b/tests/example_reflexive_tactic.t/test.v @@ -0,0 +1,293 @@ + +(** + This file builds a reflexive tactic solving equalities in a monoid. + + We use elpi to: + - reify an expression into a syntax tree + - query a Db of known monoids + - call a few ltac primitives in order to apply the corrctness theorem + +*) + +From elpi Require elpi. +Require Arith ZArith Psatz List ssreflect. + +Import elpi. +Import Arith ZArith Psatz List ssreflect. + +(* This module contains the reflexive normalizer and its correctness proof *) +Module MonoidTheory. + +(* The syntax of terms *) +Inductive lang := +| var (i : nat) (* i-th variable in the context *) +| zero : lang (* Neutral element *) +| add (x y : lang). (* binary operation *) + +(* Interpretation to T *) +Fixpoint interp T (e : T) (op : T -> T -> T) (gamma : list T) (t : lang) : T := + match t with + | var v => nth v gamma e + | zero => e + | add x y => op (interp T e op gamma x) (interp T e op gamma y) + end. + + + (* normalization of parentheses and units *) + Fixpoint normAx t1 acc := + match t1 with + | add t1 t2 => normAx t1 (normAx t2 acc) + | _ => add t1 acc + end. + Fixpoint normA t := + match t with + | add s1 s2 => normAx s1 (normA s2) + | _ => t + end. + Fixpoint norm1 t := + match t with + | var _ => t + | zero => t + | add t1 t2 => + match norm1 t1 with + | zero => norm1 t2 + | t1 => + match norm1 t2 with + | zero => t1 + | t2 => add t1 t2 + end + end + end. + Definition norm t := normA (norm1 t). + + (* Correctness theorem. This is not the point of this demo, please don't + look at the proofs ;-) *) + Section assoc_reflection_proofs. + Variable T : Type. + Variable unit : T. + Variable op : T -> T -> T. + Hypothesis op_assoc : forall a b c, op a (op b c) = op (op a b) c. + Hypothesis unit_l : forall a, op unit a = a. + Hypothesis unit_r : forall a, op a unit = a. + +Lemma normAxA t1 t2 : normAx t1 (normA t2) = normA (add t1 t2). +Proof. by []. Qed. + +Lemma normAx_add {t1 t2 s} : normAx t1 t2 = s -> exists s1 s2, s = add s1 s2. +Proof. +elim: t1 t2 s => /= [i||w1 H1 w2 H2] t2 s <-; try by do 2 eexists; reflexivity. +by case E: (normAx _ _); case/H1: E => s1 [s2 ->]; do 2 eexists; reflexivity. +Qed. + +Lemma norm1_zero {l t} : norm1 t = zero -> interp T unit op l t = unit. +Proof. +by elim: t => [||s1 + s2] //=; case E1: (norm1 s1); case E2: (norm1 s2) => //= -> // ->. +Qed. + +Lemma norm_zero {l t} : norm t = zero -> interp T unit op l t = unit. +Proof. +rewrite /norm; case E: (norm1 t) => [||x y] //; first by rewrite (norm1_zero E). +by move/normAx_add=> [] ? []. +Qed. + +Lemma norm1_var {l t j} : norm1 t = var j -> interp T unit op l t = nth j l unit. +Proof. +elim: t => [i [->]||s1 + s2] //=; case E1: (norm1 s1); case E2: (norm1 s2) => //=. + by rewrite (norm1_zero E2) unit_r => + _ H => ->. +by rewrite (norm1_zero E1) unit_l => _ + H => ->. +Qed. + +Lemma norm_var {l t j} : norm t = var j -> interp T unit op l t = nth j l unit. +Proof. +rewrite /norm; case E: (norm1 t); rewrite /= ?(norm1_var E) //; first by move=> [->]. +by move/normAx_add=> [] ? []. +Qed. + +Lemma norm1_add {l t s1 s2} : norm1 t = add s1 s2 -> interp T unit op l t = op (interp T unit op l s1) (interp T unit op l s2). +Proof. +elim: t s1 s2 => [||w1 + w2 + s1 s2] //=. +by case E1: (norm1 w1); case E2: (norm1 w2) => //= ++ [<- <-] /=; + do 2! [ move=> /(_ _ _ (refl_equal _)) -> | move=> _]; + rewrite ?(norm1_zero E1) ?(norm1_zero E2) ?(norm1_var E1) ?(norm1_var E2). +Qed. + +Lemma normAxP {l t1 t2} : interp T unit op l (normAx t1 t2) = op (interp T unit op l t1) (interp T unit op l t2). +Proof. by elim: t1 t2 => [||s1 Hs1 s2 Hs2] t2 //=; rewrite Hs1 Hs2 !op_assoc. Qed. + +Lemma normAP {l} t : interp T unit op l (normA t) = interp T unit op l t. +Proof. by elim: t => //= x Hx y Hy; rewrite normAxP Hy. Qed. + +Lemma norm_add {l t s1 s2} : norm t = add s1 s2 -> interp T unit op l t = op (interp T unit op l s1) (interp T unit op l s2). +Proof. +rewrite /norm; case E: (norm1 t) => [||x y]; rewrite //= (norm1_add E). +elim: x y s1 s2 {E} => //= [>[<- <- //=]|>[<- <-]|x + y + w s1 s2]; rewrite ?normAP //= ?unit_l //. +by rewrite normAxA -!op_assoc => ++ E => /(_ _ _ _ E) ->. +Qed. + +Lemma normP_ l t1 t2 : norm t1 = norm t2 -> interp T unit op l t1 = interp T unit op l t2. +Proof. +case E: (norm t2) => [?||??] => [/norm_var|/norm_zero|/norm_add] ->. + by rewrite (norm_var E). + by rewrite (norm_zero E). +by rewrite (norm_add E). +Qed. + +End assoc_reflection_proofs. +End MonoidTheory. + + + +(* Finally, let's build the tactic *) + +Import MonoidTheory. + +(* This is the correctness theorem of our normalizer *) +Definition normP {T e op gamma t1 t2} p1 p2 p3 H := @normP_ T e op p1 p2 p3 gamma t1 t2 H. +About normP. +Open Scope Z_scope. + +Goal forall x y z t, (x + y) + (z + 0 + t) = x + (y + z) + t. +Proof. +intros. + +change (interp Z Z.zero Z.add (x::y::z::t::nil) + (add (add (var 0) (var 1)) (add (add (var 2) zero) (var 3))) + = + interp Z Z.zero Z.add (x::y::z::t::nil) + (add (add (var 0) (add (var 1) (var 2))) (var 3))). + +apply: normP Z.add_assoc Z.add_0_l Z.add_0_r _. + +reflexivity. +Qed. + +(** Now, let's implement a tactic that does for us: + - the change step (reification) + - apply the correctness lemma +*) + +(* This is for later *) +Elpi Db monoid.db lp:{{ + pred is_monoid + i:term, % type + o:term, % zero + o:term, % op + o:term, % assoc + o:term, % unit_l + o:term. % unit_r +}}. + +Elpi Tactic monoid. +Elpi Accumulate Db monoid.db. +Elpi Accumulate lp:{{ + +% [mem L X N] asserts that X is at position N in L. +% The list is open-ended, that is it terminates with an Elpi unification +% variable, so that the list can be extended with new elements if needed. +% e.g. mem (3 :: L) 4 N ---> L = 4 :: L1, N = 1 +% Note: we build a Coq list, since we have to generate that anyway. We could +% use an Elpi list or any other data structure here, but then we would need +% to convert back anyway. +pred mem o:term, o:term, o:term. +mem {{ lp:X :: _ }} X {{ O }} :- !. +mem {{ _ :: lp:XS }} X {{ S lp:N }} :- mem XS X N. + +% Give that [mem] works with open ended lists we need a way to close it (assign +% nil to the tail) at the very end of reification. +pred close o:term. +close {{ nil }} :- !. +close {{ _ :: lp:XS }} :- close XS. + +% [quote Zero Op T AstT L] recognizes Zero and Op in T and generates the +% corresponding AstT using the "context" L for variables standing for +% terms that are not Zero nor Op +pred quote i:term, i:term, i:term, o:term, o:term. +quote Zero Op {{ lp:Op lp:T1 lp:T2 }} {{ add lp:R1 lp:R2 }} L :- !, + quote Zero Op T1 R1 L, + quote Zero Op T2 R2 L. +quote Zero _ Zero {{ zero }} _ :- !. +quote _ _ T {{ var lp:R }} L :- mem L T R. + +% This preliminary version of the tactic takes as arguments the monoid signature +% and changes the goal [A = B] into [interp L AstA = interp L AstB] +solve (goal _ _ {{ @eq lp:T lp:A lp:B }} _ [trm Zero, trm Op] as G) GS :- + quote Zero Op A AstA L, + quote Zero Op B AstB L, + close L, + % We are very low level here, we assign a term directly to the goal handler + % while one could use ltac primitives (as we do later) + Ty = {{ (interp lp:T lp:Zero lp:Op lp:L lp:AstA) + = (interp lp:T lp:Zero lp:Op lp:L lp:AstB) }}, + % This implements the "change" tactic + refine {{ (_ : lp:Ty) }} G GS. + +:name "error" +solve _ _ :- coq.error "Not an equality / no signature provided". + +}}. +Elpi Typecheck. +Tactic Notation "monoid" constr(zero) constr(add) := elpi monoid (zero) (add). + +(** Let's test the tactic *) +Goal forall x y z t, (x + y) + (z + 0 + t) = x + (y + z) + t. +Proof. + intros. + monoid 0 Z.add. + (* OK, the goal was reified for us, we can use normP now *) + apply: normP Z.add_assoc Z.add_0_l Z.add_0_r _. + reflexivity. +Qed. + +(** Now let's register in the Db the monoid for Z *) +Elpi Accumulate monoid.db lp:{{ + + is_monoid {{ Z }} + {{ 0 }} {{ Z.add }} + {{ Z.add_assoc }} {{ Z.add_0_l }} {{ Z.add_0_r }}. + +}}. + +(** Now let's improve the tactic. This time we don't expect the signature but + rather look it up in the Db. *) +Ltac my_compute := vm_compute. + +Elpi Accumulate monoid lp:{{ + +:before "error" +solve (goal _ _ {{ @eq lp:T lp:A lp:B }} _ [] as G) GL :- + is_monoid T Zero Op Assoc Ul Ur, + quote Zero Op A AstA L, + quote Zero Op B AstB L, + close L, + % This time we use higher level combinators, closer to the standard ltac1 ones + refine {{ @normP lp:T lp:Zero lp:Op lp:L lp:AstA lp:AstB lp:Assoc lp:Ul lp:Ur _ }} G [SubG], + coq.ltac.thenl [ + coq.ltac "my_compute", % https://github.com/coq/coq/issues/10769 + coq.ltac "reflexivity", + ] SubG GL. + +}}. +Elpi Typecheck. +Tactic Notation "monoid" := elpi monoid. + +(** Let's test it once more *) +Goal forall x y z t, (x + y) + (z + 0 + t) = x + (y + z) + t. +Proof. + intros. + monoid. + Show Proof. +Qed. + +Elpi Accumulate monoid.db lp:{{ + + is_monoid {{ Z }} + {{ 1 }} {{ Z.mul }} + {{ Z.mul_assoc }} {{ Z.mul_1_l }} {{ Z.mul_1_r }}. + +}}. + +Goal forall x y z t, (x * y) * (1 * (z + t)) = x * y * (z + t). +Proof. + intros. + monoid. +Qed. diff --git a/tests/glob.t/run.t b/tests/glob.t/run.t new file mode 100644 index 000000000..fb7b2ad33 --- /dev/null +++ b/tests/glob.t/run.t @@ -0,0 +1,22 @@ + $ . ../setup-project.sh + $ dune build test.vo + d1 + : nat + d2 + : nat + i1 + : Prop + i2 + : Prop + k1 + : i1 + k2 + : i2 + r1 + : Set + r2 + : Type + f1 + : r1 -> nat + f2 + : r2 -> nat diff --git a/tests/test_glob.v b/tests/glob.t/test.v similarity index 100% rename from tests/test_glob.v rename to tests/glob.t/test.v diff --git a/tests/libobject_A.t/run.t b/tests/libobject_A.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/libobject_A.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_libobject_A.v b/tests/libobject_A.t/test.v similarity index 100% rename from tests/test_libobject_A.v rename to tests/libobject_A.t/test.v diff --git a/tests/libobject_B.t/run.t b/tests/libobject_B.t/run.t new file mode 100644 index 000000000..f78a834a1 --- /dev/null +++ b/tests/libobject_B.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_libobject_A is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 3, characters 0-48: + Error: Cannot find a physical path bound to logical path + test_libobject_A with prefix elpi.tests. + + [1] diff --git a/tests/test_libobject_B.v b/tests/libobject_B.t/test.v similarity index 100% rename from tests/test_libobject_B.v rename to tests/libobject_B.t/test.v diff --git a/tests/libobject_C.t/run.t b/tests/libobject_C.t/run.t new file mode 100644 index 000000000..2c8aa4c18 --- /dev/null +++ b/tests/libobject_C.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_libobject_B is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-48: + Error: Cannot find a physical path bound to logical path + test_libobject_B with prefix elpi.tests. + + [1] diff --git a/tests/test_libobject_C.v b/tests/libobject_C.t/test.v similarity index 100% rename from tests/test_libobject_C.v rename to tests/libobject_C.t/test.v diff --git a/tests/link_order1.t/run.t b/tests/link_order1.t/run.t new file mode 100644 index 000000000..6c01b039a --- /dev/null +++ b/tests/link_order1.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 27, characters 0-40: + Error: System error: "tests/test_link_order1.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order1.v b/tests/link_order1.t/test.v similarity index 100% rename from tests/test_link_order1.v rename to tests/link_order1.t/test.v diff --git a/tests/link_order2.t/run.t b/tests/link_order2.t/run.t new file mode 100644 index 000000000..7fb13eb09 --- /dev/null +++ b/tests/link_order2.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 27, characters 0-40: + Error: System error: "tests/test_link_order2.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order2.v b/tests/link_order2.t/test.v similarity index 100% rename from tests/test_link_order2.v rename to tests/link_order2.t/test.v diff --git a/tests/link_order3.t/run.t b/tests/link_order3.t/run.t new file mode 100644 index 000000000..05835bded --- /dev/null +++ b/tests/link_order3.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 27, characters 0-40: + Error: System error: "tests/test_link_order3.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order3.v b/tests/link_order3.t/test.v similarity index 100% rename from tests/test_link_order3.v rename to tests/link_order3.t/test.v diff --git a/tests/link_order4.t/run.t b/tests/link_order4.t/run.t new file mode 100644 index 000000000..218b09639 --- /dev/null +++ b/tests/link_order4.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 27, characters 0-40: + Error: System error: "tests/test_link_order4.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order4.v b/tests/link_order4.t/test.v similarity index 100% rename from tests/test_link_order4.v rename to tests/link_order4.t/test.v diff --git a/tests/link_order5.t/run.t b/tests/link_order5.t/run.t new file mode 100644 index 000000000..a65b75b97 --- /dev/null +++ b/tests/link_order5.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 28, characters 0-40: + Error: System error: "tests/test_link_order5.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order5.v b/tests/link_order5.t/test.v similarity index 100% rename from tests/test_link_order5.v rename to tests/link_order5.t/test.v diff --git a/tests/link_order6.t/run.t b/tests/link_order6.t/run.t new file mode 100644 index 000000000..b651002fd --- /dev/null +++ b/tests/link_order6.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 28, characters 0-40: + Error: System error: "tests/test_link_order6.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order6.v b/tests/link_order6.t/test.v similarity index 100% rename from tests/test_link_order6.v rename to tests/link_order6.t/test.v diff --git a/tests/link_order7.t/run.t b/tests/link_order7.t/run.t new file mode 100644 index 000000000..f05856e9a --- /dev/null +++ b/tests/link_order7.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 28, characters 0-40: + Error: System error: "tests/test_link_order7.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order7.v b/tests/link_order7.t/test.v similarity index 100% rename from tests/test_link_order7.v rename to tests/link_order7.t/test.v diff --git a/tests/link_order8.t/run.t b/tests/link_order8.t/run.t new file mode 100644 index 000000000..107b0ac3c --- /dev/null +++ b/tests/link_order8.t/run.t @@ -0,0 +1,6 @@ + $ . ../setup-project.sh + $ dune build test.vo + File "./test.v", line 28, characters 0-40: + Error: System error: "tests/test_link_order8.txt: No such file or directory" + + [1] diff --git a/tests/test_link_order8.v b/tests/link_order8.t/test.v similarity index 100% rename from tests/test_link_order8.v rename to tests/link_order8.t/test.v diff --git a/tests/link_order9.t/run.t b/tests/link_order9.t/run.t new file mode 100644 index 000000000..45012fbfb --- /dev/null +++ b/tests/link_order9.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_link_order1 is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 2, characters 0-48: + Error: Cannot find a physical path bound to logical path + test_link_order1 with prefix elpi.tests. + + [1] diff --git a/tests/test_link_order9.v b/tests/link_order9.t/test.v similarity index 100% rename from tests/test_link_order9.v rename to tests/link_order9.t/test.v diff --git a/tests/link_order_import0.t/run.t b/tests/link_order_import0.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/link_order_import0.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_link_order_import0.v b/tests/link_order_import0.t/test.v similarity index 100% rename from tests/test_link_order_import0.v rename to tests/link_order_import0.t/test.v diff --git a/tests/link_order_import1.t/run.t b/tests/link_order_import1.t/run.t new file mode 100644 index 000000000..31fa547b2 --- /dev/null +++ b/tests/link_order_import1.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_link_order_import0 is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-55: + Error: Cannot find a physical path bound to logical path + test_link_order_import0 with prefix elpi.tests. + + [1] diff --git a/tests/test_link_order_import1.v b/tests/link_order_import1.t/test.v similarity index 100% rename from tests/test_link_order_import1.v rename to tests/link_order_import1.t/test.v diff --git a/tests/link_order_import2.t/run.t b/tests/link_order_import2.t/run.t new file mode 100644 index 000000000..31fa547b2 --- /dev/null +++ b/tests/link_order_import2.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_link_order_import0 is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-55: + Error: Cannot find a physical path bound to logical path + test_link_order_import0 with prefix elpi.tests. + + [1] diff --git a/tests/test_link_order_import2.v b/tests/link_order_import2.t/test.v similarity index 100% rename from tests/test_link_order_import2.v rename to tests/link_order_import2.t/test.v diff --git a/tests/link_order_import3.t/run.t b/tests/link_order_import3.t/run.t new file mode 100644 index 000000000..e7e457935 --- /dev/null +++ b/tests/link_order_import3.t/run.t @@ -0,0 +1,13 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_link_order_import2 is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + Warning: in file test.v, library test_link_order_import1 is required + from root elpi.tests and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-79: + Error: Cannot find a physical path bound to logical path + test_link_order_import2 with prefix elpi.tests. + + [1] diff --git a/tests/test_link_order_import3.v b/tests/link_order_import3.t/test.v similarity index 100% rename from tests/test_link_order_import3.v rename to tests/link_order_import3.t/test.v diff --git a/tests/link_perf.t/run.t b/tests/link_perf.t/run.t new file mode 100644 index 000000000..00921d382 --- /dev/null +++ b/tests/link_perf.t/run.t @@ -0,0 +1,402 @@ + $ . ../setup-project.sh + $ dune build test.vo + [p 1, p 2, p 3, p 4, p 5, p 6, p 7, p 8, p 9, p 10, p 11, p 12, p 13, + p 14, p 15, p 16, p 17, p 18, p 19, p 20, p 21, p 22, p 23, p 24, p 25, + p 26, p 27, p 28, p 29, p 30, p 31, p 32, p 33, p 34, p 35, p 36, p 37, + p 38, p 39, p 40, p 41, p 42, p 43, p 44, p 45, p 46, p 47, p 48, p 49, + p 50, p 51, p 52, p 53, p 54, p 55, p 56, p 57, p 58, p 59, p 60, p 61, + p 62, p 63, p 64, p 65, p 66, p 67, p 68, p 69, p 70, p 71, p 72, p 73, + p 74, p 75, p 76, p 77, p 78, p 79, p 80, p 81, p 82, p 83, p 84, p 85, + p 86, p 87, p 88, p 89, p 90, p 91, p 92, p 93, p 94, p 95, p 96, p 97, + p 98, p 99, p 100, p 101, p 102, p 103, p 104, p 105, p 106, p 107, + p 108, p 109, p 110, p 111, p 112, p 113, p 114, p 115, p 116, p 117, + p 118, p 119, p 120, p 121, p 122, p 123, p 124, p 125, p 126, p 127, + p 128, p 129, p 130, p 131, p 132, p 133, p 134, p 135, p 136, p 137, + p 138, p 139, p 140, p 141, p 142, p 143, p 144, p 145, p 146, p 147, + p 148, p 149, p 150, p 151, p 152, p 153, p 154, p 155, p 156, p 157, + p 158, p 159, p 160, p 161, p 162, p 163, p 164, p 165, p 166, p 167, + p 168, p 169, p 170, p 171, p 172, p 173, p 174, p 175, p 176, p 177, + p 178, p 179, p 180, p 181, p 182, p 183, p 184, p 185, p 186, p 187, + p 188, p 189, p 190, p 191, p 192, p 193, p 194, p 195, p 196, p 197, + p 198, p 199, p 200, p 201, p 202, p 203, p 204, p 205, p 206, p 207, + p 208, p 209, p 210, p 211, p 212, p 213, p 214, p 215, p 216, p 217, + p 218, p 219, p 220, p 221, p 222, p 223, p 224, p 225, p 226, p 227, + p 228, p 229, p 230, p 231, p 232, p 233, p 234, p 235, p 236, p 237, + p 238, p 239, p 240, p 241, p 242, p 243, p 244, p 245, p 246, p 247, + p 248, p 249, p 250, p 251, p 252, p 253, p 254, p 255, p 256, p 257, + p 258, p 259, p 260, p 261, p 262, p 263, p 264, p 265, p 266, p 267, + p 268, p 269, p 270, p 271, p 272, p 273, p 274, p 275, p 276, p 277, + p 278, p 279, p 280, p 281, p 282, p 283, p 284, p 285, p 286, p 287, + p 288, p 289, p 290, p 291, p 292, p 293, p 294, p 295, p 296, p 297, + p 298, p 299, p 300, p 301, p 302, p 303, p 304, p 305, p 306, p 307, + p 308, p 309, p 310, p 311, p 312, p 313, p 314, p 315, p 316, p 317, + p 318, p 319, p 320, p 321, p 322, p 323, p 324, p 325, p 326, p 327, + p 328, p 329, p 330, p 331, p 332, p 333, p 334, p 335, p 336, p 337, + p 338, p 339, p 340, p 341, p 342, p 343, p 344, p 345, p 346, p 347, + p 348, p 349, p 350, p 351, p 352, p 353, p 354, p 355, p 356, p 357, + p 358, p 359, p 360, p 361, p 362, p 363, p 364, p 365, p 366, p 367, + p 368, p 369, p 370, p 371, p 372, p 373, p 374, p 375, p 376, p 377, + p 378, p 379, p 380, p 381, p 382, p 383, p 384, p 385, p 386, p 387, + p 388, p 389, p 390, p 391, p 392, p 393, p 394, p 395, p 396, p 397, + p 398, p 399, p 400, p 401, p 402, p 403, p 404, p 405, p 406, p 407, + p 408, p 409, p 410, p 411, p 412, p 413, p 414, p 415, p 416, p 417, + p 418, p 419, p 420, p 421, p 422, p 423, p 424, p 425, p 426, p 427, + p 428, p 429, p 430, p 431, p 432, p 433, p 434, p 435, p 436, p 437, + p 438, p 439, p 440, p 441, p 442, p 443, p 444, p 445, p 446, p 447, + p 448, p 449, p 450, p 451, p 452, p 453, p 454, p 455, p 456, p 457, + p 458, p 459, p 460, p 461, p 462, p 463, p 464, p 465, p 466, p 467, + p 468, p 469, p 470, p 471, p 472, p 473, p 474, p 475, p 476, p 477, + p 478, p 479, p 480, p 481, p 482, p 483, p 484, p 485, p 486, p 487, + p 488, p 489, p 490, p 491, p 492, p 493, p 494, p 495, p 496, p 497, + p 498, p 499, p 500, p 501, p 502, p 503, p 504, p 505, p 506, p 507, + p 508, p 509, p 510, p 511, p 512, p 513, p 514, p 515, p 516, p 517, + p 518, p 519, p 520, p 521, p 522, p 523, p 524, p 525, p 526, p 527, + p 528, p 529, p 530, p 531, p 532, p 533, p 534, p 535, p 536, p 537, + p 538, p 539, p 540, p 541, p 542, p 543, p 544, p 545, p 546, p 547, + p 548, p 549, p 550, p 551, p 552, p 553, p 554, p 555, p 556, p 557, + p 558, p 559, p 560, p 561, p 562, p 563, p 564, p 565, p 566, p 567, + p 568, p 569, p 570, p 571, p 572, p 573, p 574, p 575, p 576, p 577, + p 578, p 579, p 580, p 581, p 582, p 583, p 584, p 585, p 586, p 587, + p 588, p 589, p 590, p 591, p 592, p 593, p 594, p 595, p 596, p 597, + p 598, p 599, p 600, p 601, p 602, p 603, p 604, p 605, p 606, p 607, + p 608, p 609, p 610, p 611, p 612, p 613, p 614, p 615, p 616, p 617, + p 618, p 619, p 620, p 621, p 622, p 623, p 624, p 625, p 626, p 627, + p 628, p 629, p 630, p 631, p 632, p 633, p 634, p 635, p 636, p 637, + p 638, p 639, p 640, p 641, p 642, p 643, p 644, p 645, p 646, p 647, + p 648, p 649, p 650, p 651, p 652, p 653, p 654, p 655, p 656, p 657, + p 658, p 659, p 660, p 661, p 662, p 663, p 664, p 665, p 666, p 667, + p 668, p 669, p 670, p 671, p 672, p 673, p 674, p 675, p 676, p 677, + p 678, p 679, p 680, p 681, p 682, p 683, p 684, p 685, p 686, p 687, + p 688, p 689, p 690, p 691, p 692, p 693, p 694, p 695, p 696, p 697, + p 698, p 699, p 700, p 701, p 702, p 703, p 704, p 705, p 706, p 707, + p 708, p 709, p 710, p 711, p 712, p 713, p 714, p 715, p 716, p 717, + p 718, p 719, p 720, p 721, p 722, p 723, p 724, p 725, p 726, p 727, + p 728, p 729, p 730, p 731, p 732, p 733, p 734, p 735, p 736, p 737, + p 738, p 739, p 740, p 741, p 742, p 743, p 744, p 745, p 746, p 747, + p 748, p 749, p 750, p 751, p 752, p 753, p 754, p 755, p 756, p 757, + p 758, p 759, p 760, p 761, p 762, p 763, p 764, p 765, p 766, p 767, + p 768, p 769, p 770, p 771, p 772, p 773, p 774, p 775, p 776, p 777, + p 778, p 779, p 780, p 781, p 782, p 783, p 784, p 785, p 786, p 787, + p 788, p 789, p 790, p 791, p 792, p 793, p 794, p 795, p 796, p 797, + p 798, p 799, p 800, p 801, p 802, p 803, p 804, p 805, p 806, p 807, + p 808, p 809, p 810, p 811, p 812, p 813, p 814, p 815, p 816, p 817, + p 818, p 819, p 820, p 821, p 822, p 823, p 824, p 825, p 826, p 827, + p 828, p 829, p 830, p 831, p 832, p 833, p 834, p 835, p 836, p 837, + p 838, p 839, p 840, p 841, p 842, p 843, p 844, p 845, p 846, p 847, + p 848, p 849, p 850, p 851, p 852, p 853, p 854, p 855, p 856, p 857, + p 858, p 859, p 860, p 861, p 862, p 863, p 864, p 865, p 866, p 867, + p 868, p 869, p 870, p 871, p 872, p 873, p 874, p 875, p 876, p 877, + p 878, p 879, p 880, p 881, p 882, p 883, p 884, p 885, p 886, p 887, + p 888, p 889, p 890, p 891, p 892, p 893, p 894, p 895, p 896, p 897, + p 898, p 899, p 900, p 901, p 902, p 903, p 904, p 905, p 906, p 907, + p 908, p 909, p 910, p 911, p 912, p 913, p 914, p 915, p 916, p 917, + p 918, p 919, p 920, p 921, p 922, p 923, p 924, p 925, p 926, p 927, + p 928, p 929, p 930, p 931, p 932, p 933, p 934, p 935, p 936, p 937, + p 938, p 939, p 940, p 941, p 942, p 943, p 944, p 945, p 946, p 947, + p 948, p 949, p 950, p 951, p 952, p 953, p 954, p 955, p 956, p 957, + p 958, p 959, p 960, p 961, p 962, p 963, p 964, p 965, p 966, p 967, + p 968, p 969, p 970, p 971, p 972, p 973, p 974, p 975, p 976, p 977, + p 978, p 979, p 980, p 981, p 982, p 983, p 984, p 985, p 986, p 987, + p 988, p 989, p 990, p 991, p 992, p 993, p 994, p 995, p 996, p 997, + p 998, p 999, p 1000, p 1001, p 1002, p 1003, p 1004, p 1005, p 1006, + p 1007, p 1008, p 1009, p 1010, p 1011, p 1012, p 1013, p 1014, p 1015, + p 1016, p 1017, p 1018, p 1019, p 1020, p 1021, p 1022, p 1023, p 1024, + p 1025, p 1026, p 1027, p 1028, p 1029, p 1030, p 1031, p 1032, p 1033, + p 1034, p 1035, p 1036, p 1037, p 1038, p 1039, p 1040, p 1041, p 1042, + p 1043, p 1044, p 1045, p 1046, p 1047, p 1048, p 1049, p 1050, p 1051, + p 1052, p 1053, p 1054, p 1055, p 1056, p 1057, p 1058, p 1059, p 1060, + p 1061, p 1062, p 1063, p 1064, p 1065, p 1066, p 1067, p 1068, p 1069, + p 1070, p 1071, p 1072, p 1073, p 1074, p 1075, p 1076, p 1077, p 1078, + p 1079, p 1080, p 1081, p 1082, p 1083, p 1084, p 1085, p 1086, p 1087, + p 1088, p 1089, p 1090, p 1091, p 1092, p 1093, p 1094, p 1095, p 1096, + p 1097, p 1098, p 1099, p 1100, p 1101, p 1102, p 1103, p 1104, p 1105, + p 1106, p 1107, p 1108, p 1109, p 1110, p 1111, p 1112, p 1113, p 1114, + p 1115, p 1116, p 1117, p 1118, p 1119, p 1120, p 1121, p 1122, p 1123, + p 1124, p 1125, p 1126, p 1127, p 1128, p 1129, p 1130, p 1131, p 1132, + p 1133, p 1134, p 1135, p 1136, p 1137, p 1138, p 1139, p 1140, p 1141, + p 1142, p 1143, p 1144, p 1145, p 1146, p 1147, p 1148, p 1149, p 1150, + p 1151, p 1152, p 1153, p 1154, p 1155, p 1156, p 1157, p 1158, p 1159, + p 1160, p 1161, p 1162, p 1163, p 1164, p 1165, p 1166, p 1167, p 1168, + p 1169, p 1170, p 1171, p 1172, p 1173, p 1174, p 1175, p 1176, p 1177, + p 1178, p 1179, p 1180, p 1181, p 1182, p 1183, p 1184, p 1185, p 1186, + p 1187, p 1188, p 1189, p 1190, p 1191, p 1192, p 1193, p 1194, p 1195, + p 1196, p 1197, p 1198, p 1199, p 1200, p 1201, p 1202, p 1203, p 1204, + p 1205, p 1206, p 1207, p 1208, p 1209, p 1210, p 1211, p 1212, p 1213, + p 1214, p 1215, p 1216, p 1217, p 1218, p 1219, p 1220, p 1221, p 1222, + p 1223, p 1224, p 1225, p 1226, p 1227, p 1228, p 1229, p 1230, p 1231, + p 1232, p 1233, p 1234, p 1235, p 1236, p 1237, p 1238, p 1239, p 1240, + p 1241, p 1242, p 1243, p 1244, p 1245, p 1246, p 1247, p 1248, p 1249, + p 1250, p 1251, p 1252, p 1253, p 1254, p 1255, p 1256, p 1257, p 1258, + p 1259, p 1260, p 1261, p 1262, p 1263, p 1264, p 1265, p 1266, p 1267, + p 1268, p 1269, p 1270, p 1271, p 1272, p 1273, p 1274, p 1275, p 1276, + p 1277, p 1278, p 1279, p 1280, p 1281, p 1282, p 1283, p 1284, p 1285, + p 1286, p 1287, p 1288, p 1289, p 1290, p 1291, p 1292, p 1293, p 1294, + p 1295, p 1296, p 1297, p 1298, p 1299, p 1300, p 1301, p 1302, p 1303, + p 1304, p 1305, p 1306, p 1307, p 1308, p 1309, p 1310, p 1311, p 1312, + p 1313, p 1314, p 1315, p 1316, p 1317, p 1318, p 1319, p 1320, p 1321, + p 1322, p 1323, p 1324, p 1325, p 1326, p 1327, p 1328, p 1329, p 1330, + p 1331, p 1332, p 1333, p 1334, p 1335, p 1336, p 1337, p 1338, p 1339, + p 1340, p 1341, p 1342, p 1343, p 1344, p 1345, p 1346, p 1347, p 1348, + p 1349, p 1350, p 1351, p 1352, p 1353, p 1354, p 1355, p 1356, p 1357, + p 1358, p 1359, p 1360, p 1361, p 1362, p 1363, p 1364, p 1365, p 1366, + p 1367, p 1368, p 1369, p 1370, p 1371, p 1372, p 1373, p 1374, p 1375, + p 1376, p 1377, p 1378, p 1379, p 1380, p 1381, p 1382, p 1383, p 1384, + p 1385, p 1386, p 1387, p 1388, p 1389, p 1390, p 1391, p 1392, p 1393, + p 1394, p 1395, p 1396, p 1397, p 1398, p 1399, p 1400, p 1401, p 1402, + p 1403, p 1404, p 1405, p 1406, p 1407, p 1408, p 1409, p 1410, p 1411, + p 1412, p 1413, p 1414, p 1415, p 1416, p 1417, p 1418, p 1419, p 1420, + p 1421, p 1422, p 1423, p 1424, p 1425, p 1426, p 1427, p 1428, p 1429, + p 1430, p 1431, p 1432, p 1433, p 1434, p 1435, p 1436, p 1437, p 1438, + p 1439, p 1440, p 1441, p 1442, p 1443, p 1444, p 1445, p 1446, p 1447, + p 1448, p 1449, p 1450, p 1451, p 1452, p 1453, p 1454, p 1455, p 1456, + p 1457, p 1458, p 1459, p 1460, p 1461, p 1462, p 1463, p 1464, p 1465, + p 1466, p 1467, p 1468, p 1469, p 1470, p 1471, p 1472, p 1473, p 1474, + p 1475, p 1476, p 1477, p 1478, p 1479, p 1480, p 1481, p 1482, p 1483, + p 1484, p 1485, p 1486, p 1487, p 1488, p 1489, p 1490, p 1491, p 1492, + p 1493, p 1494, p 1495, p 1496, p 1497, p 1498, p 1499, p 1500, p 1501, + p 1502, p 1503, p 1504, p 1505, p 1506, p 1507, p 1508, p 1509, p 1510, + p 1511, p 1512, p 1513, p 1514, p 1515, p 1516, p 1517, p 1518, p 1519, + p 1520, p 1521, p 1522, p 1523, p 1524, p 1525, p 1526, p 1527, p 1528, + p 1529, p 1530, p 1531, p 1532, p 1533, p 1534, p 1535, p 1536, p 1537, + p 1538, p 1539, p 1540, p 1541, p 1542, p 1543, p 1544, p 1545, p 1546, + p 1547, p 1548, p 1549, p 1550, p 1551, p 1552, p 1553, p 1554, p 1555, + p 1556, p 1557, p 1558, p 1559, p 1560, p 1561, p 1562, p 1563, p 1564, + p 1565, p 1566, p 1567, p 1568, p 1569, p 1570, p 1571, p 1572, p 1573, + p 1574, p 1575, p 1576, p 1577, p 1578, p 1579, p 1580, p 1581, p 1582, + p 1583, p 1584, p 1585, p 1586, p 1587, p 1588, p 1589, p 1590, p 1591, + p 1592, p 1593, p 1594, p 1595, p 1596, p 1597, p 1598, p 1599, p 1600, + p 1601, p 1602, p 1603, p 1604, p 1605, p 1606, p 1607, p 1608, p 1609, + p 1610, p 1611, p 1612, p 1613, p 1614, p 1615, p 1616, p 1617, p 1618, + p 1619, p 1620, p 1621, p 1622, p 1623, p 1624, p 1625, p 1626, p 1627, + p 1628, p 1629, p 1630, p 1631, p 1632, p 1633, p 1634, p 1635, p 1636, + p 1637, p 1638, p 1639, p 1640, p 1641, p 1642, p 1643, p 1644, p 1645, + p 1646, p 1647, p 1648, p 1649, p 1650, p 1651, p 1652, p 1653, p 1654, + p 1655, p 1656, p 1657, p 1658, p 1659, p 1660, p 1661, p 1662, p 1663, + p 1664, p 1665, p 1666, p 1667, p 1668, p 1669, p 1670, p 1671, p 1672, + p 1673, p 1674, p 1675, p 1676, p 1677, p 1678, p 1679, p 1680, p 1681, + p 1682, p 1683, p 1684, p 1685, p 1686, p 1687, p 1688, p 1689, p 1690, + p 1691, p 1692, p 1693, p 1694, p 1695, p 1696, p 1697, p 1698, p 1699, + p 1700, p 1701, p 1702, p 1703, p 1704, p 1705, p 1706, p 1707, p 1708, + p 1709, p 1710, p 1711, p 1712, p 1713, p 1714, p 1715, p 1716, p 1717, + p 1718, p 1719, p 1720, p 1721, p 1722, p 1723, p 1724, p 1725, p 1726, + p 1727, p 1728, p 1729, p 1730, p 1731, p 1732, p 1733, p 1734, p 1735, + p 1736, p 1737, p 1738, p 1739, p 1740, p 1741, p 1742, p 1743, p 1744, + p 1745, p 1746, p 1747, p 1748, p 1749, p 1750, p 1751, p 1752, p 1753, + p 1754, p 1755, p 1756, p 1757, p 1758, p 1759, p 1760, p 1761, p 1762, + p 1763, p 1764, p 1765, p 1766, p 1767, p 1768, p 1769, p 1770, p 1771, + p 1772, p 1773, p 1774, p 1775, p 1776, p 1777, p 1778, p 1779, p 1780, + p 1781, p 1782, p 1783, p 1784, p 1785, p 1786, p 1787, p 1788, p 1789, + p 1790, p 1791, p 1792, p 1793, p 1794, p 1795, p 1796, p 1797, p 1798, + p 1799, p 1800, p 1801, p 1802, p 1803, p 1804, p 1805, p 1806, p 1807, + p 1808, p 1809, p 1810, p 1811, p 1812, p 1813, p 1814, p 1815, p 1816, + p 1817, p 1818, p 1819, p 1820, p 1821, p 1822, p 1823, p 1824, p 1825, + p 1826, p 1827, p 1828, p 1829, p 1830, p 1831, p 1832, p 1833, p 1834, + p 1835, p 1836, p 1837, p 1838, p 1839, p 1840, p 1841, p 1842, p 1843, + p 1844, p 1845, p 1846, p 1847, p 1848, p 1849, p 1850, p 1851, p 1852, + p 1853, p 1854, p 1855, p 1856, p 1857, p 1858, p 1859, p 1860, p 1861, + p 1862, p 1863, p 1864, p 1865, p 1866, p 1867, p 1868, p 1869, p 1870, + p 1871, p 1872, p 1873, p 1874, p 1875, p 1876, p 1877, p 1878, p 1879, + p 1880, p 1881, p 1882, p 1883, p 1884, p 1885, p 1886, p 1887, p 1888, + p 1889, p 1890, p 1891, p 1892, p 1893, p 1894, p 1895, p 1896, p 1897, + p 1898, p 1899, p 1900, p 1901, p 1902, p 1903, p 1904, p 1905, p 1906, + p 1907, p 1908, p 1909, p 1910, p 1911, p 1912, p 1913, p 1914, p 1915, + p 1916, p 1917, p 1918, p 1919, p 1920, p 1921, p 1922, p 1923, p 1924, + p 1925, p 1926, p 1927, p 1928, p 1929, p 1930, p 1931, p 1932, p 1933, + p 1934, p 1935, p 1936, p 1937, p 1938, p 1939, p 1940, p 1941, p 1942, + p 1943, p 1944, p 1945, p 1946, p 1947, p 1948, p 1949, p 1950, p 1951, + p 1952, p 1953, p 1954, p 1955, p 1956, p 1957, p 1958, p 1959, p 1960, + p 1961, p 1962, p 1963, p 1964, p 1965, p 1966, p 1967, p 1968, p 1969, + p 1970, p 1971, p 1972, p 1973, p 1974, p 1975, p 1976, p 1977, p 1978, + p 1979, p 1980, p 1981, p 1982, p 1983, p 1984, p 1985, p 1986, p 1987, + p 1988, p 1989, p 1990, p 1991, p 1992, p 1993, p 1994, p 1995, p 1996, + p 1997, p 1998, p 1999, p 2000, p 2001, p 2002, p 2003, p 2004, p 2005, + p 2006, p 2007, p 2008, p 2009, p 2010, p 2011, p 2012, p 2013, p 2014, + p 2015, p 2016, p 2017, p 2018, p 2019, p 2020, p 2021, p 2022, p 2023, + p 2024, p 2025, p 2026, p 2027, p 2028, p 2029, p 2030, p 2031, p 2032, + p 2033, p 2034, p 2035, p 2036, p 2037, p 2038, p 2039, p 2040, p 2041, + p 2042, p 2043, p 2044, p 2045, p 2046, p 2047, p 2048, p 2049, p 2050, + p 2051, p 2052, p 2053, p 2054, p 2055, p 2056, p 2057, p 2058, p 2059, + p 2060, p 2061, p 2062, p 2063, p 2064, p 2065, p 2066, p 2067, p 2068, + p 2069, p 2070, p 2071, p 2072, p 2073, p 2074, p 2075, p 2076, p 2077, + p 2078, p 2079, p 2080, p 2081, p 2082, p 2083, p 2084, p 2085, p 2086, + p 2087, p 2088, p 2089, p 2090, p 2091, p 2092, p 2093, p 2094, p 2095, + p 2096, p 2097, p 2098, p 2099, p 2100, p 2101, p 2102, p 2103, p 2104, + p 2105, p 2106, p 2107, p 2108, p 2109, p 2110, p 2111, p 2112, p 2113, + p 2114, p 2115, p 2116, p 2117, p 2118, p 2119, p 2120, p 2121, p 2122, + p 2123, p 2124, p 2125, p 2126, p 2127, p 2128, p 2129, p 2130, p 2131, + p 2132, p 2133, p 2134, p 2135, p 2136, p 2137, p 2138, p 2139, p 2140, + p 2141, p 2142, p 2143, p 2144, p 2145, p 2146, p 2147, p 2148, p 2149, + p 2150, p 2151, p 2152, p 2153, p 2154, p 2155, p 2156, p 2157, p 2158, + p 2159, p 2160, p 2161, p 2162, p 2163, p 2164, p 2165, p 2166, p 2167, + p 2168, p 2169, p 2170, p 2171, p 2172, p 2173, p 2174, p 2175, p 2176, + p 2177, p 2178, p 2179, p 2180, p 2181, p 2182, p 2183, p 2184, p 2185, + p 2186, p 2187, p 2188, p 2189, p 2190, p 2191, p 2192, p 2193, p 2194, + p 2195, p 2196, p 2197, p 2198, p 2199, p 2200, p 2201, p 2202, p 2203, + p 2204, p 2205, p 2206, p 2207, p 2208, p 2209, p 2210, p 2211, p 2212, + p 2213, p 2214, p 2215, p 2216, p 2217, p 2218, p 2219, p 2220, p 2221, + p 2222, p 2223, p 2224, p 2225, p 2226, p 2227, p 2228, p 2229, p 2230, + p 2231, p 2232, p 2233, p 2234, p 2235, p 2236, p 2237, p 2238, p 2239, + p 2240, p 2241, p 2242, p 2243, p 2244, p 2245, p 2246, p 2247, p 2248, + p 2249, p 2250, p 2251, p 2252, p 2253, p 2254, p 2255, p 2256, p 2257, + p 2258, p 2259, p 2260, p 2261, p 2262, p 2263, p 2264, p 2265, p 2266, + p 2267, p 2268, p 2269, p 2270, p 2271, p 2272, p 2273, p 2274, p 2275, + p 2276, p 2277, p 2278, p 2279, p 2280, p 2281, p 2282, p 2283, p 2284, + p 2285, p 2286, p 2287, p 2288, p 2289, p 2290, p 2291, p 2292, p 2293, + p 2294, p 2295, p 2296, p 2297, p 2298, p 2299, p 2300, p 2301, p 2302, + p 2303, p 2304, p 2305, p 2306, p 2307, p 2308, p 2309, p 2310, p 2311, + p 2312, p 2313, p 2314, p 2315, p 2316, p 2317, p 2318, p 2319, p 2320, + p 2321, p 2322, p 2323, p 2324, p 2325, p 2326, p 2327, p 2328, p 2329, + p 2330, p 2331, p 2332, p 2333, p 2334, p 2335, p 2336, p 2337, p 2338, + p 2339, p 2340, p 2341, p 2342, p 2343, p 2344, p 2345, p 2346, p 2347, + p 2348, p 2349, p 2350, p 2351, p 2352, p 2353, p 2354, p 2355, p 2356, + p 2357, p 2358, p 2359, p 2360, p 2361, p 2362, p 2363, p 2364, p 2365, + p 2366, p 2367, p 2368, p 2369, p 2370, p 2371, p 2372, p 2373, p 2374, + p 2375, p 2376, p 2377, p 2378, p 2379, p 2380, p 2381, p 2382, p 2383, + p 2384, p 2385, p 2386, p 2387, p 2388, p 2389, p 2390, p 2391, p 2392, + p 2393, p 2394, p 2395, p 2396, p 2397, p 2398, p 2399, p 2400, p 2401, + p 2402, p 2403, p 2404, p 2405, p 2406, p 2407, p 2408, p 2409, p 2410, + p 2411, p 2412, p 2413, p 2414, p 2415, p 2416, p 2417, p 2418, p 2419, + p 2420, p 2421, p 2422, p 2423, p 2424, p 2425, p 2426, p 2427, p 2428, + p 2429, p 2430, p 2431, p 2432, p 2433, p 2434, p 2435, p 2436, p 2437, + p 2438, p 2439, p 2440, p 2441, p 2442, p 2443, p 2444, p 2445, p 2446, + p 2447, p 2448, p 2449, p 2450, p 2451, p 2452, p 2453, p 2454, p 2455, + p 2456, p 2457, p 2458, p 2459, p 2460, p 2461, p 2462, p 2463, p 2464, + p 2465, p 2466, p 2467, p 2468, p 2469, p 2470, p 2471, p 2472, p 2473, + p 2474, p 2475, p 2476, p 2477, p 2478, p 2479, p 2480, p 2481, p 2482, + p 2483, p 2484, p 2485, p 2486, p 2487, p 2488, p 2489, p 2490, p 2491, + p 2492, p 2493, p 2494, p 2495, p 2496, p 2497, p 2498, p 2499, p 2500, + p 2501, p 2502, p 2503, p 2504, p 2505, p 2506, p 2507, p 2508, p 2509, + p 2510, p 2511, p 2512, p 2513, p 2514, p 2515, p 2516, p 2517, p 2518, + p 2519, p 2520, p 2521, p 2522, p 2523, p 2524, p 2525, p 2526, p 2527, + p 2528, p 2529, p 2530, p 2531, p 2532, p 2533, p 2534, p 2535, p 2536, + p 2537, p 2538, p 2539, p 2540, p 2541, p 2542, p 2543, p 2544, p 2545, + p 2546, p 2547, p 2548, p 2549, p 2550, p 2551, p 2552, p 2553, p 2554, + p 2555, p 2556, p 2557, p 2558, p 2559, p 2560, p 2561, p 2562, p 2563, + p 2564, p 2565, p 2566, p 2567, p 2568, p 2569, p 2570, p 2571, p 2572, + p 2573, p 2574, p 2575, p 2576, p 2577, p 2578, p 2579, p 2580, p 2581, + p 2582, p 2583, p 2584, p 2585, p 2586, p 2587, p 2588, p 2589, p 2590, + p 2591, p 2592, p 2593, p 2594, p 2595, p 2596, p 2597, p 2598, p 2599, + p 2600, p 2601, p 2602, p 2603, p 2604, p 2605, p 2606, p 2607, p 2608, + p 2609, p 2610, p 2611, p 2612, p 2613, p 2614, p 2615, p 2616, p 2617, + p 2618, p 2619, p 2620, p 2621, p 2622, p 2623, p 2624, p 2625, p 2626, + p 2627, p 2628, p 2629, p 2630, p 2631, p 2632, p 2633, p 2634, p 2635, + p 2636, p 2637, p 2638, p 2639, p 2640, p 2641, p 2642, p 2643, p 2644, + p 2645, p 2646, p 2647, p 2648, p 2649, p 2650, p 2651, p 2652, p 2653, + p 2654, p 2655, p 2656, p 2657, p 2658, p 2659, p 2660, p 2661, p 2662, + p 2663, p 2664, p 2665, p 2666, p 2667, p 2668, p 2669, p 2670, p 2671, + p 2672, p 2673, p 2674, p 2675, p 2676, p 2677, p 2678, p 2679, p 2680, + p 2681, p 2682, p 2683, p 2684, p 2685, p 2686, p 2687, p 2688, p 2689, + p 2690, p 2691, p 2692, p 2693, p 2694, p 2695, p 2696, p 2697, p 2698, + p 2699, p 2700, p 2701, p 2702, p 2703, p 2704, p 2705, p 2706, p 2707, + p 2708, p 2709, p 2710, p 2711, p 2712, p 2713, p 2714, p 2715, p 2716, + p 2717, p 2718, p 2719, p 2720, p 2721, p 2722, p 2723, p 2724, p 2725, + p 2726, p 2727, p 2728, p 2729, p 2730, p 2731, p 2732, p 2733, p 2734, + p 2735, p 2736, p 2737, p 2738, p 2739, p 2740, p 2741, p 2742, p 2743, + p 2744, p 2745, p 2746, p 2747, p 2748, p 2749, p 2750, p 2751, p 2752, + p 2753, p 2754, p 2755, p 2756, p 2757, p 2758, p 2759, p 2760, p 2761, + p 2762, p 2763, p 2764, p 2765, p 2766, p 2767, p 2768, p 2769, p 2770, + p 2771, p 2772, p 2773, p 2774, p 2775, p 2776, p 2777, p 2778, p 2779, + p 2780, p 2781, p 2782, p 2783, p 2784, p 2785, p 2786, p 2787, p 2788, + p 2789, p 2790, p 2791, p 2792, p 2793, p 2794, p 2795, p 2796, p 2797, + p 2798, p 2799, p 2800, p 2801, p 2802, p 2803, p 2804, p 2805, p 2806, + p 2807, p 2808, p 2809, p 2810, p 2811, p 2812, p 2813, p 2814, p 2815, + p 2816, p 2817, p 2818, p 2819, p 2820, p 2821, p 2822, p 2823, p 2824, + p 2825, p 2826, p 2827, p 2828, p 2829, p 2830, p 2831, p 2832, p 2833, + p 2834, p 2835, p 2836, p 2837, p 2838, p 2839, p 2840, p 2841, p 2842, + p 2843, p 2844, p 2845, p 2846, p 2847, p 2848, p 2849, p 2850, p 2851, + p 2852, p 2853, p 2854, p 2855, p 2856, p 2857, p 2858, p 2859, p 2860, + p 2861, p 2862, p 2863, p 2864, p 2865, p 2866, p 2867, p 2868, p 2869, + p 2870, p 2871, p 2872, p 2873, p 2874, p 2875, p 2876, p 2877, p 2878, + p 2879, p 2880, p 2881, p 2882, p 2883, p 2884, p 2885, p 2886, p 2887, + p 2888, p 2889, p 2890, p 2891, p 2892, p 2893, p 2894, p 2895, p 2896, + p 2897, p 2898, p 2899, p 2900, p 2901, p 2902, p 2903, p 2904, p 2905, + p 2906, p 2907, p 2908, p 2909, p 2910, p 2911, p 2912, p 2913, p 2914, + p 2915, p 2916, p 2917, p 2918, p 2919, p 2920, p 2921, p 2922, p 2923, + p 2924, p 2925, p 2926, p 2927, p 2928, p 2929, p 2930, p 2931, p 2932, + p 2933, p 2934, p 2935, p 2936, p 2937, p 2938, p 2939, p 2940, p 2941, + p 2942, p 2943, p 2944, p 2945, p 2946, p 2947, p 2948, p 2949, p 2950, + p 2951, p 2952, p 2953, p 2954, p 2955, p 2956, p 2957, p 2958, p 2959, + p 2960, p 2961, p 2962, p 2963, p 2964, p 2965, p 2966, p 2967, p 2968, + p 2969, p 2970, p 2971, p 2972, p 2973, p 2974, p 2975, p 2976, p 2977, + p 2978, p 2979, p 2980, p 2981, p 2982, p 2983, p 2984, p 2985, p 2986, + p 2987, p 2988, p 2989, p 2990, p 2991, p 2992, p 2993, p 2994, p 2995, + p 2996, p 2997, p 2998, p 2999, p 3000, p 3001, p 3002, p 3003, p 3004, + p 3005, p 3006, p 3007, p 3008, p 3009, p 3010, p 3011, p 3012, p 3013, + p 3014, p 3015, p 3016, p 3017, p 3018, p 3019, p 3020, p 3021, p 3022, + p 3023, p 3024, p 3025, p 3026, p 3027, p 3028, p 3029, p 3030, p 3031, + p 3032, p 3033, p 3034, p 3035, p 3036, p 3037, p 3038, p 3039, p 3040, + p 3041, p 3042, p 3043, p 3044, p 3045, p 3046, p 3047, p 3048, p 3049, + p 3050, p 3051, p 3052, p 3053, p 3054, p 3055, p 3056, p 3057, p 3058, + p 3059, p 3060, p 3061, p 3062, p 3063, p 3064, p 3065, p 3066, p 3067, + p 3068, p 3069, p 3070, p 3071, p 3072, p 3073, p 3074, p 3075, p 3076, + p 3077, p 3078, p 3079, p 3080, p 3081, p 3082, p 3083, p 3084, p 3085, + p 3086, p 3087, p 3088, p 3089, p 3090, p 3091, p 3092, p 3093, p 3094, + p 3095, p 3096, p 3097, p 3098, p 3099, p 3100, p 3101, p 3102, p 3103, + p 3104, p 3105, p 3106, p 3107, p 3108, p 3109, p 3110, p 3111, p 3112, + p 3113, p 3114, p 3115, p 3116, p 3117, p 3118, p 3119, p 3120, p 3121, + p 3122, p 3123, p 3124, p 3125, p 3126, p 3127, p 3128, p 3129, p 3130, + p 3131, p 3132, p 3133, p 3134, p 3135, p 3136, p 3137, p 3138, p 3139, + p 3140, p 3141, p 3142, p 3143, p 3144, p 3145, p 3146, p 3147, p 3148, + p 3149, p 3150, p 3151, p 3152, p 3153, p 3154, p 3155, p 3156, p 3157, + p 3158, p 3159, p 3160, p 3161, p 3162, p 3163, p 3164, p 3165, p 3166, + p 3167, p 3168, p 3169, p 3170, p 3171, p 3172, p 3173, p 3174, p 3175, + p 3176, p 3177, p 3178, p 3179, p 3180, p 3181, p 3182, p 3183, p 3184, + p 3185, p 3186, p 3187, p 3188, p 3189, p 3190, p 3191, p 3192, p 3193, + p 3194, p 3195, p 3196, p 3197, p 3198, p 3199, p 3200, p 3201, p 3202, + p 3203, p 3204, p 3205, p 3206, p 3207, p 3208, p 3209, p 3210, p 3211, + p 3212, p 3213, p 3214, p 3215, p 3216, p 3217, p 3218, p 3219, p 3220, + p 3221, p 3222, p 3223, p 3224, p 3225, p 3226, p 3227, p 3228, p 3229, + p 3230, p 3231, p 3232, p 3233, p 3234, p 3235, p 3236, p 3237, p 3238, + p 3239, p 3240, p 3241, p 3242, p 3243, p 3244, p 3245, p 3246, p 3247, + p 3248, p 3249, p 3250, p 3251, p 3252, p 3253, p 3254, p 3255, p 3256, + p 3257, p 3258, p 3259, p 3260, p 3261, p 3262, p 3263, p 3264, p 3265, + p 3266, p 3267, p 3268, p 3269, p 3270, p 3271, p 3272, p 3273, p 3274, + p 3275, p 3276, p 3277, p 3278, p 3279, p 3280, p 3281, p 3282, p 3283, + p 3284, p 3285, p 3286, p 3287, p 3288, p 3289, p 3290, p 3291, p 3292, + p 3293, p 3294, p 3295, p 3296, p 3297, p 3298, p 3299, p 3300, p 3301, + p 3302, p 3303, p 3304, p 3305, p 3306, p 3307, p 3308, p 3309, p 3310, + p 3311, p 3312, p 3313, p 3314, p 3315, p 3316, p 3317, p 3318, p 3319, + p 3320, p 3321, p 3322, p 3323, p 3324, p 3325, p 3326, p 3327, p 3328, + p 3329, p 3330, p 3331, p 3332, p 3333, p 3334, p 3335, p 3336, p 3337, + p 3338, p 3339, p 3340, p 3341, p 3342, p 3343, p 3344, p 3345, p 3346, + p 3347, p 3348, p 3349, p 3350, p 3351, p 3352, p 3353, p 3354, p 3355, + p 3356, p 3357, p 3358, p 3359, p 3360, p 3361, p 3362, p 3363, p 3364, + p 3365, p 3366, p 3367, p 3368, p 3369, p 3370, p 3371, p 3372, p 3373, + p 3374, p 3375, p 3376, p 3377, p 3378, p 3379, p 3380, p 3381, p 3382, + p 3383, p 3384, p 3385, p 3386, p 3387, p 3388, p 3389, p 3390, p 3391, + p 3392, p 3393, p 3394, p 3395, p 3396, p 3397, p 3398, p 3399, p 3400, + p 3401, p 3402, p 3403, p 3404, p 3405, p 3406, p 3407, p 3408, p 3409, + p 3410, p 3411, p 3412, p 3413, p 3414, p 3415, p 3416, p 3417, p 3418, + p 3419, p 3420, p 3421, p 3422, p 3423, p 3424, p 3425, p 3426, p 3427, + p 3428, p 3429, p 3430, p 3431, p 3432, p 3433, p 3434, p 3435, p 3436, + p 3437, p 3438, p 3439, p 3440, p 3441, p 3442, p 3443, p 3444, p 3445, + p 3446, p 3447, p 3448, p 3449, p 3450, p 3451, p 3452, p 3453, p 3454, + p 3455, p 3456, p 3457, p 3458, p 3459, p 3460, p 3461, p 3462, p 3463, + p 3464, p 3465, p 3466, p 3467, p 3468, p 3469, p 3470, p 3471, p 3472, + p 3473, p 3474, p 3475, p 3476, p 3477, p 3478, p 3479, p 3480, p 3481, + p 3482, p 3483, p 3484, p 3485, p 3486, p 3487, p 3488, p 3489, p 3490, + p 3491, p 3492, p 3493, p 3494, p 3495, p 3496, p 3497, p 3498, p 3499, + p 3500, p 3501, p 3502, p 3503, p 3504, p 3505, p 3506, p 3507, p 3508, + p 3509, p 3510, p 3511, p 3512, p 3513, p 3514, p 3515, p 3516, p 3517, + p 3518, p 3519, p 3520, p 3521, p 3522, p 3523, p 3524, p 3525, p 3526, + p 3527, p 3528, p 3529, p 3530, p 3531, p 3532, p 3533, p 3534, p 3535, + p 3536, p 3537, p 3538, p 3539, p 3540, p 3541, p 3542, p 3543, p 3544, + p 3545, p 3546, p 3547, p 3548, p 3549, p 3550, p 3551, p 3552, p 3553, + p 3554, p 3555, p 3556, p 3557, p 3558, p 3559, p 3560, p 3561, p 3562, + p 3563, p 3564, p 3565, p 3566, p 3567, p 3568, p 3569, p 3570, p 3571, + p 3572, p 3573, p 3574, p 3575, p 3576, p 3577, p 3578, p 3579, p 3580, + p 3581, p 3582, p 3583, p 3584, p 3585, p 3586, p 3587, p 3588, p 3589, + p 3590, p 3591, p 3592, p 3593, p 3594, p 3595, p 3596, p 3597, p 3598, + p 3599, p 3600, p 3601, p 3602, p 3603, p 3604, p 3605, p 3606, p 3607, + p 3608, p 3609, p 3610, p 3611, p 3612, p 3613, p 3614, p 3615, p 3616, + p 3617, p 3618, p 3619, p 3620, p 3621, p 3622, p 3623, p 3624, p 3625, + p 3626, p 3627, p 3628, p 3629, p 3630, p 3631, p 3632, p 3633, p 3634, + p 3635, p 3636, p 3637, p 3638, p 3639, p 3640, p 3641, p 3642, p 3643, + p 3644, p 3645, p 3646, p 3647, p 3648, p 3649, p 3650, p 3651, p 3652, + p 3653, p 3654, p 3655, p 3656, p 3657, p 3658, p 3659, p 3660, p 3661, + p 3662, p 3663, p 3664, p 3665, p 3666, p 3667, p 3668, p 3669, p 3670, + p 3671, p 3672, p 3673, p 3674, p 3675, p 3676, p 3677, p 3678, p 3679, + p 3680, p 3681, p 3682, p 3683, p 3684, p 3685, p 3686, p 3687, p 3688, + p 3689, p 3690, p 3691, p 3692, p 3693, p 3694, p 3695, p 3696, p 3697, + p 3698, p 3699, p 3700, p 3701, p 3702, p 3703, p 3704, p 3705, p 3706, + p 3707, p 3708, p 3709, p 3710] diff --git a/tests/test_link_perf.v b/tests/link_perf.t/test.v similarity index 100% rename from tests/test_link_perf.v rename to tests/link_perf.t/test.v diff --git a/tests/ltac.t/run.t b/tests/ltac.t/run.t new file mode 100644 index 000000000..b61c76ba8 --- /dev/null +++ b/tests/ltac.t/run.t @@ -0,0 +1,19 @@ + $ . ../setup-project.sh + $ dune build test.vo + z + : nat + it = elpi_subproof + : True + it : True + + it is not universe polymorphic + it is transparent + Expands to: Constant test.test.it + elpi_subproof = I + : True + elpi_subproof : True + + elpi_subproof is not universe polymorphic + elpi_subproof is opaque + Expands to: Constant test.test.elpi_subproof + Closed under the global context diff --git a/tests/test_ltac.v b/tests/ltac.t/test.v similarity index 100% rename from tests/test_ltac.v rename to tests/ltac.t/test.v diff --git a/tests/ltac2.t/run.t b/tests/ltac2.t/run.t new file mode 100644 index 000000000..b6c1abdd8 --- /dev/null +++ b/tests/ltac2.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_ltac is required + from root elpi and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-35: + Error: Cannot find a physical path bound to logical path + test_ltac with prefix elpi. + + [1] diff --git a/tests/test_ltac2.v b/tests/ltac2.t/test.v similarity index 100% rename from tests/test_ltac2.v rename to tests/ltac2.t/test.v diff --git a/tests/ltac3.t/run.t b/tests/ltac3.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/ltac3.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_ltac3.v b/tests/ltac3.t/test.v similarity index 100% rename from tests/test_ltac3.v rename to tests/ltac3.t/test.v diff --git a/tests/perf_calls.t/run.t b/tests/perf_calls.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/perf_calls.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/perf_calls.v b/tests/perf_calls.t/test.v similarity index 100% rename from tests/perf_calls.v rename to tests/perf_calls.t/test.v diff --git a/tests/query_extra_dep.t/run.t b/tests/query_extra_dep.t/run.t new file mode 100644 index 000000000..77af7ff8f --- /dev/null +++ b/tests/query_extra_dep.t/run.t @@ -0,0 +1,9 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, external file elpi_elaborator.elpi is required + from root elpi_elpi and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 3, characters 0-63: + Error: No LoadPath found for elpi_elpi. + + [1] diff --git a/tests/test_query_extra_dep.v b/tests/query_extra_dep.t/test.v similarity index 69% rename from tests/test_query_extra_dep.v rename to tests/query_extra_dep.t/test.v index 32020f17c..57b0f5590 100644 --- a/tests/test_query_extra_dep.v +++ b/tests/query_extra_dep.t/test.v @@ -1,6 +1,6 @@ From elpi Require Import elpi. -From unreleased Extra Dependency "elpi_elaborator.elpi" as elab. +From elpi_elpi Extra Dependency "elpi_elaborator.elpi" as elab. Elpi Command test. diff --git a/tests/quotation.t/run.t b/tests/quotation.t/run.t new file mode 100644 index 000000000..74a575d83 --- /dev/null +++ b/tests/quotation.t/run.t @@ -0,0 +1,332 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query assignments: + BO = fix `add` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]] + GR = «Nat.add» + TY = prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat») + fix X0 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ X1 c2 c3) + [c2, fun `p` (X2 c1 c2) c3 \ app [c0, c3, c2]] + fix X0 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, fun `p` (X3 c1 c2) c3 \ app [c0, c3, c2]] + Query assignments: + BO1 = fix X0 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, fun `p` (X3 c1 c2) c3 \ app [c0, c3, c2]] + GR = «Nat.add» + TY = prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat») + _uvk_1_ = c0 \ c1 \ + global (indt «nat») + _uvk_2_ = c0 \ c1 \ + X3 c0 c1 + Syntactic constraints: + {c0 c1} : + decl c1 `m` (global (indt «nat»)), decl c0 `n` (global (indt «nat»)) + ?- evar (X3 c0 c1) (sort (typ «test.test.2»)) (X3 c0 c1) /* suspended on X3 */ + Universe constraints: + UNIVERSES: + {test.test.3 test.test.2 test.test.1} |= Set <= test.test.3 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + test.test.3 + SORTS: + α1 + α2 + WEAK CONSTRAINTS: + + + fun `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]) + c0 \ + match c0 + (fun `_` (X0 c0) c1 \ + fun `v` (app [global (indt «Vector.t»), X1 c0 c1, X2 c0 c1]) c2 \ + X3 c1 c2) + [global (indc «O»), + fun `_` (X4 c0) c1 \ + fun `_` (X5 c0 c1) c2 \ + fun `_` (X6 c0 c1 c2) c3 \ + app [global (indc «S»), global (indc «O»)]] + fun `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]) + c0 \ + match c0 + (fun `_` (X7 c0) c1 \ + fun `v` + (app [global (indt «Vector.t»), global (indt «nat»), X8 c0 c1]) c2 \ + global (indt «nat»)) + [global (indc «O»), + fun `_` (X9 c0) c1 \ + fun `_` (X10 c0 c1) c2 \ + fun `_` (X11 c0 c1 c2) c3 \ + app [global (indc «S»), global (indc «O»)]] + Query assignments: + T = fun `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]) + c0 \ + match c0 + (fun `_` (X7 c0) c1 \ + fun `v` + (app [global (indt «Vector.t»), global (indt «nat»), X8 c0 c1]) c2 \ + global (indt «nat»)) + [global (indc «O»), + fun `_` (X9 c0) c1 \ + fun `_` (X10 c0 c1) c2 \ + fun `_` (X11 c0 c1 c2) c3 \ + app [global (indc «S»), global (indc «O»)]] + _uvk_10_ = c0 \ c1 \ + global (indt «nat») + _uvk_11_ = c0 \ + X9 c0 + _uvk_12_ = c0 \ c1 \ + X10 c0 c1 + _uvk_13_ = c0 \ c1 \ c2 \ + X11 c0 c1 c2 + _uvk_7_ = c0 \ + X7 c0 + _uvk_8_ = c0 \ c1 \ + global (indt «nat») + _uvk_9_ = c0 \ c1 \ + X8 c0 c1 + Syntactic constraints: + {c0 c1 c2} : + decl c2 `y0` (X10 c0 c1), decl c1 `y` (X9 c0), + decl c0 `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) + ?- evar (X11 c0 c1 c2) (sort (typ «test.test.10»)) (X11 c0 c1 c2) /* suspended on X11 */ + {c0 c1} : + decl c1 `y` (X9 c0), + decl c0 `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) + ?- evar (X10 c0 c1) (sort (typ «test.test.9»)) (X10 c0 c1) /* suspended on X10 */ + {c0} : + decl c0 `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app + [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]) + ?- evar (X9 c0) (sort (typ «test.test.8»)) (X9 c0) /* suspended on X9 */ + {c0 c1} : + decl c1 `y` (X7 c0), + decl c0 `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) + ?- evar (X8 c0 c1) (X12 c0 c1) (X8 c0 c1) /* suspended on X8 */ + {c0 c1} : + decl c1 `y` (X7 c0), + decl c0 `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app + [global (indc «S»), + app [global (indc «S»), global (indc «O»)]]]) + ?- evar (X13 c0 c1) (sort (typ «test.test.6»)) (X12 c0 c1) /* suspended on X13, X12 */ + {c0} : + decl c0 `v` + (app + [global (indt «Vector.t»), global (indt «nat»), + app + [global (indc «S»), app [global (indc «S»), global (indc «O»)]]]) + ?- evar (X7 c0) (sort (typ «test.test.4»)) (X7 c0) /* suspended on X7 */ + Universe constraints: + UNIVERSES: + {test.test.12 test.test.11 test.test.10 test.test.9 test.test.8 test.test.7 + test.test.6 test.test.5 test.test.4} |= + test.test.11 < test.test.5 + Set <= Vector.t.u0 + Set <= test.test.11 + Set <= test.test.12 + test.test.11 <= Vector.t.u0 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + test.test.12 + SORTS: + α3 + α4 := Type + α5 + α6 + α7 + α8 + α9 + WEAK CONSTRAINTS: + + + 3 + Query assignments: + X = 3 + fun `x` X0 c0 \ app [X1, c0] + Query assignments: + X = X1 + Y = fun `x` X0 c0 \ app [X1, c0] + _uvk_34_ = X0 + fun `r` (global (indt «nat»)) c0 \ + fun `p` + (prod `y` (global (indt «nat»)) c1 \ + app + [global (indt «eq»), global (indt «nat»), c1, global (indc «O»)]) + c1 \ + fun `q` (global (indt «bool»)) c2 \ + prod `y` (global (indt «nat»)) c3 \ + app + [global (indt «eq»), global (indt «nat»), c3, global (indc «O»)] + Query assignments: + Spilled_1 = c0 \ c1 \ c2 \ + prod `y` (global (indt «nat»)) c3 \ + app [global (indt «eq»), global (indt «nat»), c3, global (indc «O»)] + X = fun `r` (global (indt «nat»)) c0 \ + fun `p` + (prod `y` (global (indt «nat»)) c1 \ + app + [global (indt «eq»), global (indt «nat»), c1, global (indc «O»)]) + c1 \ + fun `q` (global (indt «bool»)) c2 \ + prod `y` (global (indt «nat»)) c3 \ + app + [global (indt «eq»), global (indt «nat»), c3, global (indc «O»)] + fun u : nat => + {| val := oval u; Sub := Ord u; Sub_rect := inlined_sub_rect |} + : forall u : nat, is_SUB nat (fun x : nat => leq x u) (ord u) + Query assignments: + GR = indc «Ord» + K = global (indc «Ord») + T = fun `u` X0 c0 \ + app + [global (indc «SubType»), X1 c0, X2 c0, X3 c0, + app [global (const «oval»), c0], X4 c0, + fun `K` (X5 c0) c1 \ + fun `K_S` (X6 c0 c1) c2 \ + fun `u` (X7 c0 c1 c2) c3 \ + match c3 (fun `u0` (X8 c1 c2 c3) c4 \ app [c1, c4]) + [fun `x` (X9 c1 c2 c3) c4 \ + fun `Px` (X10 c1 c2 c3 c4) c5 \ app [c2, c4, c5]]] + T1 = fun `u` (global (indt «nat»)) c0 \ + app + [global (indc «SubType»), global (indt «nat»), + fun `x` (global (indt «nat»)) c1 \ app [global (const «leq»), c1, c0], + app [global (indt «ord»), c0], app [global (const «oval»), c0], + app [global (indc «Ord»), c0], + fun `K` + (prod `x` (app [global (indt «ord»), c0]) c1 \ sort (typ «is_SUB.u2»)) + c1 \ + fun `K_S` + (prod `x` (global (indt «nat»)) c2 \ + prod `Px` + (app + [global (indt «eq»), global (indt «bool»), + app + [fun `x` (global (indt «nat»)) c3 \ + app [global (const «leq»), c3, c0], c2], + global (indc «true»)]) c3 \ + app [c1, app [global (indc «Ord»), c0, c2, c3]]) c2 \ + fun `u0` (app [global (indt «ord»), c0]) c3 \ + match c3 + (fun `xxx` (app [global (indt «ord»), c0]) c4 \ app [c1, c4]) + [fun `x` (global (indt «nat»)) c4 \ + fun `Px` + (app + [global (indt «eq»), global (indt «bool»), + app [global (const «leq»), c4, c0], global (indc «true»)]) + c5 \ app [c2, c4, c5]]] + _uvk_35_ = X0 + _uvk_36_ = X1 + _uvk_37_ = X2 + _uvk_38_ = X3 + _uvk_39_ = X4 + _uvk_40_ = X5 + _uvk_41_ = X6 + _uvk_42_ = X7 + _uvk_43_ = X8 + _uvk_44_ = X9 + _uvk_45_ = X10 + _uvk_46_ = global (indt «nat») + _uvk_47_ = c0 \ + global (indt «nat») + _uvk_48_ = c0 \ + fun `x` (global (indt «nat»)) c1 \ app [global (const «leq»), c1, c0] + _uvk_49_ = c0 \ + app [global (indt «ord»), c0] + _uvk_50_ = c0 \ + app [global (const «oval»), c0] + _uvk_51_ = c0 \ + fun `K` + (prod `x` (app [global (indt «ord»), c0]) c1 \ sort (typ «is_SUB.u2»)) + c1 \ + fun `K_S` + (prod `x` (global (indt «nat»)) c2 \ + prod `Px` + (app + [global (indt «eq»), global (indt «bool»), + app + [fun `x` (global (indt «nat»)) c3 \ + app [global (const «leq»), c3, c0], c2], global (indc «true»)]) + c3 \ app [c1, app [global (indc «Ord»), c0, c2, c3]]) c2 \ + fun `u0` (app [global (indt «ord»), c0]) c3 \ + match c3 (fun `xxx` (app [global (indt «ord»), c0]) c4 \ app [c1, c4]) + [fun `x` (global (indt «nat»)) c4 \ + fun `Px` + (app + [global (indt «eq»), global (indt «bool»), + app [global (const «leq»), c4, c0], global (indc «true»)]) c5 \ + app [c2, c4, c5]] + Universe constraints: + UNIVERSES: + {test.test.28 test.test.27} |= + Set <= is_SUB.u0 + Set <= is_SUB.u1 + Set <= test.test.27 + is_SUB.u2 <= test.test.28 + ALGEBRAIC UNIVERSES: + {test.test.28 test.test.27} + FLEXIBLE UNIVERSES: + test.test.28 + test.test.27 + SORTS: + α22 := Type + α23 := Type + WEAK CONSTRAINTS: + + + 1 + : nat diff --git a/tests/test_quotation.v b/tests/quotation.t/test.v similarity index 100% rename from tests/test_quotation.v rename to tests/quotation.t/test.v diff --git a/tests/require_bad_order.t/run.t b/tests/require_bad_order.t/run.t new file mode 100644 index 000000000..548b78b39 --- /dev/null +++ b/tests/require_bad_order.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_API2 is required + from root elpi and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 2, characters 0-28: + Error: Cannot find a physical path bound to logical path + test_API2 with prefix elpi. + + [1] diff --git a/tests/test_require_bad_order.v b/tests/require_bad_order.t/test.v similarity index 100% rename from tests/test_require_bad_order.v rename to tests/require_bad_order.t/test.v diff --git a/tests/run.t b/tests/run.t new file mode 100644 index 000000000..932b53176 --- /dev/null +++ b/tests/run.t @@ -0,0 +1,4 @@ + $ . ../setup-project.sh + ***** UNREACHABLE ***** + $ dune build test.vo + ***** UNREACHABLE ***** diff --git a/tests/setup-project.sh b/tests/setup-project.sh new file mode 100644 index 000000000..93b5c5530 --- /dev/null +++ b/tests/setup-project.sh @@ -0,0 +1,18 @@ +cat > dune < dune-project < Type + h : o = m + w : T + ====================== + (x w = Type -> x w -> exists a : x w, a = a) + {c0 c1 c2 c3} : + decl c3 `w` c0, + decl c2 `h` + (app + [global (indt «eq»), global (indt «nat»), global (const «o»), + global (const «m»)]), + decl c1 `x` (prod `y` c0 c4 \ sort (typ «test.test.2»)), + decl c0 `T` (sort (typ «test.test.1»)) + ?- evar (X0 c0 c1 c2 c3) + (prod `e` + (app + [global (indt «eq»), sort (typ «test.test.2»), app [c1, c3], + sort (typ «test.test.3»)]) c4 \ + prod `j` (app [c1, c3]) c5 \ + app + [global (indt «ex»), app [c1, c3], + fun `a` (app [c1, c3]) c6 \ + app [global (indt «eq»), app [c1, c3], c6, c6]]) + (X1 c0 c1 c2 c3) /* suspended on X0, X1 */ + Goal: + + n : nat + m : nat + o := m : nat + T : Type + x : T -> Type + h : o = m + w : T + ====================== + (x w = Type -> x w -> exists a : x w, a = a) + {c0 c1 c2 c3 c4 c5} : + decl c5 `j` (app [c1, c3]), + decl c4 `e` + (app + [global (indt «eq»), sort (typ «test.test.2»), app [c1, c3], + sort (typ «test.test.3»)]), decl c3 `w` c0, + decl c2 `h` + (app + [global (indt «eq»), global (indt «nat»), global (const «o»), + global (const «m»)]), + decl c1 `x` (prod `y` c0 c6 \ sort (typ «test.test.2»)), + decl c0 `T` (sort (typ «test.test.1»)) + ?- evar (X0 c0 c1 c2 c3 c4 c5) (app [c1, c3]) (X1 c0 c1 c2 c3 c4 c5) /* suspended on X0, X1 */ + {c0 c1 c2 c3 c4 c5} : + decl c5 `j` (app [c1, c3]), + decl c4 `e` + (app + [global (indt «eq»), sort (typ «test.test.2»), app [c1, c3], + sort (typ «test.test.3»)]), decl c3 `w` c0, + decl c2 `h` + (app + [global (indt «eq»), global (indt «nat»), global (const «o»), + global (const «m»)]), + decl c1 `x` (prod `y` c0 c6 \ sort (typ «test.test.2»)), + decl c0 `T` (sort (typ «test.test.1»)) + ?- evar (X2 c0 c1 c2 c3 c4 c5) + (app + [global (indt «eq»), app [c1, c3], X1 c0 c1 c2 c3 c4 c5, + X1 c0 c1 c2 c3 c4 c5]) (X3 c0 c1 c2 c3 c4 c5) /* suspended on X2, X3 */ + Goal: + + n : nat + m : nat + o := m : nat + T : Type + x : T -> Type + h : o = m + w : T + e : x w = Type + j : x w + ====================== + (?foo = ?foo) + {c0 c1 c2 c3 c4 c5} : + decl c5 `j` (app [c1, c3]), + decl c4 `e` + (app + [global (indt «eq»), sort (typ «test.test.2»), app [c1, c3], + sort (typ «test.test.3»)]), decl c3 `w` c0, + decl c2 `h` + (app + [global (indt «eq»), global (indt «nat»), global (const «o»), + global (const «m»)]), + decl c1 `x` (prod `y` c0 c6 \ sort (typ «test.test.2»)), + decl c0 `T` (sort (typ «test.test.1»)) + ?- evar (X0 c0 c1 c2 c3 c4 c5) (app [c1, c3]) (X1 c0 c1 c2 c3 c4 c5) /* suspended on X0, X1 */ + {c0 c1 c2 c3 c4 c5} : + decl c5 `j` (app [c1, c3]), + decl c4 `e` + (app + [global (indt «eq»), sort (typ «test.test.2»), app [c1, c3], + sort (typ «test.test.3»)]), decl c3 `w` c0, + decl c2 `h` + (app + [global (indt «eq»), global (indt «nat»), global (const «o»), + global (const «m»)]), + decl c1 `x` (prod `y` c0 c6 \ sort (typ «test.test.2»)), + decl c0 `T` (sort (typ «test.test.1»)) + ?- evar (X2 c0 c1 c2 c3 c4 c5) + (app + [global (indt «eq»), app [c1, c3], X1 c0 c1 c2 c3 c4 c5, + X1 c0 c1 c2 c3 c4 c5]) (X3 c0 c1 c2 c3 c4 c5) /* suspended on X2, X3 */ + Goal: + + n : nat + m : nat + o := m : nat + T : Type + x : T -> Type + h : o = m + w : T + e : x w = Type + j : x w + ====================== + (?foo = ?foo) + evar (X0) (global (indt «nat»)) X1 /* suspended on X0, X1 */ + X0 global (indt «nat») + evar (X2) (global (indt «nat»)) X3 /* suspended on X2, X3 */ + hello + eq_refl : one = 1 + : one = 1 + [(c4 \ app [c1, c2]), (c4 \ app [c0, c2]), (c4 \ c4), (c4 \ + prod `x0` (app [c0, c2]) c5 \ + prod `x1` (global (indt «nat»)) c6 \ sort (typ «test.test.16»))] + [app + [global (indt «eq»), global (indt «nat»), c2, + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]], + sort prop] + 1356 + : nat + this 3 app [c4, X0 c0 c1 c2 c3 c4] + app [c3, app [c1, c2], global (const «a»)] foo.bar + [trm c0, trm (app [global (const «Nat.add»), c0, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [trm c0, trm (app [global (const «Nat.add»), X0 c0 c1, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0 c1) (global (indt «nat»)) (X0 c0 c1) /* suspended on X1, X0 */ + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X2 c0 c1) (global (indt «True»)) (X3 c0 c1) /* suspended on X2, X3 */ + [trm c0, trm (app [global (const «Nat.add»), X0 c0 c1, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0 c1) (global (indt «True»)) (X2 c0 c1) /* suspended on X1, X2 */ + [trm c0, trm c1] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [trm (app [global (const «Nat.add»), c0, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [trm (app [global (const «Nat.add»), X0 c0 c1, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0 c1) (global (indt «nat»)) (X0 c0 c1) /* suspended on X1, X0 */ + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X2 c0 c1) (global (indt «True»)) (X3 c0 c1) /* suspended on X2, X3 */ + [trm (app [global (const «Nat.add»), X0 c0 c1, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0 c1) (global (indt «True»)) (X2 c0 c1) /* suspended on X1, X2 */ + [trm (app [global (indc «O»), global (indc «O»)])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [trm c0] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [int 1] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [int -1] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [str a] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [str a] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [str x] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [trm (app [global (const «Nat.add»), c0, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [trm (app [global (const «Nat.add»), X0 c0 c1, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0 c1) (global (indt «True»)) (X2 c0 c1) /* suspended on X1, X2 */ + [trm (app [global (const «Nat.add»), X0 c0 c1, c1])] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0 c1) (global (indt «True»)) (X2 c0 c1) /* suspended on X1, X2 */ + [trm c0] + {c0 c1} : + decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»)) + ?- evar (X0 c0 c1) (global (indt «True»)) (X1 c0 c1) /* suspended on X0, X1 */ + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 314, column 10, character 6765:), + attribute elpi.phase (leaf-str interp)] + Entry binder_constr is + [ LEFTA + [ "exists2"; "'"; pattern LEVEL "0"; ":"; term LEVEL "200"; ","; term LEVEL + "200"; "&"; term LEVEL "200" + | "exists2"; "'"; pattern LEVEL "0"; ","; term LEVEL "200"; "&"; term LEVEL + "200" + | "exists2"; name; ":"; term LEVEL "200"; ","; term LEVEL "200"; "&"; term + LEVEL "200" + | "exists2"; name; ","; term LEVEL "200"; "&"; term LEVEL "200" + | "exists"; "!"; open_binders; ","; term LEVEL "200" + | "exists"; open_binders; ","; term LEVEL "200" + | "forall"; open_binders; ","; term LEVEL "200" + | "fun"; open_binders; "=>"; term LEVEL "200" + | "let"; "fix"; fix_decl; "in"; term LEVEL "200" + | "let"; "cofix"; cofix_body; "in"; term LEVEL "200" + | "let"; "'"; pattern LEVEL "200"; ":="; term LEVEL "200"; "in"; term LEVEL + "200" + | "let"; "'"; pattern LEVEL "200"; ":="; term LEVEL "200"; case_type; "in"; + term LEVEL "200" + | "let"; "'"; pattern LEVEL "200"; "in"; pattern LEVEL "200"; ":="; term + LEVEL "200"; case_type; "in"; term LEVEL "200" + | "let"; name; binders; let_type_cstr; ":="; term LEVEL "200"; "in"; term + LEVEL "200" + | "let"; [ "("; LIST0 name SEP ","; ")" | "()" ]; as_return_type; ":="; + term LEVEL "200"; "in"; term LEVEL "200" + | "if"; term LEVEL "200"; as_return_type; "then"; term LEVEL "200"; "else"; + term LEVEL "200" + | "fix"; fix_decls + | "cofix"; cofix_decls ] ] + + Entry constr is + [ LEFTA + [ "@"; global; univ_annot + | term LEVEL "8" ] ] + + Entry lconstr is + [ LEFTA + [ term LEVEL "200" ] ] + + Entry term is + [ "200" RIGHTA + [ ] + | "100" RIGHTA + [ SELF; "<:"; term LEVEL "200" + | SELF; "<<:"; term LEVEL "200" + | SELF; ":>"; term LEVEL "200" + | SELF; ":"; term LEVEL "200" ] + | "99" RIGHTA + [ SELF; "->"; term LEVEL "200" ] + | "95" RIGHTA + [ SELF; "<->"; NEXT ] + | "90" RIGHTA + [ ] + | "85" RIGHTA + [ SELF; "\\/"; term LEVEL "85" ] + | "80" RIGHTA + [ SELF; "/\\"; term LEVEL "80" ] + | "75" RIGHTA + [ "~"; term LEVEL "75" ] + | "70" RIGHTA + [ SELF; ">"; NEXT + | SELF; ">="; NEXT + | SELF; "<"; NEXT; "<="; NEXT + | SELF; "<"; NEXT; "<"; NEXT + | SELF; "<"; NEXT + | SELF; "<="; NEXT; "<"; NEXT + | SELF; "<="; NEXT; "<="; NEXT + | SELF; "<="; NEXT + | SELF; "<>"; NEXT; ":>"; NEXT + | SELF; "<>"; NEXT + | SELF; "="; NEXT; "="; NEXT + | SELF; "="; NEXT; ":>"; NEXT + | SELF; "="; NEXT ] + | "60" RIGHTA + [ SELF; "++"; term LEVEL "60" + | SELF; "::"; term LEVEL "60" ] + | "50" LEFTA + [ SELF; "||"; NEXT + | SELF; "-"; NEXT + | SELF; "+"; NEXT ] + | "40" LEFTA + [ SELF; "&&"; NEXT + | SELF; "/"; NEXT + | SELF; "*"; NEXT ] + | "35" RIGHTA + [ "/"; term LEVEL "35" + | "-"; term LEVEL "35" ] + | "30" RIGHTA + [ SELF; "^"; term LEVEL "30" ] + | LEFTA + [ IDENT "XX"; FIELD "xxx"; LIST0 arg ] + | "10" LEFTA + [ SELF; LIST1 arg + | "@"; global; univ_annot; LIST0 NEXT + | "@"; pattern_ident; LIST1 identref + | binder_constr ] + | "9" LEFTA + [ ".."; term LEVEL "0"; ".." ] + | "8" LEFTA + [ ] + | "1" LEFTA + [ SELF; ".("; "@"; global; univ_annot; LIST0 (term LEVEL "9"); ")" + | SELF; ".("; global; univ_annot; LIST0 arg; ")" + | SELF; "%"; IDENT + | SELF; "%_"; IDENT ] + | "0" LEFTA + [ "lib"; ":"; "@"; qualified_name + | "lib"; ":"; qualified_name + | QUOTATION "lp:" + | "{"; "'"; pattern LEVEL "0"; "&"; term LEVEL "200"; "&"; term LEVEL + "200"; "}" + | "{"; "'"; pattern LEVEL "0"; "&"; term LEVEL "200"; "}" + | "{"; "'"; pattern LEVEL "0"; ":"; term LEVEL "200"; "&"; term LEVEL + "200"; "&"; term LEVEL "200"; "}" + | "{"; "'"; pattern LEVEL "0"; ":"; term LEVEL "200"; "&"; term LEVEL + "200"; "}" + | "{"; "'"; pattern LEVEL "0"; ":"; term LEVEL "200"; "|"; term LEVEL + "200"; "&"; term LEVEL "200"; "}" + | "{"; "'"; pattern LEVEL "0"; ":"; term LEVEL "200"; "|"; term LEVEL + "200"; "}" + | "{"; "'"; pattern LEVEL "0"; "|"; term LEVEL "200"; "&"; term LEVEL + "200"; "}" + | "{"; "'"; pattern LEVEL "0"; "|"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; "&"; term LEVEL "200"; "&"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; "&"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; ":"; term LEVEL "200"; "&"; term LEVEL "200"; "&"; + term LEVEL "200"; "}" + | "{"; term LEVEL "99"; ":"; term LEVEL "200"; "&"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; ":"; term LEVEL "200"; "|"; term LEVEL "200"; "&"; + term LEVEL "200"; "}" + | "{"; term LEVEL "99"; ":"; term LEVEL "200"; "|"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; "|"; term LEVEL "200"; "&"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; "|"; term LEVEL "200"; "}" + | "{"; term LEVEL "99"; "}" + | IDENT "ltac"; ":"; "("; ltac_expr; ")" + | "("; term LEVEL "200"; ","; term LEVEL "200"; ","; LIST1 (term LEVEL + "200") SEP ","; ")" + | "("; term LEVEL "200"; ","; term LEVEL "200"; ")" + | "("; term LEVEL "200"; ")" + | "{|"; record_declaration; '|}' + | "`{"; term LEVEL "200"; "}" + | "`("; term LEVEL "200"; ")" + | NUMBER + | atomic_constr + | term_match + | ident; fields; univ_annot + | ident; univ_annot + | string + | test_array_opening; "["; "|"; array_elems; "|"; lconstr; type_cstr; + test_array_closing; "|"; "]"; univ_annot ] ] + + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 325, column 12, character 7018:), + attribute elpi.phase (leaf-str interp)] + skip int 1 + skip str 33 + skip trm (global (indt «bool»)) + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 325, column 12, character 7018:), + attribute elpi.phase (leaf-str interp)] + skip int 1 + skip str 33 + skip trm (global (indt «bool»)) + nat -> bool -> True + : Prop + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 334, column 12, character 7204:), + attribute elpi.phase (leaf-str interp)] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 334, column 12, character 7204:), + attribute elpi.phase (leaf-str interp)] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 338, column 30, character 7305:), + attribute elpi.phase (leaf-str interp)] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 338, column 30, character 7305:), + attribute elpi.phase (leaf-str interp)] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 346, column 7, character 7481:), + attribute elpi.phase (leaf-str interp)] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 346, column 7, character 7481:), + attribute elpi.phase (leaf-str interp)] + H + goal [] (X0) (global (indt «True»)) X1 [trm (global (const «H»))] + goal [] (X0) (global (indt «True»)) X1 + [trm + (app + [global (indt «eq»), global (indt «True»), global (const «H»), + global (const «H»)])] + goal [] (X0) (global (indt «True»)) X1 [trm (global (const «H»))] + x1 + : nat + w + : nat + File "./test.v", line 5, characters 3-155: + Warning: Type is linear: name it _Type (discard) or Type_ (fresh variable) + [elpi.typecheck,elpi,default] diff --git a/tests/test_tactic.v b/tests/tactic.t/test.v similarity index 100% rename from tests/test_tactic.v rename to tests/tactic.t/test.v diff --git a/tests/test_link_order_import3.ref b/tests/test_link_order_import3.ref deleted file mode 100644 index 2b3045596..000000000 --- a/tests/test_link_order_import3.ref +++ /dev/null @@ -1,411 +0,0 @@ -declare-evar A0 A1 A2 A3 :- - declare_constraint (declare-evar A0 A1 A2 A3) [A1]. -rm-evar (as uvar A0) (as uvar A1) :- - ! , declare_constraint (rm-evar A0 A1) [A0, A1]. -rm-evar _ _. -evar (as uvar A0) A1 A2 :- - , (var A2 _ A3) (!) (prune A1 A3) (prune A0 A3) - (declare_constraint (evar A0 A1 A2) [A0, A2]). -evar _ _ _. -coq.env.const-opaque? A0 :- - coq.warning elpi.deprecated elpi.const-opaque - use coq.env.opaque? in place of coq.env.const-opaque? , coq.env.opaque? A0. -coq.env.const-primitive? A0 :- - coq.warning elpi.deprecated elpi.const-primitive - use coq.env.primitive? in place of coq.env.const-primitive? , - coq.env.primitive? A0. -coq.env.begin-module A0 A1 :- coq.env.begin-module-functor A0 A1 []. -coq.env.begin-module-type A0 :- coq.env.begin-module-type-functor A0 []. -coq.CS.canonical-projections A0 A1 :- - coq.warning elpi.deprecated elpi.canonical-projections - use coq.env.projections in place of coq.CS.canonical-projections , - coq.env.projections A0 A1. -coq.reduction.cbv.whd_all A0 A1 :- - coq.warning elpi.deprecated elpi.cbv-whd-all - use coq.reduction.cbv.norm in place of coq.reduction.cbv.whd_all , - coq.reduction.cbv.norm A0 A1. -coq.reduction.vm.whd_all A0 A1 A2 :- - coq.warning elpi.deprecated elpi.vm-whd-all - use coq.reduction.vm.norm in place of coq.reduction.vm.whd_all , - coq.reduction.vm.norm A0 A1 A2. -coq.reduction.lazy.whd_all A0 A1 :- - get-option coq:redflags coq.redflags.all => coq.reduction.lazy.whd A0 A1. -coq.id->name A0 A1 :- coq.string->name A0 A1. -coq.elpi.accumulate A0 A1 A2 :- coq.elpi.accumulate-clauses A0 A1 [A2]. -true. -A0 ; _ :- A0. -_ ; A0 :- A0. -not A0 :- , A0 (!) fail. -not _. -stop :- halt. -A0 is A1 :- calc A1 A0. -A0 > A1 :- gt_ A0 A1. -A0 < A1 :- lt_ A0 A1. -A0 =< A1 :- le_ A0 A1. -A0 >= A1 :- ge_ A0 A1. -A0 i< A1 :- lt_ A0 A1. -A0 i> A1 :- gt_ A0 A1. -A0 i=< A1 :- le_ A0 A1. -A0 i>= A1 :- ge_ A0 A1. -A0 r< A1 :- lt_ A0 A1. -A0 r> A1 :- gt_ A0 A1. -A0 r=< A1 :- le_ A0 A1. -A0 r>= A1 :- ge_ A0 A1. -A0 s< A1 :- lt_ A0 A1. -A0 s> A1 :- gt_ A0 A1. -A0 s=< A1 :- le_ A0 A1. -A0 s>= A1 :- ge_ A0 A1. -fst (pr A0 _) A0. -snd (pr _ A0) A0. -counter A0 A1 :- trace.counter A0 A1. -rex_match A0 A1 :- rex.match A0 A1. -rex_replace A0 A1 A2 A3 :- rex.replace A0 A1 A2 A3. -rex_split A0 A1 A2 :- rex.split A0 A1 A2. -A0 == A1 :- same_term A0 A1. -primitive? A0 A1 :- is_cdata A0 (ctype A1). -if A0 A1 _ :- , A0 (!) A1. -if _ _ A0 :- A0. -if2 A0 A1 _ _ _ :- , A0 (!) A1. -if2 _ _ A0 A1 _ :- , A0 (!) A1. -if2 _ _ _ _ A0 :- ! , A0. -std.fatal-error A0 :- halt A0. -std.fatal-error-w-data A0 A1 :- halt A0 : A1. -std.debug-print A0 A1 :- print A0 A1. -std.ignore-failure! A0 :- A0 , !. -std.ignore-failure! _. -std.assert! A0 A1 :- (A0 ; std.fatal-error-w-data A1 A0) , !. -std.assert-ok! A0 A1 :- - , (A0 A2) (!) (A2 = ok ; A2 = error A3 , std.fatal-error-w-data A1 A3) (!). -std.assert-ok! _ A0 :- std.fatal-error-w-data A0 no diagnostic returned. -std.spy A0 :- - , (trace.counter run A1) (if (not (A1 = 0)) (std.debug-print run= A1) true) - (std.debug-print ----<<---- enter: A0) A0 - (std.debug-print ---->>---- exit: A0). -std.spy A0 :- std.debug-print ---->>---- fail: A0 , fail. -std.spy! A0 :- - , (trace.counter run A1) (if (not (A1 = 0)) (std.debug-print run= A1) true) - (std.debug-print ----<<---- enter: A0) A0 - (std.debug-print ---->>---- exit: A0) (!). -std.spy! A0 :- std.debug-print ---->>---- fail: A0 , fail. -std.unsafe-cast A0 A0. -std.length [_ | A0] A1 :- std.length A0 A2 , A1 is A2 + 1. -std.length [] 0. -std.rev A0 A1 :- std.rev.aux A0 [] A1. -std.rev.aux [A0 | A1] A2 A3 :- std.rev.aux A1 [A0 | A2] A3. -std.rev.aux [] A0 A0. -std.last [] _ :- std.fatal-error last on empty list. -std.last [A0] A0 :- !. -std.last [_ | A0] A1 :- std.last A0 A1. -std.append [A0 | A1] A2 [A0 | A3] :- std.append A1 A2 A3. -std.append [] A0 A0. -std.appendR [A0 | A1] A2 [A0 | A3] :- std.appendR A1 A2 A3. -std.appendR [] A0 A0. -std.take 0 _ [] :- !. -std.take A0 [A1 | A2] [A1 | A3] :- , (!) (A4 is A0 - 1) (std.take A4 A2 A3). -std.take _ _ _ :- std.fatal-error take run out of list items. -std.take-last A0 A1 A2 :- - , (std.length A1 A3) (A4 is A3 - A0) (std.drop A4 A1 A2). -std.drop 0 A0 A0 :- !. -std.drop A0 [_ | A1] A2 :- , (!) (A3 is A0 - 1) (std.drop A3 A1 A2). -std.drop _ _ _ :- std.fatal-error drop run out of list items. -std.drop-last A0 A1 A2 :- - , (std.length A1 A3) (A4 is A3 - A0) (std.take A4 A1 A2). -std.split-at 0 A0 [] A0 :- !. -std.split-at A0 [A1 | A2] [A1 | A3] A4 :- - , (!) (A5 is A0 - 1) (std.split-at A5 A2 A3 A4). -std.split-at _ _ _ _ :- std.fatal-error split-at run out of list items. -std.fold [] A0 _ A0. -std.fold [A0 | A1] A2 A3 A4 :- A3 A0 A2 A5 , std.fold A1 A5 A3 A4. -std.fold-right [] A0 _ A0. -std.fold-right [A0 | A1] A2 A3 A4 :- std.fold-right A1 A2 A3 A5 , A3 A0 A5 A4. -std.fold2 [] [_ | _] _ _ _ :- - std.fatal-error fold2 on lists of different length. -std.fold2 [_ | _] [] _ _ _ :- - std.fatal-error fold2 on lists of different length. -std.fold2 [] [] A0 _ A0. -std.fold2 [A0 | A1] [A2 | A3] A4 A5 A6 :- - A5 A0 A2 A4 A7 , std.fold2 A1 A3 A7 A5 A6. -std.map [] _ []. -std.map [A0 | A1] A2 [A3 | A4] :- A2 A0 A3 , std.map A1 A2 A4. -std.map-i A0 A1 A2 :- std.map-i.aux A0 0 A1 A2. -std.map-i.aux [] _ _ []. -std.map-i.aux [A0 | A1] A2 A3 [A4 | A5] :- - , (A3 A2 A0 A4) (A6 is A2 + 1) (std.map-i.aux A1 A6 A3 A5). -std.map-filter [] _ []. -std.map-filter [A0 | A1] A2 [A3 | A4] :- - , (A2 A0 A3) (!) (std.map-filter A1 A2 A4). -std.map-filter [_ | A0] A1 A2 :- std.map-filter A0 A1 A2. -std.map2 [] [_ | _] _ _ :- std.fatal-error map2 on lists of different length. -std.map2 [_ | _] [] _ _ :- std.fatal-error map2 on lists of different length. -std.map2 [] [] _ []. -std.map2 [A0 | A1] [A2 | A3] A4 [A5 | A6] :- - A4 A0 A2 A5 , std.map2 A1 A3 A4 A6. -std.map2-filter [] [_ | _] _ _ :- - std.fatal-error map2-filter on lists of different length. -std.map2-filter [_ | _] [] _ _ :- - std.fatal-error map2-filter on lists of different length. -std.map2-filter [] [] _ []. -std.map2-filter [A0 | A1] [A2 | A3] A4 [A5 | A6] :- - , (A4 A0 A2 A5) (!) (std.map2-filter A1 A3 A4 A6). -std.map2-filter [_ | A0] [_ | A1] A2 A3 :- std.map2-filter A0 A1 A2 A3. -std.map-ok [A0 | A1] A2 [A3 | A4] A5 :- - A2 A0 A3 A6 , if (A6 = ok) (std.map-ok A1 A2 A4 A5) (A5 = A6). -std.map-ok [] _ [] ok. -std.fold-map [] A0 _ [] A0. -std.fold-map [A0 | A1] A2 A3 [A4 | A5] A6 :- - A3 A0 A2 A4 A7 , std.fold-map A1 A7 A3 A5 A6. -std.omap none _ none. -std.omap (some A0) A1 (some A2) :- A1 A0 A2. -std.nth 0 [A0 | _] A1 :- ! , A0 = A1. -std.nth A0 [_ | A1] A2 :- , (A0 > 0) (!) (A3 is A0 - 1) (std.nth A3 A1 A2). -std.nth A0 _ _ :- , (A0 < 0) (!) (std.fatal-error nth got a negative index). -std.nth _ _ _ :- std.fatal-error nth run out of list items. -std.lookup [pr A0 A1 | _] A0 A1. -std.lookup [_ | A0] A1 A2 :- std.lookup A0 A1 A2. -std.lookup! [pr A0 A1 | _] A0 A1 :- !. -std.lookup! [_ | A0] A1 A2 :- std.lookup! A0 A1 A2. -std.mem! [A0 | _] A0 :- !. -std.mem! [_ | A0] A1 :- std.mem! A0 A1. -std.mem [A0 | _] A0. -std.mem [_ | A0] A1 :- std.mem A0 A1. -std.exists [A0 | _] A1 :- A1 A0. -std.exists [_ | A0] A1 :- std.exists A0 A1. -std.exists2 [] [_ | _] _ :- - std.fatal-error exists2 on lists of different length. -std.exists2 [_ | _] [] _ :- - std.fatal-error exists2 on lists of different length. -std.exists2 [A0 | _] [A1 | _] A2 :- A2 A0 A1. -std.exists2 [_ | A0] [_ | A1] A2 :- std.exists2 A0 A1 A2. -std.forall [] _. -std.forall [A0 | A1] A2 :- A2 A0 , std.forall A1 A2. -std.forall-ok [A0 | A1] A2 A3 :- - A2 A0 A4 , if (A4 = ok) (std.forall-ok A1 A2 A3) (A3 = A4). -std.forall-ok [] _ ok. -std.forall2 [] [_ | _] _ :- - std.fatal-error forall2 on lists of different length. -std.forall2 [_ | _] [] _ :- - std.fatal-error forall2 on lists of different length. -std.forall2 [A0 | A1] [A2 | A3] A4 :- A4 A0 A2 , std.forall2 A1 A3 A4. -std.forall2 [] [] _. -std.filter [] _ []. -std.filter [A0 | A1] A2 A3 :- - if (A2 A0) (A3 = [A0 | A4]) (A3 = A4) , std.filter A1 A2 A4. -std.zip [_ | _] [] _ :- std.fatal-error zip on lists of different length. -std.zip [] [_ | _] _ :- std.fatal-error zip on lists of different length. -std.zip [A0 | A1] [A2 | A3] [pr A0 A2 | A4] :- std.zip A1 A3 A4. -std.zip [] [] []. -std.unzip [] [] []. -std.unzip [pr A0 A1 | A2] [A0 | A3] [A1 | A4] :- std.unzip A2 A3 A4. -std.flatten [A0 | A1] A2 :- std.flatten A1 A3 , std.append A0 A3 A2. -std.flatten [] []. -std.null []. -std.iota A0 A1 :- std.iota.aux 0 A0 A1. -std.iota.aux A0 A0 [] :- !. -std.iota.aux A0 A1 [A0 | A2] :- A3 is A0 + 1 , std.iota.aux A3 A1 A2. -std.intersperse _ [] []. -std.intersperse _ [A0] [A0] :- !. -std.intersperse A0 [A1 | A2] [A1, A0 | A3] :- std.intersperse A0 A2 A3. -std.flip A0 A1 A2 :- A0 A2 A1. -std.time A0 A1 :- , (gettimeofday A2) A0 (gettimeofday A3) (A1 is A3 - A2). -std.do! []. -std.do! [A0 | A1] :- , A0 (!) (std.do! A1). -std.do-ok! ok []. -std.do-ok! A0 [A1 | A2] :- - , (A1 A3) (!) (if (A3 = ok) (std.do-ok! A0 A2) (A0 = A3)). -std.lift-ok A0 A1 A2 :- A0 , A2 = ok ; A2 = error A1. -std.spy-do! A0 :- std.map A0 (c0 \ c1 \ c1 = std.spy c0) A1 , std.do! A1. -std.while-ok-do! (as (error _) A0) _ A0. -std.while-ok-do! ok [] ok. -std.while-ok-do! ok [A0 | A1] A2 :- , (A0 A3) (!) (std.while-ok-do! A3 A1 A2). -std.any->string A0 A1 :- term_to_string A0 A1. -std.max A0 A1 A0 :- A0 >= A1 , !. -std.max _ A0 A0. -std.findall A0 A1 :- findall_solutions A0 A1. -std.map.make A0 (std.map std.map.private.empty A0). -std.map.find A0 (std.map A1 A2) A3 :- std.map.private.find A1 A2 A0 A3. -std.map.add A0 A1 (std.map A2 A3) (std.map A4 A3) :- - std.map.private.add A2 A3 A0 A1 A4. -std.map.remove A0 (std.map A1 A2) (std.map A3 A2) :- - std.map.private.remove A1 A2 A0 A3. -std.map.bindings (std.map A0 _) A1 :- std.map.private.bindings A0 [] A1. -std.map.private.height std.map.private.empty 0. -std.map.private.height (std.map.private.node _ _ _ _ A0) A0. -std.map.private.create A0 A1 A2 A3 (std.map.private.node A0 A1 A2 A3 A4) :- - , (std.map.private.height A0 A5) (std.map.private.height A3 A6) - (std.max A5 A6 A7) (A4 is A7 + 1). -std.map.private.bal A0 A1 A2 A3 A4 :- - , (std.map.private.height A0 A5) (std.map.private.height A3 A6) - (A7 is A5 + 2) (A8 is A6 + 2) - (std.map.private.bal.aux A5 A6 A7 A8 A0 A1 A2 A3 A4). -std.map.private.bal.aux A0 _ _ A1 (std.map.private.node A2 A3 A4 A5 _) A6 A7 - A8 A9 :- - , (A0 > A1) - (, (std.map.private.height A2 A11) (std.map.private.height A5 A12) - (A11 >= A12)) (!) - (std.map.private.create A5 A6 A7 A8 A10 , - std.map.private.create A2 A3 A4 A10 A9). -std.map.private.bal.aux A0 _ _ A1 - (std.map.private.node A2 A3 A4 (std.map.private.node A5 A6 A7 A8 _) _) A9 - A10 A11 A12 :- - , (A0 > A1) (!) - (, (std.map.private.create A2 A3 A4 A5 A13) - (std.map.private.create A8 A9 A10 A11 A14) - (std.map.private.create A13 A6 A7 A14 A12)). -std.map.private.bal.aux _ A0 A1 _ A2 A3 A4 - (std.map.private.node A5 A6 A7 A8 _) A9 :- - , (A0 > A1) - (, (std.map.private.height A8 A11) (std.map.private.height A5 A12) - (A11 >= A12)) (!) - (std.map.private.create A2 A3 A4 A5 A10 , - std.map.private.create A10 A6 A7 A8 A9). -std.map.private.bal.aux _ A0 A1 _ A2 A3 A4 - (std.map.private.node (std.map.private.node A5 A6 A7 A8 _) A9 A10 A11 _) A12 - :- - , (A0 > A1) (!) - (, (std.map.private.create A2 A3 A4 A5 A13) - (std.map.private.create A8 A9 A10 A11 A14) - (std.map.private.create A13 A6 A7 A14 A12)). -std.map.private.bal.aux _ _ _ _ A0 A1 A2 A3 A4 :- - std.map.private.create A0 A1 A2 A3 A4. -std.map.private.add std.map.private.empty _ A0 A1 A2 :- - std.map.private.create std.map.private.empty A0 A1 std.map.private.empty A2. -std.map.private.add (as (std.map.private.node _ A0 _ _ _) A1) A2 A3 A4 A5 :- - A2 A3 A0 A6 , std.map.private.add.aux A6 A1 A2 A3 A4 A5. -std.map.private.add.aux eq (std.map.private.node A0 _ _ A1 A2) _ A3 A4 A5 :- - A5 = std.map.private.node A0 A3 A4 A1 A2. -std.map.private.add.aux lt (std.map.private.node A0 A1 A2 A3 _) A4 A5 A6 A7 - :- std.map.private.add A0 A4 A5 A6 A8 , std.map.private.bal A8 A1 A2 A3 A7. -std.map.private.add.aux gt (std.map.private.node A0 A1 A2 A3 _) A4 A5 A6 A7 - :- std.map.private.add A3 A4 A5 A6 A8 , std.map.private.bal A0 A1 A2 A8 A7. -std.map.private.find (std.map.private.node A0 A1 A2 A3 _) A4 A5 A6 :- - A4 A5 A1 A7 , std.map.private.find.aux A7 A4 A0 A3 A2 A5 A6. -std.map.private.find.aux eq _ _ _ A0 _ A0. -std.map.private.find.aux lt A0 A1 _ _ A2 A3 :- - std.map.private.find A1 A0 A2 A3. -std.map.private.find.aux gt A0 _ A1 _ A2 A3 :- - std.map.private.find A1 A0 A2 A3. -std.map.private.remove-min-binding - (std.map.private.node std.map.private.empty _ _ A0 _) A0 :- !. -std.map.private.remove-min-binding (std.map.private.node A0 A1 A2 A3 _) A4 :- - std.map.private.remove-min-binding A0 A5 , - std.map.private.bal A5 A1 A2 A3 A4. -std.map.private.min-binding - (std.map.private.node std.map.private.empty A0 A1 _ _) A0 A1 :- !. -std.map.private.min-binding (std.map.private.node A0 _ _ _ _) A1 A2 :- - std.map.private.min-binding A0 A1 A2. -std.map.private.merge std.map.private.empty A0 A0 :- !. -std.map.private.merge A0 std.map.private.empty A0 :- !. -std.map.private.merge A0 A1 A2 :- - std.map.private.min-binding A1 A3 A4 , - std.map.private.remove-min-binding A1 A5 , - std.map.private.bal A0 A3 A4 A5 A2. -std.map.private.remove std.map.private.empty _ _ std.map.private.empty :- !. -std.map.private.remove (std.map.private.node A0 A1 A2 A3 _) A4 A5 A6 :- - A4 A5 A1 A7 , std.map.private.remove.aux A7 A4 A0 A3 A1 A2 A5 A6. -std.map.private.remove.aux eq _ A0 A1 _ _ _ A2 :- - std.map.private.merge A0 A1 A2. -std.map.private.remove.aux lt A0 A1 A2 A3 A4 A5 A6 :- - std.map.private.remove A1 A0 A5 A7 , std.map.private.bal A7 A3 A4 A2 A6. -std.map.private.remove.aux gt A0 A1 A2 A3 A4 A5 A6 :- - std.map.private.remove A2 A0 A5 A7 , std.map.private.bal A1 A3 A4 A7 A6. -std.map.private.bindings std.map.private.empty A0 A0. -std.map.private.bindings (std.map.private.node A0 A1 A2 A3 _) A4 A5 :- - std.map.private.bindings A3 A4 A6 , - std.map.private.bindings A0 [pr A1 A2 | A6] A5. -std.set.make A0 (std.set std.set.private.empty A0). -std.set.mem A0 (std.set A1 A2) :- std.set.private.mem A1 A2 A0. -std.set.add A0 (std.set A1 A2) (std.set A3 A2) :- - std.set.private.add A1 A2 A0 A3. -std.set.remove A0 (std.set A1 A2) (std.set A3 A2) :- - std.set.private.remove A1 A2 A0 A3. -std.set.cardinal (std.set A0 _) A1 :- std.set.private.cardinal A0 A1. -std.set.elements (std.set A0 _) A1 :- std.set.private.elements A0 [] A1. -std.set.private.height std.set.private.empty 0. -std.set.private.height (std.set.private.node _ _ _ A0) A0. -std.set.private.create A0 A1 A2 (std.set.private.node A0 A1 A2 A3) :- - , (std.set.private.height A0 A4) (std.set.private.height A2 A5) - (std.max A4 A5 A6) (A3 is A6 + 1). -std.set.private.bal A0 A1 A2 A3 :- - , (std.set.private.height A0 A4) (std.set.private.height A2 A5) - (A6 is A4 + 2) (A7 is A5 + 2) - (std.set.private.bal.aux A4 A5 A6 A7 A0 A1 A2 A3). -std.set.private.bal.aux A0 _ _ A1 (std.set.private.node A2 A3 A4 _) A5 A6 A7 - :- - , (A0 > A1) - (, (std.set.private.height A2 A9) (std.set.private.height A4 A10) - (A9 >= A10)) (!) - (std.set.private.create A4 A5 A6 A8 , std.set.private.create A2 A3 A8 A7). -std.set.private.bal.aux A0 _ _ A1 - (std.set.private.node A2 A3 (std.set.private.node A4 A5 A6 _) _) A7 A8 A9 :- - , (A0 > A1) (!) - (, (std.set.private.create A2 A3 A4 A10) - (std.set.private.create A6 A7 A8 A11) - (std.set.private.create A10 A5 A11 A9)). -std.set.private.bal.aux _ A0 A1 _ A2 A3 (std.set.private.node A4 A5 A6 _) A7 - :- - , (A0 > A1) - (, (std.set.private.height A6 A9) (std.set.private.height A4 A10) - (A9 >= A10)) (!) - (std.set.private.create A2 A3 A4 A8 , std.set.private.create A8 A5 A6 A7). -std.set.private.bal.aux _ A0 A1 _ A2 A3 - (std.set.private.node (std.set.private.node A4 A5 A6 _) A7 A8 _) A9 :- - , (A0 > A1) (!) - (, (std.set.private.create A2 A3 A4 A10) - (std.set.private.create A6 A7 A8 A11) - (std.set.private.create A10 A5 A11 A9)). -std.set.private.bal.aux _ _ _ _ A0 A1 A2 A3 :- - std.set.private.create A0 A1 A2 A3. -std.set.private.add std.set.private.empty _ A0 A1 :- - std.set.private.create std.set.private.empty A0 std.set.private.empty A1. -std.set.private.add (std.set.private.node A0 A1 A2 A3) A4 A5 A6 :- - A4 A5 A1 A7 , std.set.private.add.aux A7 A4 A0 A2 A1 A5 A3 A6. -std.set.private.add.aux eq _ A0 A1 A2 _ A3 (std.set.private.node A0 A2 A1 A3). -std.set.private.add.aux lt A0 A1 A2 A3 A4 _ A5 :- - std.set.private.add A1 A0 A4 A6 , std.set.private.bal A6 A3 A2 A5. -std.set.private.add.aux gt A0 A1 A2 A3 A4 _ A5 :- - std.set.private.add A2 A0 A4 A6 , std.set.private.bal A1 A3 A6 A5. -std.set.private.mem (std.set.private.node A0 A1 A2 _) A3 A4 :- - A3 A4 A1 A5 , std.set.private.mem.aux A5 A3 A0 A2 A4. -std.set.private.mem.aux eq _ _ _ _. -std.set.private.mem.aux lt A0 A1 _ A2 :- std.set.private.mem A1 A0 A2. -std.set.private.mem.aux gt A0 _ A1 A2 :- std.set.private.mem A1 A0 A2. -std.set.private.remove-min-binding - (std.set.private.node std.set.private.empty _ A0 _) A0 :- !. -std.set.private.remove-min-binding (std.set.private.node A0 A1 A2 _) A3 :- - std.set.private.remove-min-binding A0 A4 , std.set.private.bal A4 A1 A2 A3. -std.set.private.min-binding - (std.set.private.node std.set.private.empty A0 _ _) A0 :- !. -std.set.private.min-binding (std.set.private.node A0 _ _ _) A1 :- - std.set.private.min-binding A0 A1. -std.set.private.merge std.set.private.empty A0 A0 :- !. -std.set.private.merge A0 std.set.private.empty A0 :- !. -std.set.private.merge A0 A1 A2 :- - std.set.private.min-binding A1 A3 , - std.set.private.remove-min-binding A1 A4 , std.set.private.bal A0 A3 A4 A2. -std.set.private.remove std.set.private.empty _ _ std.set.private.empty. -std.set.private.remove (std.set.private.node A0 A1 A2 _) A3 A4 A5 :- - A3 A4 A1 A6 , std.set.private.remove.aux A6 A3 A0 A2 A1 A4 A5. -std.set.private.remove.aux eq _ A0 A1 _ _ A2 :- - std.set.private.merge A0 A1 A2. -std.set.private.remove.aux lt A0 A1 A2 A3 A4 A5 :- - std.set.private.remove A1 A0 A4 A6 , std.set.private.bal A6 A3 A2 A5. -std.set.private.remove.aux gt A0 A1 A2 A3 A4 A5 :- - std.set.private.remove A2 A0 A4 A6 , std.set.private.bal A1 A3 A6 A5. -std.set.private.cardinal std.set.private.empty 0. -std.set.private.cardinal (std.set.private.node A0 _ A1 _) A2 :- - , (std.set.private.cardinal A0 A3) (std.set.private.cardinal A1 A4) - (A2 is A3 + 1 + A4). -std.set.private.elements std.set.private.empty A0 A0. -std.set.private.elements (std.set.private.node A0 A1 A2 _) A3 A4 :- - std.set.private.elements A2 A3 A5 , std.set.private.elements A0 [A1 | A5] A4. -printterm A0 A1 :- term_to_string A1 A2 , output A0 A2. -read A0 :- , (flush std_out) (input_line std_in A1) (string_to_term A1 A0). -p before 2. -p before 22. -p before 1. -p before 11. -p init 0. -p after 11. -p after 1. -p after 22. -p after 2. diff --git a/tests/toposort.t/run.t b/tests/toposort.t/run.t new file mode 100644 index 000000000..8e12cbc1c --- /dev/null +++ b/tests/toposort.t/run.t @@ -0,0 +1,2 @@ + $ . ../setup-project.sh + $ dune build test.vo diff --git a/tests/test_toposort.v b/tests/toposort.t/test.v similarity index 100% rename from tests/test_toposort.v rename to tests/toposort.t/test.v diff --git a/tests/tutorial_coq_elpi_HOAS.t/run.t b/tests/tutorial_coq_elpi_HOAS.t/run.t new file mode 100644 index 000000000..74fce2017 --- /dev/null +++ b/tests/tutorial_coq_elpi_HOAS.t/run.t @@ -0,0 +1,335 @@ + $ . ../setup-project.sh + $ dune build test.vo + Query assignments: + GRnat = indt «nat» + GRplus = const «Nat.add» + GRs = indc «S» + Query assignments: + Bo = app [global (indc «S»), app [global (indc «S»), global (indc «O»)]] + C = «x» + GR = const «x» + Ty = global (indt «nat») + TyC = global (indt «nat») + Query assignments: + Bo = fun `x` (global (indt «nat»)) c0 \ c0 + C = «f» + Query assignments: + Bo = fix `add` 0 + (prod `n` (global (indt «nat»)) c0 \ + prod `m` (global (indt «nat»)) c1 \ global (indt «nat»)) c0 \ + fun `n` (global (indt «nat»)) c1 \ + fun `m` (global (indt «nat»)) c2 \ + match c1 (fun `n` (global (indt «nat»)) c3 \ global (indt «nat»)) + [c2, + fun `p` (global (indt «nat»)) c3 \ + app [global (indc «S»), app [c0, c3, c2]]] + C = «Nat.add» + The return type of m is: c0 \ c1 \ + fun `x` (global (indt «nat»)) c2 \ + fun `e` + (app [global (indt «eq»), global (indt «nat»), global (indc «O»), c2]) + c3 \ prod `_` (app [c1, global (indc «O»)]) c4 \ app [c1, c2] + Query assignments: + C = «m» + RT = c0 \ c1 \ + fun `x` (global (indt «nat»)) c2 \ + fun `e` + (app [global (indt «eq»), global (indt «nat»), global (indc «O»), c2]) + c3 \ prod `_` (app [c1, global (indc «O»)]) c4 \ app [c1, c2] + typ «test.test.6» < typ «test.test.7» + Debug: Cannot enforce test.test.7 <= test.test.6 because test.test.6 + < test.test.7 + Query assignments: + U = typ «test.test.6» + U1 = typ «test.test.7» + Universe constraints: + UNIVERSES: + {test.test.7 test.test.6} |= test.test.6 < test.test.7 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + + WEAK CONSTRAINTS: + + + (id b) is: app [fun `x` (sort (typ X0)) c0 \ c0, sort (typ X1)] + (id a) is illtyped: + Illegal application: + The term "fun x : Type => x" of type "Type -> Type" + cannot be applied to the term + "Type" : "Type" + This term has type "Type@{test.test.8+1}" which should be a subtype of + "Type@{test.test.8}". + (universe inconsistency: Cannot enforce test.test.8 < test.test.8 because + test.test.8 = test.test.8) + after typing (id b) is: + app + [fun `x` (sort (typ «test.test.8»)) c0 \ c0, sort (typ «test.test.9»)] + : sort (typ «test.test.8») + Universe constraints: UNIVERSES: + {test.test.9 test.test.8} |= test.test.9 < test.test.8 + ALGEBRAIC UNIVERSES: + {test.test.9 test.test.8} + FLEXIBLE UNIVERSES: + test.test.9 + test.test.8 + SORTS: + + WEAK CONSTRAINTS: + + + Query assignments: + A = sort (typ «test.test.8») + B = sort (typ «test.test.9») + ErrMsg = Illegal application: + The term "fun x : Type => x" of type "Type -> Type" + cannot be applied to the term + "Type" : "Type" + This term has type "Type@{test.test.8+1}" which should be a subtype of + "Type@{test.test.8}". + (universe inconsistency: Cannot enforce test.test.8 < test.test.8 because + test.test.8 = test.test.8) + ID = fun `x` (sort (typ «test.test.8»)) c0 \ c0 + T = sort (typ «test.test.8») + U = «test.test.8» + V = «test.test.9» + Universe constraints: + UNIVERSES: + {test.test.9 test.test.8} |= test.test.9 < test.test.8 + ALGEBRAIC UNIVERSES: + {test.test.9 test.test.8} + FLEXIBLE UNIVERSES: + test.test.9 + test.test.8 + SORTS: + + WEAK CONSTRAINTS: + + + app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + = + app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]] + app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + app [global (indc «S»), global (indc «O»)]] + Query assignments: + S = indc «S» + fun `x` (global (indt «nat»)) c0 \ + fun `x` (global (indt «nat»)) c1 \ + app [global (const «Nat.add»), c1, c0] + fun `x` (global (indt «nat»)) c0 \ + fun `x` (global (indt «nat»)) c1 \ + app [global (const «Nat.add»), c1, c0] + fun `a` (global (indt «nat»)) c0 \ + fun `b` (global (indt «nat»)) c1 \ + app [global (const «Nat.add»), c1, c0] + Query assignments: + X = c0 \ c1 \ + app [global (const «Nat.add»), c1, c0] + fun `a` (global (indt «nat»)) c0 \ + fun `b` (global (indt «nat»)) c1 \ + app [global (indt «eq»), global (indt «nat»), c0, c1] + indt «nat» + indt «nat» + before: + fun `ax` (global (indt «nat»)) c0 \ + fun `b` (global (indt «nat»)) c1 \ + app [global (indt «eq»), X0 c1, c0, c1] + after: + fun `ax` (global (indt «nat»)) c0 \ + fun `b` (global (indt «nat»)) c1 \ + app [global (indt «eq»), global (indt «nat»), c0, c1] + Query assignments: + T = fun `ax` (global (indt «nat»)) c0 \ + fun `b` (global (indt «nat»)) c1 \ + app [global (indt «eq»), global (indt «nat»), c0, c1] + _uvk_1_ = c0 \ + global (indt «nat») + Universe constraints: + UNIVERSES: + {test.test.11 test.test.10} |= + test.test.11 < test.test.10 + Set <= test.test.11 + test.test.11 <= eq.u0 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α6 := Type + WEAK CONSTRAINTS: + + + Query assignments: + Bo = c0 \ + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]] + N = `x` + T = fun `x` (global (indt «nat»)) c0 \ + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]] + Ty = global (indt «nat») + Query assignments: + Bo = c0 \ + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]] + N = `x` + T = fun `x` (global (indt «nat»)) c0 \ + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]] + Ty = global (indt «nat») + raw T = X0 + + SHELF: + FUTURE GOALS STACK: + + + Coq-Elpi mapping: + RAW: + ELAB: + + -------------------------------- + evar (X1) (global (indt «nat»)) (X1) /* suspended on X1 */ + EVARS: + ?X11==[ |- nat] (internal placeholder) {?e0} + ?X10==[ |- => nat] (internal placeholder) + + SHELF: + FUTURE GOALS STACK: + ?X11 + + Coq-Elpi mapping: + RAW: + ?X11 <-> X1 + ELAB: + ?X11 <-> X1 + + Query assignments: + T = X1 + _uvk_4_ = X1 + Syntactic constraints: + evar (X1) (global (indt «nat»)) (X1) /* suspended on X1 */ + Universe constraints: + UNIVERSES: + {test.test.12} |= Set <= test.test.12 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α7 := Type + WEAK CONSTRAINTS: + + + raw T = + fun `x` (global (indt «nat»)) c0 \ + app [global (const «Nat.add»), c0, X0 c0] + {c0 c1} : decl c1 `x` (global (indt «nat»)) + ?- evar (X1 c1) (global (indt «nat»)) (X1 c1) /* suspended on X1 */ + EVARS: + ?X13==[x |- nat] (internal placeholder) {?e0} + ?X12==[x |- => nat] (internal placeholder) + + SHELF: + FUTURE GOALS STACK: + ?X13 + + Coq-Elpi mapping: + RAW: + ?X13 <-> c0 \ X1 c0 + ELAB: + ?X13 <-> X1 + + Query assignments: + Bo = c0 \ + app [global (const «Nat.add»), c0, X1 c0] + N = `x` + T = fun `x` (global (indt «nat»)) c0 \ + app [global (const «Nat.add»), c0, X1 c0] + Ty = global (indt «nat») + _uvk_9_ = c0 \ + X1 c0 + Syntactic constraints: + {c0 c1} : decl c1 `x` (global (indt «nat»)) + ?- evar (X1 c1) (global (indt «nat»)) (X1 c1) /* suspended on X1 */ + Universe constraints: + UNIVERSES: + {test.test.13} |= Set <= test.test.13 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α8 := Type + WEAK CONSTRAINTS: + + + Bo1 (not in pattern fragment) = + app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + X0 (app [global (indc «S»), global (indc «O»)])] + Bo1 before = + app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], + X0 (app [global (indc «S»), global (indc «O»)])] + Bo1 after = + app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], X1] + Query assignments: + Bo = c0 \ + app [global (const «Nat.add»), c0, X1] + Bo1 = app + [global (const «Nat.add»), + app [global (indc «S»), global (indc «O»)], X1] + N = `x` + T = fun `x` (global (indt «nat»)) c0 \ app [global (const «Nat.add»), c0, X1] + Ty = global (indt «nat») + _uvk_15_ = c0 \ + X1 + Syntactic constraints: + evar (X1) (global (indt «nat»)) (X1) /* suspended on X1 */ + Universe constraints: + UNIVERSES: + {test.test.14} |= Set <= test.test.14 + ALGEBRAIC UNIVERSES: + {} + FLEXIBLE UNIVERSES: + + SORTS: + α9 := Type + WEAK CONSTRAINTS: + + + Query assignments: + Bo = c0 \ + app [global (const «andb»), c0, X0 c0] + Bo1 = app + [global (const «andb»), app [global (indc «S»), global (indc «O»)], + X0 (app [global (indc «S»), global (indc «O»)])] + Bo2 = app + [global (const «andb»), + app + [global (const «nat2bool»), + app [global (indc «S»), global (indc «O»)]], X1] + N = `x` + T = fun `x` (global (indt «nat»)) c0 \ app [global (const «andb»), c0, X0 c0] + Ty = global (indt «nat») + _uvk_21_ = X0 + Syntactic constraints: + evar (X2) (global (indt «bool»)) X1 /* suspended on X2, X1 */ diff --git a/tests/tutorial_coq_elpi_HOAS.t/test.v b/tests/tutorial_coq_elpi_HOAS.t/test.v new file mode 100644 index 000000000..1c92d9462 --- /dev/null +++ b/tests/tutorial_coq_elpi_HOAS.t/test.v @@ -0,0 +1,780 @@ +(*| + +Tutorial on the HOAS for Coq terms +********************************** + +:author: Enrico Tassi + +.. include:: ../etc/tutorial_style.rst + +.. + Elpi is an extension language that comes as a library + to be embedded into host applications such as Coq. + + Elpi is a variant of λProlog enriched with constraints. + λProlog is a programming language designed to make it easy + to manipulate abstract syntax trees containing binders. + Elpi extends λProlog with programming constructs that are + designed to make it easy to manipulate abstract syntax trees + containing metavariables (also called unification variables, or + evars in the Coq jargon). + + This software, "coq-elpi", is a Coq plugin embedding Elpi and + exposing to the extension language Coq spefic data types (e.g. terms) + and API (e.g. to declare a new inductive type). + + In order to get proper syntax highlighting using VSCode please install the + "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in + Edit -> Preferences -> Colors. + + +This tutorial focuses on the integration of Elpi within Coq, in particular +it describes how Coq terms are exposed to Elpi programs and how Coq APIs can +be called. + +This tutorial assumes the reader is familiar with Elpi and HOAS; if it is not +the case, please take a look at the +`Elpi tutorial `_ +first. + +.. contents:: + +================ +HOAS for Gallina +================ + +|*) + +From elpi Require Import elpi. (* .none *) + +Elpi Command tutorial_HOAS. (* .none *) + +(*| + +The full syntax of Coq terms can be found in +`coq-builtin.elpi `_ +together with a detailed documentation of the encoding of contexts and the +APIs one can use to interact with Coq. This tutorial, and the two more +that focus on commands and tactics, are a gentle introduction to all that. + +We defer to later quotations and antiquotations: syntactic features that +let one write terms in Coq's native syntax. Here we focus on the abstract +syntax tree of Coq terms. + +----------------------- +Constructor :e:`global` +----------------------- + +Let's start with the :type:`gref` data type (for global rerence). + +.. code:: elpi + + type const constant -> gref. + type indt inductive -> gref. + type indc constructor -> gref. + +:type:`constant`, :type:`inductive` and :type:`constructor` are Coq specific +data types that are opaque to Elpi. Still the :type:`gref` data type lets you +see what these names point to (a constant, and inductive type or a +constructor). + +The :builtin:`coq.locate` API resolves a string to a :type:`gref`. + +|*) + +Elpi Query lp:{{ + + coq.locate "nat" GRnat, + coq.locate "S" GRs, + coq.locate "plus" GRplus + +}}. + +(*| + +The :e:`coq.env.*` family of APIs lets one access the +environment of well typed Coq terms that have a global name. + +|*) + +Definition x := 2. + +Elpi Query lp:{{ + + coq.locate "x" GR, + + % all global references have a type + coq.env.typeof GR Ty, + + % destruct GR to obtain its constant part C + GR = const C, + + % constants may have a body, do have a type + coq.env.const C (some Bo) TyC + +}}. + +(*| + +An expression like :e:`indt «nat»` is not a Coq term (or better a type) yet. + +The :constructor:`global` term constructor turns a :type:`gref` into an +actual :type:`term`. + +.. code:: elpi + + type global gref -> term. + +---------------------------------- +Constructors :e:`app` and :e:`fun` +---------------------------------- + +The :constructor:`app` term constructor takes a list of terms and builds +the (n-ary) application. The first term is the head, while the others +are the arguments. + +For example :e:`app [global (indc «S»), global (indc «O»)]` is +the representation of `1`. + +.. code:: elpi + + type app list term -> term. + +Let's move to binders! + +|*) + +Definition f := fun x : nat => x. + +Elpi Query lp:{{ + + coq.locate "f" (const C), + coq.env.const C (some Bo) _ + +}}. + +(*| + +The :constructor:`fun` constructor carries a pretty printing hint ```x```, +the type of the bound variable `nat` and a function describing the body: + +.. code:: elpi + + type fun name -> term -> (term -> term) -> term. + +.. note:: :type:`name` is just for pretty printing: in spite of carrying + a value in the Coq world, it has no content in Elpi (like the unit type) + + Elpi terms of type :type:`name` are just identifiers + written between ````` (backticks). + + .. coq:: + + Elpi Query lp:{{ + + fun `foo` T B = fun `bar` T B % names don't matter + + }}. + + API such as :builtin:`coq.name-suffix` lets one craft a family of + names starting from one, eg ``coq.name-suffix `H` 1 N`` sets :e:`N` + to ```H1```. + +------------------------------------ +Constructors :e:`fix` and :e:`match` +------------------------------------ + +The other binders :constructor:`prod` (Coq's `forall`, AKA `Π`) and :constructor:`let` are similar, +so let's rather focus on :constructor:`fix` here. + +|*) + +Elpi Query lp:{{ + + coq.locate "plus" (const C), + coq.env.const C (some Bo) _ + +}}. + +(*| + +The :constructor:`fix` constructor carries a pretty printing hint, +the number of the recursive argument (starting at :e:`0`), the type +of the recursive function and finally the body where the recursive +call is represented via a bound variable + +.. code:: elpi + + type fix name -> int -> term -> (term -> term) -> term. + +A :constructor:`match` constructor carries the term being inspected, +the return clause +and a list of branches. Each branch is a Coq function expecting in input +the arguments of the corresponding constructor. The order follows the +order of the constructors in the inductive type declaration. + +.. code:: elpi + + type match term -> term -> list term -> term. + +The return clause is represented as a Coq function expecting in input +the indexes of the inductive type, the inspected term and generating the +type of the branches. + +|*) + +Definition m (h : 0 = 1 ) P : P 0 -> P 1 := + match h as e in eq _ x return P 0 -> P x + with eq_refl => fun (p : P 0) => p end. + +Elpi Query lp:{{ + +coq.locate "m" (const C), +coq.env.const C (some (fun _ _ h\ fun _ _ p\ match _ (RT h p) _)) _, +coq.say "The return type of m is:" RT + +}}. + + +(*| + +--------------------- +Constructor :e:`sort` +--------------------- + +The last term constructor worth discussing is :constructor:`sort`. + +.. code:: elpi + + type sort universe -> term. + type prop universe. + type typ univ -> universe. + +The opaque type :type:`univ` is a universe level variable. Elpi holds a store of +constraints among these variables and provides APIs named :e:`coq.univ.*` to +impose constraints. + +|*) + +Elpi Query lp:{{ + + coq.sort.sup U U1, + coq.say U "<" U1, + % This constraint can't be allowed in the store! + not(coq.sort.leq U1 U) + +}}. + +(*| + +.. note:: the user is not expected to declare universe constraints by hand + + The type checking primitives update the store of constraints + automatically and put Coq universe variables in place of Elpi's unification + variables (:e:`U` and :e:`V` below). + +Let's play a bit more with universe constraints using the +:builtin:`coq.typecheck` API: + +|*) + +Elpi Query lp:{{ + + ID = (fun `x` (sort (typ U)) x\ x), + A = (sort (typ U)), % the same U as before + B = (sort (typ V)), + coq.say "(id b) is:" (app [ID, B]), + + % error, since U : U is not valid + coq.typecheck (app [ID, A]) T (error ErrMsg), + coq.say "(id a) is illtyped:" ErrMsg, + + % ok, since V : U is possible + coq.typecheck (app [ID, B]) T ok, + + % remark: U and V are now Coq's univ with constraints + coq.say "after typing (id b) is:" (app [ID, B]) ":" T, + coq.univ.print + +}}. + +(*| + +The :stdtype:`diagnostic` data type is used by :builtin:`coq.typecheck` to +tell if the term is well typed. The constructor :e:`ok` signals success, while +:e:`error` carries an error message. In case of success universe constraints +are added to the store. + +============================= +Quotations and Antiquotations +============================= + +Writing Gallina terms as we did so far is surely possible but very verbose +and unhandy. Elpi provides a system of quotations and antiquotations to +let one take advantage of the Coq parser to write terms. + +The antiquotation, from Coq to Elpi, is written `lp:{{ ... }}` and we have +been using it since the beginning of the tutorial. The quotation from +Elpi to Coq is written :e:`{{:coq ... }}` or also just :e:`{{ ... }}` since +the `:coq` is the default quotation (Coq has no default quotation, hence you always need +to write `lp:` there). + +|*) + +Elpi Query lp:{{ + + % the ":coq" flag is optional + coq.say {{:coq 1 + 2 }} "=" {{ 1 + 2 }} + +}}. + +(*| + +Of course quotations can nest. + +|*) + +Elpi Query lp:{{ + + coq.locate "S" S, + coq.say {{ 1 + lp:{{ app[global S, {{ 0 }} ] }} }} +% elpi.... coq.. elpi........... coq elpi coq + +}}. + +(*| + +One rule governs bound variables: + +.. important:: + + if a variable is bound in a language, Coq or Elpi, + then the variable is only visible in that language (not in the other one). + +The following example is horrible but proves this point. In real code +you are encouraged to pick appropriate names for your variables, avoiding +gratuitous (visual) clashes. + +|*) + +Elpi Query lp:{{ + + coq.say (fun `x` {{nat}} x\ {{ fun x : nat => x + lp:{{ x }} }}) +% e c c e +}}. + +(*| + +A commodity quotation without parentheses let's one quote identifiers +omitting the curly braces. +That is `lp:{{ ident }}` can be written just `lp:ident`. + +|*) + + +Elpi Query lp:{{ + + coq.say (fun `x` {{nat}} x\ {{ fun x : nat => x + lp:x }}) +% e c c e +}}. + +(*| + +It is quite frequent to put Coq variables in the scope of an Elpi +unification variable, and this can be done by simply writing +`lp:(X a b)` which is a shorhand for `lp:{{ X {{ a }} {{ b }} }}`. + +.. warning:: writing `lp:X a b` (without parentheses) would result in a + Coq application, not an Elpi one + +Let's play a bit with these shorthands: + +|*) + +Elpi Query lp:{{ + + X = (x\y\ {{ lp:y + lp:x }}), % x and y live in Elpi + + coq.say {{ fun a b : nat => lp:(X a b) }} % a and b live in Coq + +}}. + +(*| + +Another commodity quotation lets one access the coqlib +feature introduced in Coq 8.10. + +Coqlib gives you an indirection between your code and the actual name +of constants. + +|*) + +Register Coq.Init.Datatypes.nat as my.N. +Register Coq.Init.Logic.eq as my.eq. + +Elpi Query lp:{{ + + coq.say {{ fun a b : lib:my.N => lib:@my.eq lib:my.N a b }} + +}}. + +(*| + +.. note:: The (optional) `@` in `lib:@some.name` disables implicit arguments. + +The `{{:gref .. }}` quotation lets one build the gref data type, instead of the +term one. It supports `lib:` as well. + +|*) + +Elpi Query lp:{{ + + coq.say {{:gref nat }}, + coq.say {{:gref lib:my.N }}. + +}}. + +(*| + +The last thing to keep in mind when using quotations is that implicit +arguments are inserted (according to the `Arguments` setting in Coq) +but not synthesized automatically. + +It is the job of the type checker or elaborator to synthesize them. +We shall see more on this in the section on `holes`_. + +|*) + +Elpi Query lp:{{ + + T = (fun `ax` {{nat}} a\ {{ fun b : nat => lp:a = b }}), + coq.say "before:" T, + coq.typecheck T _ ok, + coq.say "after:" T + +}}. + +(*| + +=========== +The context +=========== + +The context of Elpi (the hypothetical program made of rules loaded +via :e:`=>`) is taken into account by the Coq APIs. In particular every time +a bound variable is crossed, the programmer *must* load in the context a +rule attaching to that variable a type. There are a few facilities to +do that, but let's first see what happens if one forgets it. + +|*) + +Fail Elpi Query lp:{{ + + T = {{ fun x : nat => x + 1 }}, + coq.typecheck T _ ok, + T = fun _ _ Bo, + pi x\ + coq.typecheck (Bo x) _ _ + +}}. (* .fails *) + +(*| + +This fatal error says that :e:`x` in :e:`(Bo x)` is unknown to Coq. +It is +a variable postulated in Elpi, but it's type, `nat`, was lost. There +is nothing wrong per se in using :e:`pi x\ ` as we did if we don't call Coq +APIs under it. But if we do, we have to record the type of :e:`x` somewhere. + +In some sense Elpi's way of traversing a binder is similar to a Zipper. +The context of Elpi must record the part of the Zipper context that is +relevant for binders. + +The two predicates :builtin:`decl` and :builtin:`def` are used +for that purpose: + +.. code:: elpi + + pred decl i:term, o:name, o:term. % Var Name Ty + pred def i:term, o:name, o:term, o:term. % Var Name Ty Bo + +where :e:`def` is used to cross a :e:`let`. + +|*) + +Elpi Query lp:{{ + + T = {{ fun x : nat => x + 1 }}, + coq.typecheck T _ ok, + T = fun N Ty Bo, + pi x\ + decl x N Ty => + coq.typecheck (Bo x) _ ok + +}}. + +(*| + +In order to ease this task, Coq-Elpi provides a few commodity macros such as +`@pi-decl`: + +.. code:: elpi + + macro @pi-decl N T F :- pi x\ decl x N T => F x. + +.. note:: the precedence of lambda abstraction :e:`x\ ` lets you write the + following code without parentheses for :e:`F`. + +|*) + +Elpi Query lp:{{ + + T = {{ fun x : nat => x + 1 }}, + coq.typecheck T _ ok, + T = fun N Ty Bo, + @pi-decl N Ty x\ + coq.typecheck (Bo x) _ ok + +}}. + +(*| + +.. tip:: :e:`@pi-decl N Ty x\ ` takes arguments in the same order of :constructor:`fun` and + :constructor:`prod`, while + :e:`@pi-def N Ty Bo x\ ` takes arguments in the same order of :constructor:`let`. + +.. _holes: + +========================== +Holes (implicit arguments) +========================== + +An "Evar" (Coq slang for existentially quantified meta variable) is +represented as a Elpi unification variable and a typing constraint. + +|*) + +Elpi Query lp:{{ + + T = {{ _ }}, + coq.say "raw T =" T, + coq.sigma.print, + coq.say "--------------------------------", + coq.typecheck T {{ nat }} ok, + coq.sigma.print + +}}. + +(*| + +Before the call to :builtin:`coq.typecheck`, :builtin:`coq.sigma.print` +prints nothing interesting, while after the call it also prints the following +syntactic constraint: + +.. mquote:: .s(Elpi).msg(suspended on X1) + :language: elpi + +which indicates that the hole :e:`X1` is linked to a Coq evar +and is expected to have type `nat`. + +Now the bijective mapping from Coq evars to Elpi's unification variables +is not empty anymore: + +.. mquote:: .s(Elpi).msg{Coq-Elpi mapping:*[?]X11 <-> X1*} + :language: text + +Note that Coq's evar identifiers are of the form `?X`, while the Elpi ones +have no leading `?`. The Coq Evar map says that `?X11` has type `nat`: + +.. mquote:: .s(Elpi).msg{EVARS:*[?]X11==[[] |- nat[]]*} + :language: text + +The intuition is that Coq's Evar map (AKA sigma or evd), which assigns +typing judgement to evars, is represented with Elpi constraints which carry +the same piece of info. + +Naked Elpi unification variables, when passed to Coq's API, are +automatically linked to a Coq evar. We postpone the explanation of the +difference "raw" and "elab" unification variables to the chapter about +tactics, here the second copy of :e:`X1` in the evar constraint plays +no role. + +Now, what about the typing context? + +|*) + +Elpi Query lp:{{ + + T = {{ fun x : nat => x + _ }}, + coq.say "raw T =" T, + T = fun N Ty Bo, + @pi-decl N Ty x\ + coq.typecheck (Bo x) {{ nat }} ok, + coq.sigma.print. + +}}. + +(*| + +In the value of raw :e:`T` we can see that the hole in `x + _`, which occurs under the +binder :e:`c0\ `, is represented by an Elpi unification variable :e:`X1 c0`, that +means that :e:`X1` sees :e:`c0` (:e:`c0` is in the scope of :e:`X1`). + +The constraint is this time a bit more complex. Let's dissect it: + +.. mquote:: .s(Elpi).msg(suspended on X1) + :language: elpi + +Here `{...}` is the set of names (not necessarily minimized) used in the +constraint, while `?-` separates the assumptions (the context) from the +conclusion (the suspended goal). + +The mapping between Coq and Elpi is: + +.. mquote:: .s(Elpi).msg{Coq-Elpi mapping:*[?]X13 <-> X1*} + :language: text + +where `?X13` can be found in Coq's sigma: + +.. mquote:: .s(Elpi).msg{EVARS:*[?]X13==[[]x |- nat[]]*} + :language: text + +As expected both Elpi's constraint and Coq's evar map record a context +with a variable :e:`x` (of type `nat`) which is in the scope of the hole. + +Unless one is writing a tactic, Elpi's constraints are just used to +represent the evar map. When a term is assigned to a variable +the corresponding constraint is dropped. When one is writing a tactic, +things are wired up so that assigning a term to an Elpi variable +representing an evar resumes a type checking goal to ensure the term has +the expected type. +We will explain this in detail in the tutorial about tactics. + +---------------------------- +Outside the pattern fragment +---------------------------- + +This encoding of evars is such that the programmer does not need to care +much about them: no need to carry around an assignment/typing map like the +Evar map, no need to declared new variables there, etc. The programmer +can freely call Coq API passing an Elpi term containing holes. + +There is one limitation, though. The rest of this tutorial describes it +and introduces a few APIs and options to deal with it. + +The limitation is that the automatic declaration and mapping +does not work in all situations. In particular it only works for Elpi +unification variables which are in the pattern fragment, which mean +that they are applied only to distinct names (bound variables). + +This is the case for all the `{{ _ }}` one writes inside quotations, for +example, but it is not hard to craft a term outside this fragment. +In particular we can use Elpi's substitution (function application) to +put an arbitrary term in place of a bound variable. + +|*) + +Fail Elpi Query lp:{{ + + T = {{ fun x : nat => x + _ }}, + % remark the hole sees x + T = fun N Ty Bo, + % 1 is the offending term we put in place of x + Bo1 = Bo {{ 1 }}, + % Bo1 is outside the pattern fragment + coq.say "Bo1 (not in pattern fragment) =" Bo1, + % boom + coq.typecheck Bo1 {{ nat }} ok. + +}}. (* .fails *) + +(*| + +This snippet fails hard, with the following message: + +.. mquote:: .s(Elpi).msg(Flexible term outside) + :language: elpi + +Indeed :e:`Bo1` contains a term outside the pattern fragment, +the second argument of `plus`, which is obtained by replacing +:e:`c0` with `{{ 1 }}` in :e:`X0 c0`. + +While programming Coq extensions in Elpi, it may happen that we want to +use a Coq term as a syntax tree (with holes) and we need to apply +substitutions to it but we don't really care about the scope of holes. +We would like these holes to stay `{{ _ }}` (a fresh hole which sees the +entire context of bound variables). In some sense, we would like `{{ _ }}` +to be a special dummy constant, to be turned into an actual hole on the +fly when needed. + +This use case is perfectly legitimate and is supported by all APIs taking +terms in input thanks to the :macro:`@holes!` option. + +|*) + +Elpi Query lp:{{ + + T = {{ fun x : nat => x + _ }}, + T = fun N Ty Bo, + Bo1 = Bo {{ 1 }}, + coq.say "Bo1 before =" Bo1, + % by loading this rule in the context, we set + % the option for the APIs called under it + @holes! => coq.typecheck Bo1 {{ nat }} ok, + coq.say "Bo1 after =" Bo1. + +}}. + +(*| + +Note that after the call to :builtin:`coq.typecheck`, :e:`X0` is assigned the +term :e:`_\ X1`, that means that the offending argument has been pruned +(discarded). + +.. note:: All APIs taking a term support the :macro:`@holes!` option. + +In addition to the :macro:`@holes!` option, there is a class of APIs which can +deal with terms outside the pattern fragment. These APIs take in input a term +*skeleton*. A skeleton is not modified in place, as :builtin:`coq.typecheck` +does with its first argument, but is rather elaborated to a term related to it. + +In some sense APIs taking a skeleton are more powerful, because they can +modify the structure of the term, eg. insert a coercions, but are less +precise, in the sense that the relation between the input and the output +terms is not straightforward (it's not unification). + +|*) + +Coercion nat2bool n := match n with O => false | _ => true end. +Open Scope bool_scope. + +Elpi Query lp:{{ + + T = {{ fun x : nat => x && _ }}, + T = fun N Ty Bo, + Bo1 = Bo {{ 1 }}, + coq.elaborate-skeleton Bo1 {{ bool }} Bo2 ok + +}}. + +(*| + +Here :e:`Bo2` is obtained by taking :e:`Bo1`, considering all +unification variables as holes and all `{{ Type }}` levels as fresh +(the are none in this example), and running Coq's elaborator on it. + +The result is a term with a similar structure (skeleton), but a coercion +is inserted to make :e:`x` fit as a boolean value, and a fresh hole :e:`X1` is +put in place of the term :e:`X0 (app [global (indc «S»), global (indc «O»)])` +which is left untouched. + +Skeletons and their APIs are described in more details in the tutorial +on commands. + +That is all for this tutorial. You can continue by reading the tutorial +about +`commands `_ +or the one about +`tactics `_. + +|*) diff --git a/tests/tutorial_coq_elpi_command.t/run.t b/tests/tutorial_coq_elpi_command.t/run.t new file mode 100644 index 000000000..9a939ccb5 --- /dev/null +++ b/tests/tutorial_coq_elpi_command.t/run.t @@ -0,0 +1,90 @@ + $ . ../setup-project.sh + $ dune build test.vo 2>&1 | sed '/The module is/s/Module[0-9]*/ModuleXX/' + Hello [str world!] + Hello [int 46] + Hello [str there] + Hello [str my, str friend] + Hello [str this.is.a.qualified.name] + Hello + [trm + (app + [global (indt «eq»), global (indt «nat»), global (indc «O»), + app [global (indc «S»), global (indc «O»)]])] + Hello + [const-decl test + (some + (app + [global (indt «eq»), global (indt «nat»), global (indc «O»), + app [global (indc «S»), global (indc «O»)]])) (arity (sort prop))] + Hello + [indt-decl + (record test (sort (typ «Set»)) Build_test + (field [coercion off, canonical tt] f1 (global (indt «nat»)) c0 \ + field [coercion off, canonical tt] f2 + (app + [global (indt «eq»), global (indt «nat»), c0, + app [global (indc «S»), global (indc «O»)]]) c1 \ end-record))] + The type of + app + [global (indt «eq»), global (indt «nat»), + app [global (indc «S»), global (indc «O»)], global (indc «O»)] is + sort prop + 1 = true + : Prop + T= + app + [global (indt «eq»), X0, app [global (indc «S»), global (indc «O»)], + global (indc «true»)] + T1= + app + [global (indt «eq»), global (indt «nat»), + app [global (indc «S»), global (indc «O»)], + app [global (const «bool2nat»), global (indc «true»)]] + Ty= sort prop + nK_bool = 2 + : nat + nK_False = 0 + : nat + Inductive tree' (A : Set) : Set := + leaf' : tree' A | node' : tree' A -> A -> tree' A -> tree' A. + + Arguments tree' A%type_scope + Arguments leaf' A%type_scope + Arguments node' A%type_scope _ _ _ + bob is 24 years old + alice is 21 years old + bob is 24 years old + alice is 21 years old + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 609, column 31, character 17326:), + attribute elpi.phase (leaf-str interp), attribute this (leaf-str ), + attribute more (node [attribute stuff (leaf-str 33)])] + options= + [get-option elpi.test yes, get-option elpi.str some-string, + get-option elpi.loc File "./test.v", line 642, column 31, character 18163:, + get-option elpi.phase interp, get-option this tt, get-option more.stuff 33] + 33 tt + That is all folks! + going from source to target via plane + synterp x := some _ + interp x := + some + (app [global (indc «S»), app [global (indc «S»), global (indc «O»)]]) + The module is «test.test.ModuleXX» + Box.Box.Box.Box.foo = fun n : nat => n + 2 + : nat -> nat + + Arguments Box.Box.Box.Box.foo n%nat_scope + Module NextModule2 := Struct End + + File "./test.v", line 609, characters 2-24: + Warning: This command does not support these attributes: more, this. + [unsupported-attributes,parsing,default] + File "./test.v", line 642, characters 2-24: + Warning: This command does not support these attributes: more, this. + [unsupported-attributes,parsing,default] + File "./test.v", line 643, characters 7-14: + Warning: This command does not support this attribute: unknown. + [unsupported-attributes,parsing,default] diff --git a/tests/tutorial_coq_elpi_command.t/test.v b/tests/tutorial_coq_elpi_command.t/test.v new file mode 100644 index 000000000..42256a037 --- /dev/null +++ b/tests/tutorial_coq_elpi_command.t/test.v @@ -0,0 +1,963 @@ +(*| + +Tutorial on Coq commands +************************ + +:author: Enrico Tassi + +.. include:: ../etc/tutorial_style.rst + +.. + Elpi is an extension language that comes as a library + to be embedded into host applications such as Coq. + + Elpi is a variant of λProlog enriched with constraints. + λProlog is a programming language designed to make it easy + to manipulate abstract syntax trees containing binders. + Elpi extends λProlog with programming constructs that are + designed to make it easy to manipulate abstract syntax trees + containing metavariables (also called unification variables, or + evars in the Coq jargon). + + This software, "coq-elpi", is a Coq plugin embedding Elpi and + exposing to the extension language Coq spefic data types (e.g. terms) + and API (e.g. to declare a new inductive type). + + In order to get proper syntax highlighting using VSCode please install the + "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in + Edit -> Preferences -> Colors. + +This tutorial assumes the reader is familiar with Elpi and the HOAS +representation of Coq terms; if it is not the case, please take a look at +these other tutorials first: +`Elpi tutorial `_ +and +`Coq HOAS tutorial `_. + +.. contents:: + +================= +Defining commands +================= + +Let's create a simple command, called "hello", which prints :e:`"Hello"` +followed by the arguments we pass to it: + +|*) +From elpi Require Import elpi. + +Elpi Command hello. +Elpi Accumulate lp:{{ + + % main is, well, the entry point + main Arguments :- coq.say "Hello" Arguments. + +}}. +Elpi Typecheck. + +(*| + +The program declaration is made of 3 parts. + +The first one `Elpi Command hello.` sets the current program to hello. +Since it is declared as a `Command` some code is loaded automatically: + +* APIs (eg :builtin:`coq.say`) and data types (eg Coq :type:`term` s) are loaded from + `coq-builtin.elpi `_ +* some utilities, like :lib:`copy` or :libred:`whd1` are loaded from + `elpi-command-template.elpi `_ + + +The second one `Elpi Accumulate ...` loads some extra code. +The `Elpi Accumulate ...` family of commands lets one accumulate code +taken from: + +* verbatim text `Elpi Accumulate lp:{{ code }}` +* source files `Elpi Accumulate File path` +* data bases (Db) `Elpi Accumulate Db name` + +Accumulating code via inline text or file is equivalent, the AST of `code` +is stored in the .vo file (the external file does not need to be installed). +We postpone the description of data bases to a dedicated section. + +Once all the code is accumulated `Elpi Typecheck` verifies that the +code does not contain the most frequent kind of mistakes. This command +considers some mistakes minor and only warns about them. You can +pass `-w +elpi.typecheck` to `coqc` to turn these warnings into errors. + +We can now run our program! + +|*) + +Elpi hello "world!". + +(*| + +You should see the following output (hover the bubble next to the +code if you are reading this online): + +.. mquote:: .s(Elpi hello).msg(str world) + :language: text + +The string `"world!"` we passed to the command is received by the code +as :e:`(str "world!")`. + +.. note:: :builtin:`coq.say` won't print quotes around strings + +================= +Command arguments +================= + +Let's pass different kind of arguments to `hello`: + +|*) + +Elpi hello 46. +Elpi hello there. + +(*| + +This time we passed to the command a number and an identifier. +Identifiers are received as strings, and can contain dots, but no spaces. + +|*) + +Elpi hello my friend. +Elpi hello this.is.a.qualified.name. + +(*| + +Indeed the first invocation passes two arguments, of type string, while +the second a single one, again a string containing dots. + +There are a few more types of arguments a command can receive: + +* terms, delimited by `(` and `)` +* toplevel declarations, like `Inductive ..`, `Definition ..`, etc.. + which are introduced by their characterizing keyword. + +Let's try with a term. + +|*) + +Elpi hello (0 = 1). + +(*| + +Since Coq-Elpi 1.15, terms are received in elaborated form, meaning +that the elaborator of Coq is used to pre-process them. +In the example above the type argument to `eq` has +been synthesized to be `nat`. + +|*) + +Elpi hello Definition test := 0 = 1. +Elpi hello Record test := { f1 : nat; f2 : f1 = 1 }. + +(*| + +Global declarations are received in elaborated form as well. +In the case of `Definition test` the optional body (would be +:e:`none` for an `Axiom` declaration) is present +while the omitted type is inferred (to be `Prop`). + +In the case of the `Record` declaration remark that each field has a few +attributes, like being a coercions (the `:>` in Coq's syntax). Also note that +the type of the record (which was omitted) defaults to `Type`. +Finally note that the type of the second field +sees :e:`c0` (the value of the first field). + +See the :type:`argument` data type +for a detailed decription of all the arguments a command can receive. + +------------------------ +Processing raw arguments +------------------------ + +It is sometimes useful to receive arguments in raw format, +so that no elaboration has been performed. +This can be achieved by using the +`#[arguments(raw)]` attributed when the command is declared. + +Then, thre are two ways to process term arguments: +typechecking and elaboration. + +|*) + +#[arguments(raw)] Elpi Command check_arg. +Elpi Accumulate lp:{{ + + main [trm T] :- + std.assert-ok! (coq.typecheck T Ty) "argument illtyped", + coq.say "The type of" T "is" Ty. + +}}. +Elpi Typecheck. + +Elpi check_arg (1 = 0). +Fail Elpi check_arg (1 = true). (* .fails *) + +(*| + +The command `check_arg` receives a term :e:`T` and type checks it, then it +prints the term and its type. + +The :builtin:`coq.typecheck` API has 3 arguments: a term, its type and a +:stdtype:`diagnostic` which can either be :e:`ok` or :e:`(error Message)`. +The :stdlib:`assert-ok!` combinator checks if the diagnostic is :e:`ok`, +and if not it prints the error message and bails out. + +The first invocation succeeds while the second one fails and prints +the type checking error (given by Coq) following the string passed to +:e:`std.assert-ok!`. + +|*) + +Coercion bool2nat (b : bool) := if b then 1 else 0. +Fail Elpi check_arg (1 = true). (* .fails *) +Check (1 = true). + +(*| + +The command still fails even if we told Coq how to inject booleans values +into the natural numbers. Indeed the `Check` commands works. + +The call to :builtin:`coq.typecheck` modifies the term in place, it can assign +implicit arguments (like the type parameter of `eq`) but it cannot modify the +structure of the term. To do so, one has to use the +:builtin:`coq.elaborate-skeleton` API. + +|*) + +#[arguments(raw)] +Elpi Command elaborate_arg. +Elpi Accumulate lp:{{ + + main [trm T] :- + std.assert-ok! (coq.elaborate-skeleton T Ty T1) "illtyped arg", + coq.say "T=" T, + coq.say "T1=" T1, + coq.say "Ty=" Ty. + +}}. +Elpi Typecheck. + +Elpi elaborate_arg (1 = true). + +(*| + +Remark how :e:`T` is not touched by the call to this API, and how :e:`T1` +is a copy of :e:`T` where the hole after `eq` is synthesized and the value +`true` injected to `nat` by using `bool2nat`. + +It is also possible to manipulate term arguments before typechecking +them, but note that all the considerations on holes in the tutorial about +the HOAS representation of Coq terms apply here. An example of tool +taking advantage of this possibility is Hierarchy Builder: the declarations +it receives would not typecheck in the current context, but do once the +context is temporarily augmented with ad-hoc canonical structure instances. + +======== +Examples +======== + +------------------- +Synthesizing a term +------------------- + +Synthesizing a term typically involves reading an existing declaration +and writing a new one. The relevant APIs are in the `coq.env.*` namespace +and are named after the global refence they manipulate, eg :builtin:`coq.env.const` +for reading and :builtin:`coq.env.add-const` for writing. + +Here we implement a little command that given an inductive type name +generates a term of type `nat` whose value is the number of constructors +of the given inductive type. + +|*) + +Elpi Command constructors_num. + +Elpi Accumulate lp:{{ + +pred int->nat i:int, o:term. +int->nat 0 {{ 0 }}. +int->nat N {{ S lp:X }} :- M is N - 1, int->nat M X. + +main [str IndName, str Name] :- + std.assert! (coq.locate IndName (indt GR)) "not an inductive type", + coq.env.indt GR _ _ _ _ Kn _, % the names of the constructors + std.length Kn N, % count them + int->nat N Nnat, % turn the integer into a nat + coq.env.add-const Name Nnat _ _ _. % save it + +}}. +Elpi Typecheck. + +Elpi constructors_num bool nK_bool. +Print nK_bool. + +Elpi constructors_num False nK_False. +Print nK_False. + +Fail Elpi constructors_num plus nK_plus. (* .fails *) +Fail Elpi constructors_num not_there bla. (* .fails *) + +(*| + +The command starts by locating the first argument and asserting it points to +an inductive type. This line is idiomatic: :builtin:`coq.locate` aborts if +the string cannot be located, and if it relates it to a :e:`gref` which is not +:e:`indt` (for example :e:`const plus`) :stdlib:`assert!` aborts with the given +error message. + +:builtin:`coq.env.indt` lets one access all the details of an inductive type, +here we just use the list of constructors. +The twin API :builtin:`coq.env.indt-decl` lets +one access the declaration of the inductive in HOAS form, which might be +easier to manipulate in other situations, like the next example. + +Then the program crafts a natural number and declares a constant for it. + +------------------------ +Abstracting an inductive +------------------------ + +For the sake of introducing :lib:`copy`, the swiss army knife of λProlog, we +write a command which takes an inductive type declaration and builds a new +one abstracting the former one on a given term. The new inductive has a +parameter in place of the occurrences of that term. + +|*) + +Elpi Command abstract. + +Elpi Accumulate lp:{{ + + % a renaming function which adds a ' to an ident (a string) + pred prime i:id, o:id. + prime S S1 :- S1 is S ^ "'". + + main [str Ind, trm Param] :- + + % the term to be abstracted out, P of type PTy + std.assert-ok! + (coq.elaborate-skeleton Param PTy P) + "illtyped parameter", + + % fetch the old declaration + std.assert! (coq.locate Ind (indt I)) "not an inductive type", + coq.env.indt-decl I Decl, + + % let's start to craft the new declaration by putting a + % parameter A which has the type of P + NewDecl = parameter "A" explicit PTy Decl', + + % let's make a copy, capturing all occurrences of P with a + % (which stands for the parameter) + (pi a\ copy P a => copy-indt-decl Decl (Decl' a)), + + % to avoid name clashes, we rename the type and its constructors + % (we don't need to rename the parameters) + coq.rename-indt-decl (=) prime prime NewDecl DeclRenamed, + + % we type check the inductive declaration, since abstracting + % random terms may lead to illtyped declarations (type theory + % is hard) + std.assert-ok! + (coq.typecheck-indt-decl DeclRenamed) + "can't be abstracted", + + coq.env.add-indt DeclRenamed _. + +}}. +Elpi Typecheck. + +Inductive tree := leaf | node : tree -> option nat -> tree -> tree. + +Elpi abstract tree (option nat). +Print tree'. + +(*| + +As expected `tree'` has a parameter `A`. + +Now let's focus on :lib:`copy`. The standard +coq library (loaded by the command template) contains a definition of copy +for terms and declarations. + +An excerpt: + +.. code:: elpi + + copy X X :- name X. % checks X is a bound variable + copy (global _ as C) C. + copy (fun N T F) (fun N T1 F1) :- + copy T T1, pi x\ copy (F x) (F1 x). + copy (app L) (app L1) :- std.map L copy L1. + +:e:`copy` implements the identity: it builds, recursively, a copy of the first +term into the second argument. Unless one loads in the context a new rule, +which takes precedence over the identity ones. Here we load: + +.. code:: elpi + + copy P a + +which, at run time, looks like + +.. code:: elpi + + copy (app [global (indt «option»), global (indt «nat»)]) c0 + +and that rule masks the one for `app` when the sub-term being copied is +exactly `option nat`. The API :lib:`copy-indt-decl` copies an inductive +declaration and calls `copy` on all the terms it contains (e.g. the +type of the constructors). + +The :lib:`copy` predicate is very flexible, but sometimes one needs to collect +some data along the way. The sibling API :lib:`fold-map` lets one do that. + +An excerpt: + +.. code:: elpi + + fold-map (fun N T F) A (fun N T1 F1) A2 :- + fold-map T A T1 A1, pi x\ fold-map (F x) A1 (F1 x) A2. + +For example one can use :lib:`fold-map` to collect into a list all the occurrences +of inductive type constructors in a given term, then use the list to postulate +the right number of binders for them, and finally use :lib:`copy` to capture them. + + +==================================== +Using DBs to store data across calls +==================================== + +A Db can be created with the command: + +|*) + +Elpi Db name.db lp:{{ some code. }}. + +(*| + +and a Db can be later extended via `Elpi Accumulate`. +As a convention, we like Db names to end in a .db suffix. + +A Db is pretty much like a regular program but can be *shared* among +other programs and is accumulated *by name*. +Since is a Db is accumulated *when a program runs* the *current +contents of the Db are used*. +Moreover the Db can be extended by Elpi programs themselves +thanks to the API :builtin:`coq.elpi.accumulate`, enabling code to save a state +which is then visible at subsequent runs. + +The initial contents of a Db, `some code` in the example +above, is usually just the type declaration for the predicates part of the Db, +and maybe a few default rules. +Let's define a Db. + +|*) + +Elpi Db age.db lp:{{ + + % A typical Db is made of one main predicate + pred age o:string, o:int. + + % the Db is empty for now, we put a rule giving a + % descriptive error and we name that rule "age.fail". + :name "age.fail" + age Name _ :- coq.error "I don't know who" Name "is!". + +}}. + +(*| + +Elpi rules can be given a name via the :e:`:name` attribute. Named rules +serve as anchor-points for new rules when added to the Db. + +Let's define a `Command` that makes use of a Db. + +|*) + +Elpi Command age. +Elpi Accumulate Db age.db. (* we accumulate the Db *) +Elpi Accumulate lp:{{ + + main [str Name] :- + age Name A, + coq.say Name "is" A "years old". + +}}. +Elpi Typecheck. + +Fail Elpi age bob. (* .fails *) + +(*| + +Let's put some data in the Db. Given that the Db contains a catch-all rule, +we need the new ones to be put before it. + +|*) + +Elpi Accumulate age.db lp:{{ + + :before "age.fail" % we place this rule before the catch all + age "bob" 24. + +}}. + +Elpi age bob. + +(*| + +Extending data bases this way is fine, but requires the user of our command +to be familiar with Elpi's syntax, which is not very nice. Instead, +we can write a new program that uses the :builtin:`coq.elpi.accumulate` API +to extend the Db. + +|*) + +Elpi Command set_age. +Elpi Accumulate Db age.db. +Elpi Accumulate lp:{{ + main [str Name, int Age] :- + TheNewRule = age Name Age, + coq.elpi.accumulate _ "age.db" + (clause _ (before "age.fail") TheNewRule). + +}}. +Elpi Typecheck. + +Elpi set_age "alice" 21. +Elpi age "alice". + +(*| + +Additions to a Db are a Coq object, a bit like a Notation or a Type Class +instance: these object live inside a Coq module (or a Coq file) and become +active when that module is Imported. + +Deciding to which Coq module these +extra rules belong is important and :builtin:`coq.elpi.accumulate` provides +a few options to tune that. Here we passed :e:`_`, that uses the default +setting. See the :type:`scope` and :type:`clause` data types for more info. + +.. _inspecting: + +--------------- +Inspecting a Db +--------------- + +So far we did query a Db but sometimes one needs to inspect the whole +contents. + +|*) + +Elpi Command print_all_ages. +Elpi Accumulate Db age.db. +Elpi Accumulate lp:{{ + + :before "age.fail" + age _ _ :- !, fail. % softly + + main [] :- + std.findall (age _ _) Rules, + std.forall Rules print-rule. + + pred print-rule i:prop. + print-rule (age P N) :- coq.say P "is" N "years old". + +}}. +Elpi Typecheck. +Elpi print_all_ages. + +(*| + +The :stdlib:`std.findall` predicate gathers in a list all solutions to +a query, while :stdlib:`std.forall` iterates a predicate over a list. +It is important to notice that :builtin:`coq.error` is a fatal error which +aborts an Elpi program. Here we shadow the catch all clause with a regular +failure so that :stdlib:`std.findall` can complete to list all the results. + +=================== +Polishing a command +=================== + +The details do make the difference, some times. + +---------- +Attributes +---------- + +Elpi programs can be prefixed with attributes, like `#[local]`. +Attributes are not passed as arguments but rather as a rule in the context, +a bit like the option :e:`@holes!` we have seen before. + +|*) + +Elpi Command attr. +Elpi Accumulate lp:{{ + + main _ :- + attributes A, % we fetch the list of attributes from the context + coq.say A. + +}}. + +#[this, more(stuff="33")] Elpi attr. + +(*| + +The first attribute, :e:`elpi.loc` is always present and corresponds to the +location in the source file of the command. Then we find an attribute for +:e:`"this"` holding the emptry string and an attribute for :e:`"more.stuff"` holding +the string :e:`"33"`. + +Attributes are usually validated (parsed) and turned into regular options +using :lib-common:`coq.parse-attributes` and a description of their types using +the :libtype-common:`attribute-type` data type: + +|*) + +Elpi Command parse_attr. +Elpi Accumulate lp:{{ + + pred some-code. + some-code :- + get-option "more.stuff" N, get-option "this" B, coq.say N B. + + main _ :- + attributes A, + coq.parse-attributes A [ + att "this" bool, + att "more.stuff" int, + ] Opts, + coq.say "options=" Opts, + Opts => some-code. + +}}. + +#[this, more(stuff="33")] Elpi parse_attr. +Fail #[unknown] Elpi parse_attr. (* .fails *) + +(*| + +Note that :e:`get-option` links a string with a datum of type :e:`any`, which means +no type checking is performed on it. It is recommended to wrap calls to +get-option into other predicates typed in a more precise way. Eg: + +.. code:: elpi + + pred get-my-option o:int. + get-my-option I :- get-option "my-option-name" I. + +----------------------------- +Extending the command grammar +----------------------------- + +Elpi programs can be exported as regular Coq commands, so that the +final user does not need to type `Elpi` to invoke them. + +|*) + +Elpi Command Say. +Elpi Accumulate lp:{{ main [str S] :- coq.say S. }}. +Elpi Typecheck. + +Elpi Export Say. (* extend the Coq command grammar *) + +Say "That is all folks!". + +(*| + +Not yet... + +Coq offers no equivalent of `Tactic Notation` for commands. +Still Elpi commands accept any symbol or keyword as strings. +It is up to the programmer to catch and report parse errors. + +|*) + +Elpi Command Go. +Elpi Accumulate lp:{{ + main [str Src, str "=>", str Tgt, str "/", str F] :- !, + coq.say "going from" Src "to" Tgt "via" F. + main _ :- + coq.error "Parse error! Use: go => / ". +}}. +Elpi Typecheck. +Elpi Export Go. + +Go source => target / plane. +Fail Go nowhere. (* .fails *) + +(*| + +---------------- +Reporting errors +---------------- + +Last, (good) Elpi programs should fail reporting intellegible error messages, +as the previous one. + +|*) + +Elpi Command bad. +Elpi Accumulate lp:{{ main []. }}. +Elpi Typecheck. +Elpi Export bad. + +Fail bad 1. (* .fails *) + +(*| + +If they just fail, they produce the following generic +error: + +.. mquote:: .s(bad 1).msg(inconvenience) + :language: text + +You should use the :builtin:`coq.error` API or the :stdlib:`assert!` one +to abort a program. There is a dedicated :builtin:`coq.ltac.fail` API to abort +tactics. + +Warnings can be reported using the :builtin:`coq.warning` which lets you +pick a name and category. In turn these can be used to disable or make fatal +your warnings (as any other Coq warning). + +===================== +Parsing and Execution +===================== + +Since version 8.18 Coq has separate parsing and execution phases, +respectively called synterp and interp. + +Since Coq has an extensible grammar the parsing phase is not entirely +performed by the parser: after parsing one sentence Coq evaluates its +synterp action. The synterp actions of a command like `Import A.` are +the subset of its effect which affect parsing, like enabling a notation. +Later, during the execution phase, Coq evaluates its +interp actions, which include effects like putting lemma in scope or +enabling type class instances etc. Synterp actions are quick, if only because +they don't really manipulate Coq terms, hence no type checking and the like. + +Being able to parse an entire document quickly +is important for developing reactive +user interfaces, but requires some extra work when defining new commands, +in particular to identify their synterp. +Each command defined with Coq-Elpi is split into two programs, +one running during the parsing phase and the other one during the execution +phase. Each API that affects the parser, i.e. APIs dealing with modules +and sections like begin/end-module or import/export, is available to both the +synterp and the interp program under the same name, but its actual effect is +limited to what concerns the current phase. Hence all these APIs have to be +called at *both* synterp and interp time and *in the same order*. + +At synterp time the data types and the APIs are restricted, in particular +Coq terms are not available. When a command argument contains a term, that +term is replaced by `_` at synterp time. In the following example, the synterp +program can see the name of the definition and the fact that a body was given, +but not the value of the body. + +|*) + + +Elpi Command hello_synterp. +#[synterp] Elpi Accumulate lp:{{ + main [const-decl Name Body _] :- coq.say "synterp" Name ":=" Body. +}}. +Elpi Accumulate lp:{{ + main [const-decl Name Body _] :- coq.say "interp" Name ":=" Body. +}}. +Elpi Typecheck. + +Elpi hello_synterp Definition x := 2. + +(*| + +This simple command has no real synterp action, one could safely remove +the synterp code. On the contrary when a command performs actions affecting +the parser then it must come equipped with some synterp code performing +the corresponding actions. + +|*) + +Module Notations. +Notation "x '>>' y" := (x > y) (at level 40). +Definition w := 3. +End Notations. + +Elpi Command import_module. +Elpi Accumulate lp:{{ + main [str M] :- + coq.locate-module M MP, + coq.env.import-module MP, + coq.locate "w" (const GR), + coq.env.const GR (some {{ 3 }}) _. +}}. +Elpi Typecheck. + +Fail Elpi import_module Notations. (* .fails .in .messages *) + +(* oops, we forgot to declare code for the synterp phase. Here it is *) +#[synterp] Elpi Accumulate lp:{{ + main [str M] :- + coq.locate-module M MP, + coq.env.import-module MP. +}}. +Elpi Typecheck. + +Elpi import_module Notations. + +(*| + +Elpi reports a descriptive error message if actions affecting the parser are +not declared in the synterp code of the command. + +.. mquote:: .s(Elpi import_module Notations).msg{*Interp*actions*must*match*synterp*actions*} + :language: text + +Thanks to the synterp code, Coq can parse the document without even looking +at the interp code. + +Sometimes it is necessary to pass data from the synterp code to the interp one. +Passing data can be done in two ways. the former is by using the :e:`main-synterp` +and :e:`main-interp` entry points. + +.. code:: elpi + + pred main-synterp i:list argument, o:any. + pred main-interp i:list argument, i:any. + +Unlike :e:`main` the former outputs a datum while the latter receives it +in input. In the following command we create a (empty) module with a random +name. Even if the name is random, the two phases need to agree on it, hence +we pass the name from one to the other. + +|*) + +Elpi Command mk_random_module. +#[synterp] Elpi Accumulate lp:{{ + main-synterp [] M :- + random.self_init, + random.int 99 N, + M is "Module" ^ {std.any->string N}, + coq.env.begin-module M none, + coq.env.end-module _. +}}. +Elpi Accumulate lp:{{ + main-interp [] M :- + coq.env.begin-module M none, + coq.env.end-module MP, + coq.say "The module is" MP. +}}. +Elpi Typecheck. + +Elpi mk_random_module. + +(*| + +If the only data to be passed to the interp phase is the list of +synterp actions, then a few APIs can come in handy. +The synterp phase has access to the API :builtin-synterp:`coq.synterp-actions` +that lists the actions performed so far. The interp phase can use +:lib:`coq.replay-synterp-action` and :builtin:`coq.next-synterp-action` to +replay an action or peek the next one to be performed. + +An excerpt of the :type:`synterp-action`. + +.. code:: elpi + + % Action executed during the parsing phase (aka synterp) + kind synterp-action type. + type begin-module id -> synterp-action. + type end-module modpath -> synterp-action. + +The following command creates a stack of modules and puts in there +the given definition. The synterp phase saves the actions when the top of the +stack is reached, and passes them to the interp phase that replays them before +putting a definition inside. Finally the interp phase replays all the missing +actions. + +|*) + +Elpi Command put_inside. +#[synterp] Elpi Accumulate lp:{{ + main-synterp [int N, A] ActionsUpToNow :- N > 0, M is N - 1, + coq.env.begin-module "Box" none, + main-synterp [int M, A] ActionsUpToNow, + coq.env.end-module _. + main-synterp [int 0, _] ActionsUpToNow :- + coq.synterp-actions ActionsUpToNow. +}}. +Elpi Accumulate lp:{{ + main-interp [int _, const-decl Name (some BO) _] Before :- + std.forall Before coq.replay-synterp-action, + coq.env.add-const Name BO _ _ _, + replay-missing. + pred replay-missing. + replay-missing :- + coq.replay-synterp-action {coq.next-synterp-action}, + replay-missing. + replay-missing. +}}. + +Elpi Typecheck. + +Elpi put_inside 4 Definition foo (n : nat) := n + 2. + +Print Box.Box.Box.Box.foo. + +(*| + +This last example delegates to the synterp phase the creation of an arbitrary +complex module structure, a structure the interp phase does not need to be aware +of. The data passed to the interp phase is sufficient to replicate it without +too much effort. + +Finally, as regular commands, data bases can be used to store a state which +is available at subsequent calls. Data bases used in the two phases live +in different name spaces, and are only available to the corresponding phase. +The `#[synterp]` attribute tells `Elpi Db` to create a data base for the +synterp phase. Here a simple command saving a state in the synterp phase. + +|*) + +#[synterp] Elpi Db counter.db lp:{{ pred tick. }}. + +Elpi Command mk_next_module. +#[synterp] Elpi Accumulate Db counter.db. +#[synterp] Elpi Accumulate lp:{{ + main [] :- + std.findall tick L, + std.length L N, + M is "NextModule" ^ {std.any->string N}, + coq.env.begin-module M none, + coq.env.end-module _, + coq.elpi.accumulate _ "counter.db" (clause _ _ tick). +}}. +Elpi Accumulate lp:{{ + main [] :- replay-missing. + pred replay-missing. + replay-missing :- + coq.replay-synterp-action {coq.next-synterp-action}, + replay-missing. + replay-missing. +}}. +Elpi Typecheck. + +Elpi mk_next_module. +Elpi mk_next_module. +Elpi mk_next_module. + +Print Module NextModule2. + +(*| + +This is really the end, unless you want to learn more about writing +`tactics `_ +in Elpi, in that case look at that tutorial ;-) + +|*) diff --git a/tests/tutorial_coq_elpi_tactic.t/run.t b/tests/tutorial_coq_elpi_tactic.t/run.t new file mode 100644 index 000000000..d94c5c6c3 --- /dev/null +++ b/tests/tutorial_coq_elpi_tactic.t/run.t @@ -0,0 +1,95 @@ + $ . ../setup-project.sh + $ dune build test.vo + Goal: + [decl c1 `y` (global (indt «nat»)), decl c0 `x` (global (indt «nat»))] + |- X0 c0 c1 : + app + [global (indt «eq»), global (indt «nat»), + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]], c1] + (I, 0) + conj : forall [A B : Prop], A -> B -> A /\ B + + conj is not universe polymorphic + Arguments conj [A B]%type_scope _ _ + Expands to: Constructor Coq.Init.Logic.conj + (ex_intro (fun t : Prop => True /\ True /\ t) True (conj I (conj I I))) + [int 1, str x, str a b, + trm + (app + [global (indt «eq»), X0, + app [global (indc «S»), global (indc «O»)], global (indc «O»)])] + Using H ?p of type Q + Using H ?p of type Q + Using p of type P + [trm c0, trm c3, trm (app [c2, c3])] + found P + found P /\ P + Goal: [decl c0 `x` (global (indt «nat»))] |- X0 c0 : + app + [global (indt «eq»), global (indt «nat»), + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]], global (indc «O»)] + Proof state: + {c0} : decl c0 `x` (global (indt «nat»)) + ?- evar (X1 c0) + (app + [global (indt «eq»), global (indt «nat»), + app + [global (const «Nat.add»), c0, + app [global (indc «S»), global (indc «O»)]], + global (indc «O»)]) (X0 c0) /* suspended on X1, X0 */ + EVARS: + ?X57==[x |- x + 1 = 0] (goal evar) {?Goal} + ?X56==[ |- => fun x : nat => ?Goal] (goal evar) + ?X55==[x |- => nat] (parameter A of eq) + ?X54==[ |- => nat] (type of x) + + SHELF:|| + FUTURE GOALS STACK: + || + + Coq-Elpi mapping: + RAW: + ?X57 <-> c0 \ X1 c0 + ELAB: + ?X57 <-> X0 + + #goals = 2 + [nabla c0 \ + nabla c1 \ + seal + (goal [decl c1 `Q` (sort prop), decl c0 `P` (sort prop)] (X0 c0 c1) c0 + (X1 c0 c1) []), + nabla c0 \ + nabla c1 \ + seal + (goal [decl c1 `Q` (sort prop), decl c0 `P` (sort prop)] (X2 c0 c1) c1 + (X3 c0 c1) [])] + (fun (P Q : Prop) (p : P) (q : Q) => conj ?Goal (conj ?Goal0 ?Goal1)) + (fun (P Q : Prop) (p : P) (q : Q) => conj ?Goal (conj ?Goal0 ?Goal)) + foo = 46 + : nat + bar = (false :: nil)%list + : list bool + baz = (46%nat :: nil)%list + : list nat + File "./test.v", line 631, characters 0-22: + Warning: x is already taken, Elpi will make a name up [lib,elpi,default] + File "./test.v", line 741, characters 3-225: + Warning: B is linear: name it _B (discard) or B_ (fresh variable) + [elpi.typecheck,elpi,default] + File "./test.v", line 741, characters 3-225: + Warning: A is linear: name it _A (discard) or A_ (fresh variable) + [elpi.typecheck,elpi,default] + File "./test.v", line 741, characters 3-225: + Warning: Ctx is linear: name it _Ctx (discard) or Ctx_ (fresh variable) + [elpi.typecheck,elpi,default] + File "./test.v", line 842, characters 3-280: + Warning: G2 is linear: name it _G2 (discard) or G2_ (fresh variable) + [elpi.typecheck,elpi,default] + File "./test.v", line 842, characters 3-280: + Warning: G1 is linear: name it _G1 (discard) or G1_ (fresh variable) + [elpi.typecheck,elpi,default] diff --git a/tests/tutorial_coq_elpi_tactic.t/test.v b/tests/tutorial_coq_elpi_tactic.t/test.v new file mode 100644 index 000000000..ec1e31767 --- /dev/null +++ b/tests/tutorial_coq_elpi_tactic.t/test.v @@ -0,0 +1,1056 @@ +(*| + +Tutorial on Coq tactics +*********************** + +:author: Enrico Tassi + +.. include:: ../etc/tutorial_style.rst + +.. + Elpi is an extension language that comes as a library + to be embedded into host applications such as Coq. + + Elpi is a variant of λProlog enriched with constraints. + λProlog is a programming language designed to make it easy + to manipulate abstract syntax trees containing binders. + Elpi extends λProlog with programming constructs that are + designed to make it easy to manipulate abstract syntax trees + containing metavariables (also called unification variables, or + evars in the Coq jargon). + + This software, "coq-elpi", is a Coq plugin embedding Elpi and + exposing to the extension language Coq spefic data types (e.g. terms) + and API (e.g. to declare a new inductive type). + + In order to get proper syntax highlighting using VSCode please install the + "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in + Edit -> Preferences -> Colors. + + +This tutorial focuses on the implementation of Coq tactics. + +This tutorial assumes the reader is familiar with Elpi and the HOAS +representation of Coq terms; if it is not the case, please take a look at +these other tutorials first: +`Elpi tutorial `_ +and `Coq HOAS tutorial `_. + +.. contents:: + +================ +Defining tactics +================ + +In Coq a proof is just a term, and an incomplete proof is just a term +with holes standing for the open goals. + +When a proof starts there is just one hole (one goal) and its type +is the statement one wants to prove. Then proof construction makes +progress by instantiation: a term possibly containing holes is +grafted to the hole corresponding to the current goal. What a tactic +does behind the scenes is to synthesize this partial term. + +Let's define a simple tactic that prints the current goal. + +|*) + +From elpi Require Import elpi. + +Elpi Tactic show. +Elpi Accumulate lp:{{ + + solve (goal Ctx _Trigger Type Proof _) _ :- + coq.say "Goal:" Ctx "|-" Proof ":" Type. + +}}. +Elpi Typecheck. + +(*| + +The tactic declaration is made of 3 parts. + +The first one `Elpi Tactic show.` sets the current program to `show`. +Since it is declared as a `Tactic` some code is loaded automatically: + +* APIs (eg :builtin:`coq.say`) and data types (eg Coq :type:`term` s) are loaded from + `coq-builtin.elpi `_ +* some utilities, like :lib:`copy` or :libred:`whd1` are loaded from + `elpi-command-template.elpi `_ + + +The second one `Elpi Accumulate ...` loads some extra code. +The `Elpi Accumulate ...` family of commands lets one accumulate code +taken from: + +* verbatim text `Elpi Accumulate lp:{{ code }}` +* source files `Elpi Accumulate File path` +* data bases (Db) `Elpi Accumulate Db name` + +Accumulating code via inline text or file is equivalent, the AST of `code` +is stored in the .vo file (the external file does not need to be installed). +We invite the reader to look up the description of data bases in the tutorial +about commands. + +Once all the code is accumulated `Elpi Typecheck` verifies that the +code does not contain the most frequent kind of mistakes. This command +considers some mistakes minor and only warns about them. You can +pass `-w +elpi.typecheck` to `coqc` to turn these warnings into errors. + +The entry point for tactics is called :builtin:`solve` which maps a :type:`goal` +into a list of :type:`sealed-goal` (representing subgoals). + +Tactics written in Elpi can be invoked by prefixing its name with `elpi`. + +|*) + +Lemma tutorial x y : x + 1 = y. +elpi show. (* .in .messages *) +Abort. + +(*| + +In the Elpi code up there :e:`Proof` is the hole for the current goal, +:e:`Type` the statement to be proved and :e:`Ctx` the proof context (the list of +hypotheses). Since we don't assign :e:`Proof` the tactic makes no progess. +Elpi prints somethinglike this: + +.. mquote:: .s(elpi).msg{Goal:*X0 c0 c1*} + :language: text + +The first line is the proof context: +proof variables are bound Elpi variables (here :e:`c0` and :e:`c1`), the context +is a list of predicates holding on them (their type in Coq). For example: + +.. code:: + + decl c0 `x` (global (indt «nat»)) + +asserts that :e:`c0` (pretty printed as `x`) has type `nat`. + +Then we see that the value of :e:`Proof` is :e:`X0 c0 c1`. This means that the +proof of the current goal is represented by Elpi's variable :e:`X0` and that +the variable has :e:`c0` and :e:`c1` in scope (the proof term can use them). + +Finally we see the type of the goal `x + 1 = y`. + +The :e:`_Trigger` component, which we did not print, is a variable that, when +assigned, trigger the elaboration of its value against the type of the goal +and obtains a value for :e:`Proof` this way. + +Keeping in mind that the :builtin:`solve` predicate relates one goal to a list of +subgoals, we implement our first tactic which blindly tries to solve the goal. + +|*) + +Elpi Tactic blind. +Elpi Accumulate lp:{{ + solve (goal _ Trigger _ _ _) [] :- Trigger = {{0}}. + solve (goal _ Trigger _ _ _) [] :- Trigger = {{I}}. +}}. +Elpi Typecheck. + +Lemma test_blind : True * nat. +Proof. (* .in *) +split. +- elpi blind. +- elpi blind. +Show Proof. (* .in .messages *) +Qed. + +(*| + +Since the assignment of a term to :e:`Trigger` triggers its elaboration against +the expected type (the goal statement), assigning the wrong proof term +results in a failure which in turn results in the other rule being tried. + +For now, this is all about the low level mechanics of tactics which is +developed further in the section `The-proof-engine`_. + +We now focus on how to better integrate tactics written in Elpi with Ltac. + +--------------------- +Integration with Ltac +--------------------- + +For a simple tactic like `blind` the list of subgoals is easy to write, since +it is empty, but in general one should collect all the holes in +the value of :e:`Proof` (the checked proof term) and build goals out of them. + +There is a family of APIs named after :libtac:`refine`, the mother of all +tactics, in +`elpi-ltac.elpi `_ +which does this job for you. + +Usually a tactic builds a (possibly partial) term and calls +:libtac:`refine` on it. + +Let's rewrite the `blind` tactic using this schema. + +|*) + + +Elpi Tactic blind2. +Elpi Accumulate lp:{{ + solve G GL :- refine {{0}} G GL. + solve G GL :- refine {{I}} G GL. +}}. +Elpi Typecheck. + +Lemma test_blind2 : True * nat. +Proof. (* .in *) +split. +- elpi blind2. +- elpi blind2. +Qed. + +(*| + +This schema works even if the term is partial, that is if it contains holes +corresponding to missing sub proofs. + +Let's write a tactic which opens a few subgoals, for example +let's implement the `split` tactic. + +.. important:: + + Elpi's equality (that is, unification) on Coq terms corresponds to + alpha equivalence, we can use that to make our tactic less blind. + +The head of a rule for the solve predicate is *matched* against the +goal. This operation cannot assign unification variables in the goal, only +variables in the rule's head. +As a consequence the following rule for `solve` is only used when +the statement features an explicit conjunction. + +|*) + +About conj. (* remak the implicit arguments *) + +Elpi Tactic split. +Elpi Accumulate lp:{{ + solve (goal _ _ {{ _ /\ _ }} _ _ as G) GL :- !, + % conj has 4 arguments, but two are implicits + % (_ are added for them and are inferred from the goal) + refine {{ conj _ _ }} G GL. + + solve _ _ :- + % This signals a failure in the Ltac model. A failure + % in Elpi, that is no more cluases to try, is a fatal + % error that cannot be catch by Ltac combinators like repeat. + coq.ltac.fail _ "not a conjunction". +}}. +Elpi Typecheck. + +Lemma test_split : exists t : Prop, True /\ True /\ t. +Proof. (* .in *) +eexists. +repeat elpi split. (* The failure is catched by Ltac's repeat *) +(* Remark that the last goal is left untouched, since + it did not match the pattern {{ _ /\ _ }}. *) +all: elpi blind. +Show Proof. (* .in .messages *) +Qed. + +(*| + +The tactic `split` succeeds twice, stopping on the two identical goals `True` and +the one which is an evar of type `Prop`. + +We then invoke `blind` on all goals. In the third case the type checking +constraint triggered by assigning `{{0}}` to `Trigger` fails because +its type `nat` is not of sort `Prop`, so it backtracks and picks `{{I}}`. + +Another common way to build an Elpi tactic is to synthesize a term and +then call some Ltac piece of code finishing the work. + +The API :libtac:`coq.ltac.call` invokes some Ltac piece +of code passing to it the desired +arguments. Then it builds the list of subgoals. + +Here we pass an integer, which in turn is passed to `fail`, and a term, +which is turn is passed to `apply`. + +|*) + +Ltac helper_split2 n t := fail n || apply t. + +Elpi Tactic split2. +Elpi Accumulate lp:{{ + solve (goal _ _ {{ _ /\ _ }} _ _ as G) GL :- + coq.ltac.call "helper_split2" [int 0, trm {{ conj }}] G GL. + solve _ _ :- + coq.ltac.fail _ "not a conjunction". +}}. +Elpi Typecheck. + +Lemma test_split2 : exists t : Prop, True /\ True /\ t. +Proof. (* .in *) +eexists. +repeat elpi split2. +all: elpi blind. +Qed. + +(*| + +============================= +Arguments and Tactic Notation +============================= + +Elpi tactics can receive arguments. Arguments are received as a list, which +is the last argument of the goal constructor. This suggests that arguments +are attached to the current goal being observed, but we will dive into +this detail later on. + +|*) + +Elpi Tactic print_args. +Elpi Accumulate lp:{{ + solve (goal _ _ _ _ Args) _ :- coq.say Args. +}}. +Elpi Typecheck. + +Lemma test_print_args : True. (* .in *) +elpi print_args 1 x "a b" (1 = 0). (* .in .messages *) +Abort. + +(*| + +The convention is that numbers like `1` are passed as :e:`int 1`, +identifiers or strings are passed as :e:`str "arg"` and terms +have to be put between parentheses. + +.. important:: terms are received in raw format, eg before elaboration + + Indeed the type argument to `eq` is a variable. + One can use APIs like :builtin:`coq.elaborate-skeleton` to infer holes like + :e:`X0`. + +See the :type:`argument` data type +for a detailed decription of all the arguments a tactic can receive. + +Now let's write a tactic which behaves pretty much like the :libtac:`refine` +one from Coq, but prints what it does using the API :builtin:`coq.term->string`. + +|*) + +Elpi Tactic refine. +Elpi Accumulate lp:{{ + solve (goal _ _ Ty _ [trm S] as G) GL :- + % check S elaborates to T of type Ty (the goal) + coq.elaborate-skeleton S Ty T ok, + + coq.say "Using" {coq.term->string T} + "of type" {coq.term->string Ty}, + + % since T is already checked, we don't check it again + refine.no_check T G GL. + + solve (goal _ _ _ _ [trm S]) _ :- + Msg is {coq.term->string S} ^ " does not fit", + coq.ltac.fail _ Msg. +}}. +Elpi Typecheck. + +Lemma test_refine (P Q : Prop) (H : P -> Q) : Q. +Proof. (* .in *) +Fail elpi refine (H). (* .fails *) +elpi refine (H _). +Abort. + +(*| + +-------------------------------- +Ltac arguments to Elpi arguments +-------------------------------- + +It is customary to use the Tactic Notation command to attach a nicer syntax +to Elpi tactics. + +In particular `elpi tacname` accepts as arguments the following `bridges +for Ltac values `_ : + +* `ltac_string:(v)` (for `v` of type `string` or `ident`) +* `ltac_int:(v)` (for `v` of type `int` or `integer`) +* `ltac_term:(v)` (for `v` of type `constr` or `open_constr` or `uconstr` or `hyp`) +* `ltac_(string|int|term)_list:(v)` (for `v` of type `list` of ...) + +Note that the Ltac type associates some semantics to the action of passing +the arguments. For example `hyp` will accept an identifier only if it is +an hypotheses of the context. While `uconstr` does not type check the term, +which is the recommended way to pass terms to an Elpi tactic (since it is +likely to be typed anyway by the Elpi tactic). + +|*) + +Tactic Notation "use" uconstr(t) := + elpi refine ltac_term:(t). + +Tactic Notation "use" hyp(t) := + elpi refine ltac_term:(t). + +Lemma test_use (P Q : Prop) (H : P -> Q) (p : P) : Q. +Proof. (* .in *) +use (H _). +Fail use q. (* .fails .in .messages *) +use p. +Qed. + +Tactic Notation "print" uconstr_list_sep(l, ",") := + elpi print_args ltac_term_list:(l). + +Lemma test_print (P Q : Prop) (H : P -> Q) (p : P) : Q. +print P, p, (H p). (* .in .messages *) +Abort. + +(*| + +======== +Failure +======== + +The :builtin:`coq.error` aborts the execution of both +Elpi and any enclosing LTac context. This failure cannot be catched +by LTac. + +On the contrary the :builtin:`coq.ltac.fail` builtin can be used to +abort the execution of Elpi code in such a way that LTac can catch it. +This API takes an integer akin to LTac's fail depth together with +the error message to be displayed to the user. + +Library functions of the `assert!` family call, by default, :builtin:`coq.error`. +The flag `@ltacfail! N` can be set to alter this behavior and turn erros into +calls to `coq.ltac.fail N`. + +|*) + +Elpi Tactic abort. +Elpi Accumulate lp:{{ + solve _ _ :- coq.error "uncatchable". +}}. + +Goal True. +Fail elpi abort || idtac. +Abort. + +Elpi Tactic fail. +Elpi Accumulate lp:{{ + solve (goal _ _ _ _ [int N]) _ :- coq.ltac.fail N "catchable". +}}. + +Goal True. +elpi fail 0 || idtac. +Fail elpi fail 1 || idtac. +Abort. + + +(*| + +======== +Examples +======== + +------------------------------- +Let's code `assumption` in Elpi +------------------------------- + +`assumption` is a very simple tactic: we look up in the proof +context for an hypothesis which unifies with the goal. +Recall that `Ctx` is made of :builtin:`decl` and :builtin:`def` +(here, for simplicity, we ignore the latter case). + +|*) + +Elpi Tactic assumption. +Elpi Accumulate lp:{{ + solve (goal Ctx _ Ty _ _ as G) GL :- + % H is the name for hyp, Ty is the goal + std.mem Ctx (decl H _ Ty), + refine H G GL. + solve _ _ :- + coq.ltac.fail _ "no such hypothesis". +}}. +Elpi Typecheck. + +Lemma test_assumption (P Q : Prop) (p : P) (q : Q) : P /\ id Q. +Proof. (* .in *) +split. +elpi assumption. +Fail elpi assumption. (* .fails *) +Abort. + +(*| + +As we hinted before, Elpi's equality is alpha equivalence. In the second +goal the assumption has type `Q` but the goal has type `id Q` which is +convertible (unifiable, for Coq's unification) to `Q`. + +Let's improve our tactic looking for an assumption which is unifiable with +the goal, an not just alpha convertible. The :builtin:`coq.unify-leq` +calls Coq's unification for types (on which cumulativity applies, hence the +`-leq` suffix). The :stdlib:`std.mem` utility, thanks to backtracking, +eventually finds an hypothesis that satisfies the following predicate +(ie unifies with the goal). + +|*) + +Elpi Tactic assumption2. +Elpi Accumulate lp:{{ + solve (goal Ctx _ Ty _ _ as G) GL :- + % std.mem is backtracking (std.mem! would stop at the first hit) + std.mem Ctx (decl H _ Ty'), coq.unify-leq Ty' Ty ok, + refine H G GL. + solve _ _ :- + coq.ltac.fail _ "no such hypothesis". +}}. +Elpi Typecheck. + +Lemma test_assumption2 (P Q : Prop) (p : P) (q : Q) : P /\ id Q. +Proof. (* .in *) +split. +all: elpi assumption2. +Qed. + +(*| + +:libtac:`refine` does unify the type of goal with the type of the term, +hence we can simplify the code further. We obtain a +tactic very similar to our initial `blind` tactic, which picks +candidates from the context rather than from the program itself. + +|*) + +Elpi Tactic assumption3. +Elpi Accumulate lp:{{ + solve (goal Ctx _ _ _ _ as G) GL :- + std.mem Ctx (decl H _ _), + refine H G GL. + solve _ _ :- + coq.ltac.fail _ "no such hypothesis". +}}. +Elpi Typecheck. + +Lemma test_assumption3 (P Q : Prop) (p : P) (q : Q) : P /\ id Q. +Proof. (* .in *) +split. +all: elpi assumption3. +Qed. + +(*| + +------------------------ +Let's code `set` in Elpi +------------------------ + +The `set` tactic takes a term, possibly with holes, and +makes a let-in out of it. + +It gives us the occasion to explain the :lib:`copy` utility. + +|*) + +Elpi Tactic find. +Elpi Accumulate lp:{{ + +solve (goal _ _ T _ [trm X]) _ :- + pi x\ + copy X x => copy T (Tabs x), + if (occurs x (Tabs x)) + (coq.say "found" {coq.term->string X}) + (coq.ltac.fail _ "not found"). +}}. +Elpi Typecheck. + +Lemma test_find (P Q : Prop) : (P /\ P) \/ (P /\ Q). +Proof. (* .in *) +elpi find (P). +Fail elpi find (Q /\ _). (* .fails .in .messages *) +elpi find (P /\ _). +Abort. + +(*| + +This first approximation only prints the term it found, or better the first +intance of the given term. + +Now lets focus on :lib:`copy`. An excerpt: + +.. code:: elpi + + copy X X :- name X. % checks X is a bound variable + copy (global _ as C) C. + copy (fun N T F) (fun N T1 F1). + copy T T1, pi x\ copy (F x) (F1 x). + copy (app L) (app L1) :- !, std.map L copy L1. + +Copy implements the identity: it builds, recursively, a copy of the first +term into the second argument. Unless one loads in the context a new rule, +which takes precedence over the identity ones. Here we load: + +.. code:: elpi + + copy X x + +which, at run time, looks like + +.. code:: elpi + + copy (app [global (indt «andn»), sort prop, sort prop, c0, X0 c0 c1]) c2 + +and that rule masks the one for :constructor:`app` when the +sub-term being copied matches `(P /\ _)`. The first time this rule +is used :e:`X0` is assigned, making the rule represent the term `(P /\ P)`. + +Now let's refine the tactic to build a let-in, and complain if the +desired name is already taken. + +|*) + +Elpi Tactic set. +Elpi Accumulate lp:{{ + +solve (goal _ _ T _ [str ID, trm X] as G) GL :- + pi x\ + copy X x => copy T (Tabs x), + if (occurs x (Tabs x)) + (if (coq.ltac.id-free? ID G) true + (coq.warn ID "is already taken, Elpi will make a name up"), + coq.id->name ID Name, + Hole x = {{ _ : lp:{{ Tabs x }} }}, % a hole with a type + refine (let Name _ X x\ Hole x) G GL) + (coq.ltac.fail _ "not found"). + +}}. +Elpi Typecheck. + +Lemma test_set (P Q : Prop) : (P /\ P) \/ (P /\ Q). +Proof. (* .in *) +elpi set "x" (P). +unfold x. +Fail elpi set "x" (Q /\ _). (* .fails .in .messages *) +elpi set "x" (P /\ _). +Abort. + +(*| + +For more examples of (basic) tactics written in Elpi see the +`eltac app `_. + + +.. _The-proof-engine: + +================ +The proof engine +================ + +In this section we dive into the details of the proof engine, that is +how goals are represented in Elpi and how things are wired up behind the scenes. + +Let's inspect the proof state a bit deeper: + +|*) + +Elpi Tactic show_more. +Elpi Accumulate lp:{{ + + solve (goal Ctx _Trigger Type Proof _) _ :- + coq.say "Goal:" Ctx "|-" Proof ":" Type, + coq.say "Proof state:", + coq.sigma.print. + +}}. +Elpi Typecheck. + +Lemma test_show_more x : x + 1 = 0. +elpi show_more. (* .in .messages *) +Abort. + +(*| + +In addition to the goal we print the Elpi and Coq proof state, +plus the link between them. +The proof state is the collection of goals together with their types. + +On the Elpi side this state is represented by constraints for the :e:`evar` +predicate. + +.. mquote:: .s(elpi show_more).msg{*c0*evar (X1 c0)*suspended on X1, X0*} + :language: text + +One can recognize the set of bound variables `{c0}`, the hypothetical +context of rules about these variable (that also corresponds to the proof +context), and finally the suspended goal :e:`evar (X1 c0) .. (X0 c0)`. + +The set of constraints on `evar` represents the Coq data structure called +sigma (sometimes also called evd or evar_map) that is used to +represent the proof state in Coq. It is printed just afterwards: + +.. mquote:: .s(elpi show_more).msg{EVARS:*[?]X57*x + 1 = 0*} + :language: text + +.. mquote:: .s(elpi show_more).msg{Coq-Elpi mapping:*RAW:*[?]X57 <-> *X1*ELAB:*[?]X57 <-> *X0*} + :language: text + +Here `?X57` is a Coq evar linked with Elpi's :e:`X0` and :e:`X1`. +:e:`X1` represents the goal (the trigger) while :e:`X0` represent the proof. +The meaning of the :e:`evar` Elpi predicate linking the two is that the term +assigned to the trigger :e:`X1` has to be elaborated to the final proof term +:e:`X0`, that should be a well typed term of type `x + 1 = 0`. +This means that when an Elpi tactic assigns a value to :e:`X1` some procedure to +turn that value into :e:`X0` is triggered. That procedure is called +elaboration and it is currently implemented by calling the +:builtin:`coq.elaborate-skeleton` API. + +Given this set up, it is impossible to use a term of the wrong type as a +Proof. Let's rewrite the `split` tactic without using :libtac:`refine`. + +|*) + +Elpi Tactic split_ll. +Elpi Accumulate lp:{{ + solve (goal Ctx Trigger {{ lp:A /\ lp:B }} Proof []) GL :- !, + Trigger = {{ conj _ _ }}, % triggers elaboration, filling Proof + Proof = {{ conj lp:Pa lp:Pb }}, + GL = [seal G1, seal G2], + G1 = goal Ctx _ A Pa [], + G2 = goal Ctx _ B Pb []. + solve _ _ :- + coq.ltac.fail _ "not a conjunction". +}}. +Elpi Typecheck. + +Lemma test_split_ll : exists t : Prop, True /\ True /\ t. +Proof. (* .in *) +eexists. +repeat elpi split_ll. +all: elpi blind. +Qed. + +(*| + +Crafting by hand the list of subgoal is not easy. +In particular here we did not set up the new trigger for :e:`Pa` and :e:`Pb`, +nor seal the goals appropriately (we did not bind proof variables). + +The :builtin:`coq.ltac.collect-goals` API helps us doing this. + +|*) + +Elpi Tactic split_ll_bis. +Elpi Accumulate lp:{{ + solve (goal Ctx Trigger {{ lp:A /\ lp:B }} Proof []) GL :- !, + % this triggers the elaboration + Trigger = {{ conj _ _ }}, + % we only take main goals + coq.ltac.collect-goals Proof GL _ShelvedGL. + solve _ _ :- + coq.ltac.fail _ "not a conjunction". +}}. +Elpi Typecheck. + +Lemma test_split_ll_bis : exists t : Prop, True /\ True /\ t. +Proof. (* .in *) +eexists. +repeat elpi split_ll_bis. +all: elpi blind. +Qed. + +(*| + +At the light of that, :libtac:`refine` is simply: + +.. code:: elpi + + refine T (goal _ RawEv _ Ev _) GS :- + RawEv = T, coq.ltac.collect-goals Ev GS _. + +Now that we know the low level plumbing, we can use :libtac:`refine` ;-) + +The only detail we still have to explain is what exactly a +:type:`sealed-goal` is. A sealed goal wraps into a single object all +the proof variables and the assumptions about them, making this object easy +(or better, sound) to pass around. + +------------------ +multi-goal tactics +------------------ + +Since Coq 8.4 tactics can see more than one goal (multi-goal tactics). +You can access this feature by using `all:` goal selector: + +* if the tactic is a regular one, it will be used on each goal independently +* if the tactic is a multi-goal one, it will receive all goals + +In Elpi you can implement a multi-goal tactic by providing a rule for +the :builtin:`msolve` predicate. Since such a tactic will need to manipulate +multiple goals, potentially living in different proof context, it receives +a list of :type:`sealed-goal`, a data type which seals a goal and +its proof context. + +|*) + +Elpi Tactic ngoals. +Elpi Accumulate lp:{{ + + msolve GL _ :- + coq.say "#goals =" {std.length GL}, + coq.say GL. + +}}. +Elpi Typecheck. + +Lemma test_undup (P Q : Prop) : P /\ Q. +Proof. (* .in *) +split. +all: elpi ngoals. +Abort. + +(*| + +This simple tactic prints the number of goals it receives, as well as +the list itself. We see something like: + +.. mquote:: .s(elpi ngoals).msg{*goals =*} + :language: text + +.. mquote:: .s(elpi ngoals).msg{*nabla*} + :language: elpi + +:constructor:`nabla` binds all proof variables, then :constructor:`seal` +holds a regular goal, which in turn carries the proof context. + +In order to operate inside a goal one can use the :libtac:`coq.ltac.open` utility, +which postulates all proof variables using :e:`pi x\ ` and loads the proof +context using :e:`=>`. + +Operating on multiple goals at the same time is doable, but not easy. +In particular the two proof context have to be related in some way. + +The following simple multi goal tactic shrinks the list of goals by +removing duplicates. As one can see, there is much room for improvement +in the :e:`same-ctx` predicate. + +|*) + +Elpi Tactic undup. +Elpi Accumulate lp:{{ + + pred same-goal i:sealed-goal, i:sealed-goal. + same-goal (nabla G1) (nabla G2) :- + % TODO: proof variables could be permuted + pi x\ same-goal (G1 x) (G2 x). + same-goal (seal (goal Ctx1 _ Ty1 P1 _) as G1) + (seal (goal Ctx2 _ Ty2 P2 _) as G2) :- + same-ctx Ctx1 Ctx2, + % this is an elpi builtin, aka same_term, which does not + % unify but rather compare two terms without assigning variables + Ty1 == Ty2, + P1 = P2. + + pred same-ctx i:goal-ctx, i:goal-ctx. + same-ctx [] []. + same-ctx [decl V _ T1|C1] [decl V _ T2|C2] :- + % TODO: we could compare up to permutation... + % TODO: we could try to relate def and decl + T1 == T2, + same-ctx C1 C2. + + pred undup i:sealed-goal, i:list sealed-goal, o:list sealed-goal. + undup _ [] []. + undup G [G1|GN] GN :- same-goal G G1. + undup G [G1|GN] [G1|GL] :- undup G GN GL. + + msolve [G1|GS] [G1|GL] :- + % TODO: we could find all duplicates, not just + % copies of the first goal... + undup G1 GS GL. + +}}. +Elpi Typecheck. + +Lemma test_undup (P Q : Prop) (p : P) (q : Q) : P /\ Q /\ P. +Proof. (* .in *) +repeat split. +Show Proof. (* .in .messages *) +all: elpi undup. +Show Proof. (* .in .messages *) +- apply p. +- apply q. +Qed. + +(*| + +The two calls to show proof display, respectively: + +.. mquote:: .s(Show Proof).msg{*conj [?]Goal (conj [?]Goal0 [?]Goal1)*} + :language: text + +.. mquote:: .s(Show Proof).msg{*conj [?]Goal (conj [?]Goal0 [?]Goal)*} + :language: text + +the proof term is the same but for the fact that after the tactic the first +and last missing subterm (incomplete proof tree branch) are represented by +the same hole `?Goal0`. Indeed by solving one, we can also solve the other. + +------------- +LCF tacticals +------------- + +On the notion of sealed-goal it is easy to define the usual LCF combinators, +also known as Ltac tacticals. Tacticals usually take in input one or more +tactic, here the precise type definition: + +.. code:: elpi + + typeabbrev tactic (sealed-goal -> (list sealed-goal -> prop)). + +A few tacticals can be fond in the +`elpi-ltac.elpi file `_. +For example this is the code of :libtac:`try`: + +.. code:: elpi + + pred try i:tactic, i:sealed-goal, o:list sealed-goal. + try T G GS :- T G GS. + try _ G [G]. + +------------------------------ +Setting arguments for a tactic +------------------------------ + +As we hinted before, tactic arguments are attached to the goal since +they can mention proof variables. So the Ltac code: + +.. code:: coq + + intro H; apply H. + +has to be seen as 3 steps, starting from a goal `G`: + +* introduction of `H`, obtaining `G1` +* setting the argument `H`, obtaining `G2` +* calling apply, obtaining `G3` + +|*) + +Elpi Tactic argpass. +Elpi Accumulate lp:{{ + +% this directive lets you use short names +shorten coq.ltac.{ open, thenl, all }. + +type intro open-tactic. % goal -> list sealed-goal +intro G GL :- refine {{ fun H => _ }} G GL. + +type set-arg-n-hyp int -> open-tactic. +set-arg-n-hyp N (goal Ctx _ _ _ _ as G) [SG1] :- + std.nth N Ctx (decl X _ _), + coq.ltac.set-goal-arguments [trm X] G (seal G) SG1. + +type apply open-tactic. +apply (goal _ _ _ _ [trm T] as G) GL :- refine T G GL. + +msolve SG GL :- + all (thenl [ open intro, + open (set-arg-n-hyp 0), + open apply ]) SG GL. + +}}. +Elpi Typecheck. + +Lemma test_argpass (P : Prop) : P -> P. +Proof. (* .in *) +elpi argpass. +Qed. + +(*| + +Of course the tactic playing the role of `intro` could communicate back +a datum to be passed to what follows + +.. code:: elpi + + thenl [ open (tac1 Datum), open (tac2 Datum) ] + +but the binder structure of :type:`sealed-goal` would prevent :e:`Datum` +to mention proof variables, that would otherwise escape the sealing. + +The utility :libtac:`set-goal-arguments`: + +.. code:: elpi + + coq.ltac.set-goal-arguments Args G G1 G1wArgs + +tries to move :e:`Args` from the context of :e:`G` to the one of :e:`G1`. +Relating the two proof contexts is not obvious: you may need to write your +own procedure if the two contexts are very distant. + +================ +Tactics in terms +================ + +Elpi tactics can be used inside terms via the usual `ltac:(...)` +quotation, but can also be exported to the term grammar. + +Here we write a simple tactic for default values, which +optionally takes a bound to the search depth. + +|*) + +Elpi Tactic default. +Elpi Accumulate lp:{{ + + pred default i:term, i:int, o:term. + + default _ 0 _ :- coq.ltac.fail _ "max search depth reached". + default {{ nat }} _ {{ 46 }}. + default {{ bool }} _ {{ false }}. + default {{ list lp:A }} Max {{ cons lp:D nil }} :- + Max' is Max - 1, default A Max' D. + + solve (goal _ _ T _ [] as G) GL :- + default T 9999 P, + refine P G GL. + +}}. +Elpi Typecheck. +Elpi Export default. + +Definition foo : nat := default. +Print foo. + +Definition bar : list bool := default. +Print bar. + +(*| + +The grammar entries for Elpi tactics in terms take an arbitrary +number of arguments with the limitation that they are all terms: +you can't pass a string or an integer as one would normally do. + +Here we use Coq's primitive integers to pass the search depth +(in a compact way). + +|*) + +Elpi Accumulate default lp:{{ + solve (goal _ _ T _ [trm (primitive (uint63 Max))] as G) GL :- + coq.uint63->int Max MaxI, + default T MaxI P, + refine P G GL. +}}. +Elpi Typecheck. + +From Coq Require Import Uint63. +Open Scope uint63_scope. + +Fail Definition baz : list nat := default 1. (* .fails *) + +Definition baz : list nat := default 2. +Print baz. + +(*| + +That is all folks! + +|*) diff --git a/tests/tutorial_elpi_lang.t/run.t b/tests/tutorial_elpi_lang.t/run.t new file mode 100644 index 000000000..b628c5af7 --- /dev/null +++ b/tests/tutorial_elpi_lang.t/run.t @@ -0,0 +1,594 @@ + $ . ../setup-project.sh + $ dune build test.vo + The age of alice is 20 + Query assignments: + A = 20 + mallory is 23 years old + Query assignments: + P = mallory + alice is 20 years old + Query assignments: + P = alice + mallory and bob are 23 years old + Query assignments: + A = 23 + P = mallory + Q = bob + I picked P = mallory + I picked Q = mallory + I picked Q = bob + the last choice worked! + mallory and bob are 23 years old + Query assignments: + A = 23 + P = mallory + Q = bob + bob is older than alice + Query assignments: + X = alice + both bob and mallory are older than alice + Query assignments: + X = alice + F = c0 \ age alice c0 + F 20 = age alice 20 + F 23 = age alice 23 + Query assignments: + F = c0 \ + age alice c0 + λx.x ~> fun c0 \ c0 + (λx.x) (λx.x) ~> fun c0 \ c0 + Query assignments: + I = fun c0 \ c0 + T = fun c0 \ c0 + T1 = fun c0 \ c0 + (Fst foo bar) ~> foo + (foo bar) ~> app foo bar + Query assignments: + Fst = fun c0 \ fun c1 \ c0 + S = app foo bar + S1 = app foo bar + T = app (app (fun c0 \ fun c1 \ c0) foo) bar + T1 = foo + The type of λx.λy.x is: arr X0 (arr X1 X0) + Query assignments: + Ty = arr X0 (arr X1 X0) + Error: fun c0 \ app c0 c0 has no type + Query assignments: + Delta = fun c0 \ app c0 c0 + Ty = X0 + 2 + 1 = s (s (s z)) + Query assignments: + R = s (s (s z)) + Query assignments: + X = X0 + Z = X1 + Syntactic constraints: sum X0 (s z) X1 /* suspended on X0 */ + The result is: s z + Query assignments: + X = z + Z = s z + Query assignments: + X = s z + sum X0 (s z) X1 /* suspended on X0 */ + Currently Y = X1 + sum X2 (s z) X3 /* suspended on X2 */ + Currently Y = s X3 + Finally Y = s (s z) + Query assignments: + X = s z + Y = s (s z) + Z = z + Query assignments: + X = X0 + Syntactic constraints: + even X0 /* suspended on X0 */ odd X0 /* suspended on X0 */ + X0 can't be even and odd at the same time + Query assignments: + A = [1, 2, 3, 3, 2, 1] + Query assignments: + A = [1, 2, 3, 3, 2, 1] + result = 5 + Query assignments: + X = result = + Y = 5 + result = 5 + Query assignments: + Spilled_1 = 5 + Query assignments: + R1 = X0 + R2 = [2, 3, 4] + R3 = [2, 3, 4] + Query assignments: + R = [2, 3, 4] + Y = c0 + arr X0 (arr X1 X0) + Query assignments: + Ty = arr X0 (arr X1 X0) + run 1 {{{ + + rid:0 step:1 gid:6 user:curgoal = , + of (fun c0 \ fun c1 \ c0) X0 , coq.say X0 + + rid:0 step:1 gid:6 user:rule = and + + rid:0 step:1 gid:6 user:subgoal = 7 + + rid:0 step:1 gid:7 user:newgoal = of (fun c0 \ fun c1 \ c0) X0 + + rid:0 step:1 gid:6 user:subgoal = 8 + + rid:0 step:1 gid:8 user:newgoal = coq.say X0 + + rid:0 step:1 gid:6 user:rule:and = success + + }}} -> (0.000s) + run 2 {{{ + + rid:0 step:2 gid:7 user:curgoal = of + of (fun c0 \ fun c1 \ c0) X0 + + rid:0 step:2 gid:7 user:rule = backchain + + rid:0 step:2 gid:7 user:rule:backchain:candidates = File "./test.v", line 596, column 3, character 15363: + + }}} -> (0.000s) + select 3 {{{ + + rid:0 step:2 gid:7 user:rule:backchain:try = File "./test.v", line 596, column 3, character 15363: + (of (fun A0) (arr A1 A2)) :- ( + pi (c0 \ + (of c0 A1 => of (A0 c0) A2))). + + rid:0 step:2 gid:0 user:assign = A0 := c0 \ + fun c1 \ c0 + + rid:0 step:2 gid:0 user:assign = X0 := arr X1 X2 + + rid:0 step:2 gid:7 user:subgoal = 9 + + rid:0 step:2 gid:9 user:newgoal = pi c0 \ of c0 X1 => of (fun c1 \ c0) X2 + + rid:0 step:2 gid:9 user:rule:backchain = success + + }}} -> (0.000s) + run 3 {{{ + + rid:0 step:3 gid:9 user:curgoal = pi + pi c0 \ of c0 X1 => of (fun c1 \ c0) X2 + + rid:0 step:3 gid:9 user:rule = pi + + rid:0 step:3 gid:9 user:subgoal = 10 + + rid:0 step:3 gid:10 user:newgoal = of c0 X1 => of (fun c1 \ c0) X2 + + rid:0 step:3 gid:10 user:rule:pi = success + + }}} -> (0.000s) + run 4 {{{ + + rid:0 step:4 gid:10 user:curgoal = => + of c0 X1 => of (fun c1 \ c0) X2 + + rid:0 step:4 gid:10 user:rule = implication + + rid:0 step:4 gid:10 user:subgoal = 11 + + rid:0 step:4 gid:11 user:newgoal = of (fun c1 \ c0) X2 + + rid:0 step:4 gid:11 user:rule:implication = success + + }}} -> (0.000s) + run 5 {{{ + + rid:0 step:5 gid:11 user:curgoal = of + of (fun c1 \ c0) X2 + + rid:0 step:5 gid:11 user:rule = backchain + + rid:0 step:5 gid:11 user:rule:backchain:candidates = File "./test.v", line 596, column 3, character 15363: + + }}} -> (0.000s) + select 4 {{{ + + rid:0 step:5 gid:11 user:rule:backchain:try = File "./test.v", line 596, column 3, character 15363: + (of (fun A0) (arr A1 A2)) :- ( + pi (c0 \ + (of c0 A1 => of (A0 c0) A2))). + + rid:0 step:5 gid:0 user:assign = A0 := c1 \ + c0 + + rid:0 step:5 gid:0 user:assign = X2 := arr X3 X4 + + rid:0 step:5 gid:11 user:subgoal = 12 + + rid:0 step:5 gid:12 user:newgoal = pi c1 \ of c1 X3 => of c0 X4 + + rid:0 step:5 gid:12 user:rule:backchain = success + + }}} -> (0.000s) + run 6 {{{ + + rid:0 step:6 gid:12 user:curgoal = pi + pi c1 \ of c1 X3 => of c0 X4 + + rid:0 step:6 gid:12 user:rule = pi + + rid:0 step:6 gid:12 user:subgoal = 13 + + rid:0 step:6 gid:13 user:newgoal = of c1 X3 => of c0 X4 + + rid:0 step:6 gid:13 user:rule:pi = success + + }}} -> (0.000s) + run 7 {{{ + + rid:0 step:7 gid:13 user:curgoal = => + of c1 X3 => of c0 X4 + + rid:0 step:7 gid:13 user:rule = implication + + rid:0 step:7 gid:13 user:subgoal = 14 + + rid:0 step:7 gid:14 user:newgoal = of c0 X4 + + rid:0 step:7 gid:14 user:rule:implication = success + + }}} -> (0.000s) + run 8 {{{ + + rid:0 step:8 gid:14 user:curgoal = of + of c0 X4 + + rid:0 step:8 gid:14 user:rule = backchain + + rid:0 step:8 gid:14 user:rule:backchain:candidates = File "(context step_id:4)", line 1, column 0, character 0: + + }}} -> (0.000s) + select 5 {{{ + + rid:0 step:8 gid:14 user:rule:backchain:try = File "(context step_id:4)", line 1, column 0, character 0: + (of c0 X1) :- . + + rid:0 step:8 gid:0 user:assign = X1 := X4 + + rid:0 step:8 gid:14 user:rule:backchain = success + + }}} -> (0.000s) + run 9 {{{ + + rid:0 step:9 gid:8 user:curgoal = coq.say + coq.say (arr X4 (arr X3 X4)) + + rid:0 step:9 gid:8 user:rule = builtin + + rid:0 step:9 gid:8 user:rule:builtin:name = coq.say + + arr X4 (arr X3 X4) + rid:0 step:9 gid:8 user:rule:builtin = success + + }}} -> (0.000s) + Query assignments: + Ty = arr X4 (arr X3 X4) + run 1 {{{ + + rid:1 step:1 gid:15 user:curgoal = , + of (fun c0 \ app c0 c0) X0 , coq.say X0 + + rid:1 step:1 gid:15 user:rule = and + + rid:1 step:1 gid:15 user:subgoal = 16 + + rid:1 step:1 gid:16 user:newgoal = of (fun c0 \ app c0 c0) X0 + + rid:1 step:1 gid:15 user:subgoal = 17 + + rid:1 step:1 gid:17 user:newgoal = coq.say X0 + + rid:1 step:1 gid:15 user:rule:and = success + + }}} -> (0.000s) + run 2 {{{ + + rid:1 step:2 gid:16 user:curgoal = of + of (fun c0 \ app c0 c0) X0 + + rid:1 step:2 gid:16 user:rule = backchain + + rid:1 step:2 gid:16 user:rule:backchain:candidates = File "./test.v", line 596, column 3, character 15363: + + }}} -> (0.000s) + select 3 {{{ + + rid:1 step:2 gid:16 user:rule:backchain:try = File "./test.v", line 596, column 3, character 15363: + (of (fun A0) (arr A1 A2)) :- ( + pi (c0 \ + (of c0 A1 => of (A0 c0) A2))). + + rid:1 step:2 gid:0 user:assign = A0 := c0 \ + app c0 c0 + + rid:1 step:2 gid:0 user:assign = X0 := arr X1 X2 + + rid:1 step:2 gid:16 user:subgoal = 18 + + rid:1 step:2 gid:18 user:newgoal = pi c0 \ of c0 X1 => of (app c0 c0) X2 + + rid:1 step:2 gid:18 user:rule:backchain = success + + }}} -> (0.000s) + run 3 {{{ + + rid:1 step:3 gid:18 user:curgoal = pi + pi c0 \ of c0 X1 => of (app c0 c0) X2 + + rid:1 step:3 gid:18 user:rule = pi + + rid:1 step:3 gid:18 user:subgoal = 19 + + rid:1 step:3 gid:19 user:newgoal = of c0 X1 => of (app c0 c0) X2 + + rid:1 step:3 gid:19 user:rule:pi = success + + }}} -> (0.000s) + run 4 {{{ + + rid:1 step:4 gid:19 user:curgoal = => + of c0 X1 => of (app c0 c0) X2 + + rid:1 step:4 gid:19 user:rule = implication + + rid:1 step:4 gid:19 user:subgoal = 20 + + rid:1 step:4 gid:20 user:newgoal = of (app c0 c0) X2 + + rid:1 step:4 gid:20 user:rule:implication = success + + }}} -> (0.000s) + run 5 {{{ + + rid:1 step:5 gid:20 user:curgoal = of + of (app c0 c0) X2 + + rid:1 step:5 gid:20 user:rule = backchain + + rid:1 step:5 gid:20 user:rule:backchain:candidates = File "./test.v", line 591, column 3, character 15198: + + }}} -> (0.000s) + select 4 {{{ + + rid:1 step:5 gid:20 user:rule:backchain:try = File "./test.v", line 591, column 3, character 15198: + (of (app A0 A1) A2) :- ( + of A0 (arr A3 A2)), + (of A1 A3). + + rid:1 step:5 gid:0 user:assign = A0 := c0 + + rid:1 step:5 gid:0 user:assign = A1 := c0 + + rid:1 step:5 gid:0 user:assign = A2 := X2 + + rid:1 step:5 gid:20 user:subgoal = 21 + + rid:1 step:5 gid:21 user:newgoal = of c0 (arr X3^1 X2) + + rid:1 step:5 gid:21 user:subgoal = 22 + + rid:1 step:5 gid:22 user:newgoal = of c0 X3^1 + + rid:1 step:5 gid:21 user:rule:backchain = success + + }}} -> (0.000s) + run 6 {{{ + + rid:1 step:6 gid:21 user:curgoal = of + of c0 (arr X3^1 X2) + + rid:1 step:6 gid:21 user:rule = backchain + + rid:1 step:6 gid:21 user:rule:backchain:candidates = File "(context step_id:4)", line 1, column 0, character 0: + + }}} -> (0.000s) + select 5 {{{ + + rid:1 step:6 gid:21 user:rule:backchain:try = File "(context step_id:4)", line 1, column 0, character 0: + (of c0 X1) :- . + + rid:1 step:6 gid:0 user:assign:expand = X3^1 := X4 c0 + + rid:1 step:6 gid:0 user:assign:restrict = 0 X4 c0 := c0 \ + .X5 + + rid:1 step:6 gid:0 user:assign = X1 := arr X5 X2 + + rid:1 step:6 gid:21 user:rule:backchain = success + + }}} -> (0.000s) + run 7 {{{ + + rid:1 step:7 gid:22 user:curgoal = of + of c0 X5 + + rid:1 step:7 gid:22 user:rule = backchain + + rid:1 step:7 gid:22 user:rule:backchain:candidates = File "(context step_id:4)", line 1, column 0, character 0: + + }}} -> (0.000s) + select 6 {{{ + + rid:1 step:7 gid:22 user:rule:backchain:try = File "(context step_id:4)", line 1, column 0, character 0: + (of c0 (arr X5 X2)) :- . + + rid:1 step:7 gid:22 user:backchain:fail-to = unify X5 with arr X5 X2 + + }}} -> (0.000s) + select 7 {{{ + + rid:1 step:7 gid:22 user:rule:backchain = fail + + }}} -> (0.000s) + run 6 {{{ + + rid:2 step:6 gid:29 user:curgoal = pi + pi c1 \ of c1 X0 => of c0 X1 + + rid:2 step:6 gid:29 user:rule = pi + + rid:2 step:6 gid:29 user:subgoal = 30 + + rid:2 step:6 gid:30 user:newgoal = of c1 X0 => of c0 X1 + + rid:2 step:6 gid:30 user:rule:pi = success + + }}} -> (0.000s) + run 7 {{{ + + rid:2 step:7 gid:30 user:curgoal = => + of c1 X0 => of c0 X1 + + rid:2 step:7 gid:30 user:rule = implication + + rid:2 step:7 gid:30 user:subgoal = 31 + + rid:2 step:7 gid:31 user:newgoal = of c0 X1 + + rid:2 step:7 gid:31 user:rule:implication = success + + }}} -> (0.000s) + run 8 {{{ + + rid:2 step:8 gid:31 user:curgoal = of + of c0 X1 + + rid:2 step:8 gid:31 user:rule = backchain + + rid:2 step:8 gid:31 user:rule:backchain:candidates = File "(context step_id:4)", line 1, column 0, character 0: + + }}} -> (0.000s) + select 5 {{{ + + rid:2 step:8 gid:31 user:rule:backchain:try = File "(context step_id:4)", line 1, column 0, character 0: + (of c0 X2) :- . + + rid:2 step:8 gid:0 user:assign = X2 := X1 + + rid:2 step:8 gid:31 user:rule:backchain = success + + }}} -> (0.000s) + arr X1 (arr X0 X1) + Query assignments: + Ty = arr X1 (arr X0 X1) + run 2 {{{ + + rid:3 step:2 gid:33 user:curgoal = of + of (fun c0 \ fun c1 \ c0) X0 + + rid:3 step:2 gid:33 user:rule = backchain + + rid:3 step:2 gid:33 user:rule:backchain:candidates = File "./test.v", line 596, column 3, character 15363: + + }}} -> (0.000s) + select 3 {{{ + + rid:3 step:2 gid:33 user:rule:backchain:try = File "./test.v", line 596, column 3, character 15363: + (of (fun A0) (arr A1 A2)) :- ( + pi (c0 \ + (of c0 A1 => of (A0 c0) A2))). + + rid:3 step:2 gid:0 user:assign = A0 := c0 \ + fun c1 \ c0 + + rid:3 step:2 gid:0 user:assign = X0 := arr X1 X2 + + rid:3 step:2 gid:33 user:subgoal = 35 + + rid:3 step:2 gid:35 user:newgoal = pi c0 \ of c0 X1 => of (fun c1 \ c0) X2 + + rid:3 step:2 gid:35 user:rule:backchain = success + + }}} -> (0.000s) + run 5 {{{ + + rid:3 step:5 gid:37 user:curgoal = of + of (fun c1 \ c0) X2 + + rid:3 step:5 gid:37 user:rule = backchain + + rid:3 step:5 gid:37 user:rule:backchain:candidates = File "./test.v", line 596, column 3, character 15363: + + }}} -> (0.000s) + select 4 {{{ + + rid:3 step:5 gid:37 user:rule:backchain:try = File "./test.v", line 596, column 3, character 15363: + (of (fun A0) (arr A1 A2)) :- ( + pi (c0 \ + (of c0 A1 => of (A0 c0) A2))). + + rid:3 step:5 gid:0 user:assign = A0 := c1 \ + c0 + + rid:3 step:5 gid:0 user:assign = X2 := arr X3 X4 + + rid:3 step:5 gid:37 user:subgoal = 38 + + rid:3 step:5 gid:38 user:newgoal = pi c1 \ of c1 X3 => of c0 X4 + + rid:3 step:5 gid:38 user:rule:backchain = success + + }}} -> (0.000s) + run 8 {{{ + + rid:3 step:8 gid:40 user:curgoal = of + of c0 X4 + + rid:3 step:8 gid:40 user:rule = backchain + + rid:3 step:8 gid:40 user:rule:backchain:candidates = File "(context step_id:4)", line 1, column 0, character 0: + + }}} -> (0.000s) + select 5 {{{ + + rid:3 step:8 gid:40 user:rule:backchain:try = File "(context step_id:4)", line 1, column 0, character 0: + (of c0 X1) :- . + + rid:3 step:8 gid:0 user:assign = X1 := X4 + + rid:3 step:8 gid:40 user:rule:backchain = success + + }}} -> (0.000s) + arr X4 (arr X3 X4) + Query assignments: + Ty = arr X4 (arr X3 X4) + run 8 {{{ + + rid:4 step:8 gid:49 user:curgoal = of + of c0 X0 + + rid:4 step:8 gid:49 user:rule = backchain + + rid:4 step:8 gid:49 user:rule:backchain:candidates = File "(context step_id:4)", line 1, column 0, character 0: + + }}} -> (0.000s) + select 5 {{{ + + rid:4 step:8 gid:49 user:rule:backchain:try = File "(context step_id:4)", line 1, column 0, character 0: + (of c0 X1) :- . + + rid:4 step:8 gid:0 user:assign = X1 := X0 + + rid:4 step:8 gid:49 user:rule:backchain = success + + }}} -> (0.000s) + arr X0 (arr X2 X0) + Query assignments: + Ty = arr X0 (arr X2 X0) + calling mypred on 3 + calling mypred on 2 + calling mypred on 1 + calling mypred on 0 + ok + Query assignments: + A = X0 + B = X0 + C = X0 diff --git a/tests/tutorial_elpi_lang.t/test.v b/tests/tutorial_elpi_lang.t/test.v new file mode 100644 index 000000000..2fcb6b2b1 --- /dev/null +++ b/tests/tutorial_elpi_lang.t/test.v @@ -0,0 +1,1564 @@ +(*| + +Tutorial on the Elpi programming language +***************************************** + +:author: Enrico Tassi + +.. include:: ../etc/tutorial_style.rst + +.. + Elpi is an extension language that comes as a library + to be embedded into host applications such as Coq. + + Elpi is a variant of λProlog enriched with constraints. + λProlog is a programming language designed to make it easy + to manipulate abstract syntax trees containing binders. + Elpi extends λProlog with modes and constraints in order + to make it easy to manipulate abstract syntax trees + containing metavariables (also called unification variables, or + evars in the Coq jargon). + + This software, "coq-elpi", is a Coq plugin embedding Elpi and + exposing to the extension language Coq specific data types (e.g. terms) + and API (e.g. to declare a new inductive type). + + In order to get proper syntax highlighting using VSCode please install the + "gares.coq-elpi-lang" extension. In CoqIDE please chose "coq-elpi" in + Edit -> Preferences -> Colors. + +This little tutorial does not talk about Coq, but rather focuses on +Elpi as a programming language. It assumes no previous knowledge of +Prolog, λProlog or Elpi. Coq is used as an environment for stepping trough +the tutorial one paragraph at a time. The text between `lp:{{` and `}}` is +Elpi code, while the rest are Coq directives to drive the Elpi interpreter. + +.. contents:: + +|*) + +From elpi Require Import elpi. (* .none *) + +(*| + +================= +Logic programming +================= + +Elpi is a dialect of λProlog enriched with constraints. We start by introducing +the first order fragment of λProlog, i.e. the terms will not contain binders. +Later we cover terms with binders and constraints. + +Our first program is called `tutorial`. +We begin by declaring the signature of our terms. +Here we declare that :e:`person` is a type, and that +:e:`mallory`, :e:`bob` and :e:`alice` are terms of that type. + +|*) + +Elpi Program tutorial lp:{{ + + kind person type. + type mallory, bob, alice person. + +}}. + +(*| + +An Elpi program is made of rules that declare +when predicates hold and that are accumulated one after the +other. Rules are also called clauses in Prolog's slang, so we may use both +terms interchangeably. + +The next code snippet accumulates on top +of the current `tutorial` program a predicate declaration for :e:`age` +and three rules representing our knowledge about our terms. + +|*) + +Elpi Accumulate lp:{{ + + pred age o:person, o:int. + + age mallory 23. + age bob 23. + age alice 20. + +}}. + +(*| + +The predicate :e:`age` has two arguments, the former is a person while +the latter is an integer. The label :e:`o:` (standing for output) +is a mode declaration, which we will explain later (ignore it for now). + +.. note:: :stdtype:`int` is the built-in data type of integers + + Integers come with usual arithmetic operators, see the :stdlib:`calc` built-in. + +In order to run our program we have to write a query, +i.e. a predicate expression containing variables such as: + +.. code:: elpi + + age alice A + +The execution of the program is expected to assign a value to :e:`A`, which +represents the age of :e:`alice`. + +.. important:: + + Syntactic conventions: + + * variables are identifiers starting with a capital letter, eg + :e:`A`, :e:`B`, :e:`FooBar`, :e:`Foo_bar`, :e:`X1` + * constants (for individuals or predicates) are identifiers + starting with a lowercase letter, eg + :e:`foo`, :e:`bar`, :e:`this_that`, :e:`camelCase`, + :e:`dash-allowed`, :e:`qmark_too?`, :e:`arrows->and.dots.as<-well` + +A query can be composed of many predicate expressions separated by :e:`,` +that stands for conjunction: we want to get an answer to all the +predicate expressions. + +|*) + +Elpi Query lp:{{ + + age alice A, coq.say "The age of alice is" A + +}}. + +(*| + +:builtin:`coq.say` is a built-in predicate provided by Coq-Elpi which +prints its arguments. +You can look at the output buffer of Coq to see the value for :e:`A` or hover +or toggle the little bubble after `}}.` if you are reading the tutorial with a +web browser. + +.. note:: :stdtype:`string` is a built-in data type + + Strings are delimited by double quotes and ``\`` is the escape symbol. + +The predicate :e:`age` represents a *relation* (in contrast to a function) +and it computes both ways: we can ask Elpi which person :e:`P` is 23 years old. + +|*) + +Elpi Query lp:{{ + + age P 23, coq.say P "is 23 years old" + +}}. + +(*| + +----------- +Unification +----------- + +Operationally the query :e:`age P 23` is *unified* with each +and every rule present in the program starting from the first one. + +Unification compares two +terms structurally and eventually assigns variables. +For example for the first rule of the program we obtain +the following unification problem: + +.. code:: elpi + + age P 23 = age mallory 23 + +This problem can be simplified into smaller unification problems following +the structure of the terms: + +.. code:: elpi + + age = age + P = mallory + 23 = 23 + +The first and last are trivial, while the second one can be satisfied by +assigning :e:`mallory` to :e:`P`. All equations are solved, +hence unification succeeds. + +See also the `Wikipedia page on Unification `_. + +Since the first part of the query is succesful the rest of +the query is run: the value of :e:`P` is printed as well as +the :e:`"is 23 years old"` string. + +.. note:: :e:`=` is a regular predicate + + The query :e:`age P 23` can be also written as follows: + + .. code:: elpi + + A = 23, age P A, Msg = "is 23 years old", coq.say P Msg + + +Let's try a query harder to solve! + +|*) + +Elpi Query lp:{{ + + age P 20, coq.say P "is 20 years old" + +}}. + +(*| + +This time the unification problem for the first rule +in the program is: + +.. code:: elpi + + age P 20 = age mallory 23 + +that is simplified to: + +.. code:: elpi + + age = age + P = mallory + 20 = 23 + +The second equation can be solved by assigning :e:`mallory` to :e:`P`, +but the third one has no solution, so unification fails. + +------------ +Backtracking +------------ + +When failure occurs all assignements are undone (i.e. :e:`P` is unset again) +and the next rule in the program is tried. This operation is called +*backtracking*. + +The unification problem for the next rule is: + +.. code:: elpi + + age P 20 = age bob 23 + +This one also fails. The unification problem for the last rule is: + +.. code:: elpi + + age P 20 = age alice 20 + +This one works, and the assigment :e:`P = alice` is kept as the result +of the first part of the query. Then :e:`P` is printed and the program +ends. + +An even harder query is the following one where we ask for two distinct +individuals to have the same age. + +|*) + +Elpi Query lp:{{ + + age P A, age Q A, not(P = Q), + coq.say P "and" Q "are" A "years old" + +}}. + +(*| + +This example shows that backtracking is global. The first solution for +:e:`age P A` and :e:`age Q A` picks :e:`P` and :e:`Q` to +be the same individual :e:`mallory`, +but then :e:`not(P = Q)` fails and forces the last choice that was made to be +reconsidered, so :e:`Q` becomes :e:`bob`. + +Look at the output of the following code to better understand +how backtracking works. + +|*) + +Elpi Query lp:{{ + + age P A, coq.say "I picked P =" P, + age Q A, coq.say "I picked Q =" Q, + not(P = Q), + coq.say "the last choice worked!", + coq.say P "and" Q "are" A "years old" + +}}. + +(*| + +.. note:: :e:`not` is a black hole + + The :e:`not(P)` predicate tries to solve the query :e:`P`: it fails if + :e:`P` succeeds, and succeeds if :e:`P` fails. In any case no trace is left + of the computation for :e:`P`. E.g. :e:`not(X = 1, 2 < 1)` suceeds, but + the assignment for :e:`X` is undone. See also the section + about the `foundations`_ of λProlog. + +--------------------------- +Facts and conditional rules +--------------------------- + +The rules we have seen so far are *facts*: they always hold. +In general rules can only be applied if some *condition* holds. Conditions are +also called premises, we may use the two terms interchangeably. + +Here we add to our program a rule that defines what :e:`older P Q` means +in terms of the :e:`age` of :e:`P` and :e:`Q`. + +.. note:: :e:`:-` separates the *head* of a rule from the *premises* + +|*) + +Elpi Accumulate lp:{{ + + pred older o:person, o:person. + older P Q :- age P N, age Q M, N > M. + +}}. + +(*| + +The rule reads: :e:`P` is older than :e:`Q` if +:e:`N` is the age of :e:`P` +*and* :e:`M` is the age of :e:`Q` +*and* :e:`N` is greater than :e:`M`. + +Let's run a query using older: + +|*) + +Elpi Query lp:{{ + + older bob X, + coq.say "bob is older than" X + +}}. + +(*| + +The query :e:`older bob X` is unified with the head of +the program rule :e:`older P Q` +assigning :e:`P = bob` and :e:`X = Q`. Then three new queries are run: + +.. code:: elpi + + age bob N + age Q M + N > M + +The former assigns :e:`N = 23`, the second one first +sets :e:`Q = mallory` and :e:`M = 23`. This makes the last +query to fail, since :e:`23 > 23` is false. Hence the +second query is run again and again until :e:`Q` is +set to :e:`alice` and :e:`M` to :e:`20`. + +Variables in the query are said to be existentially +quantified because Elpi will try to find one +possible value for them. + +Conversely, the variables used in rules are +universally quantified in the front of the rule. +This means that the same program rule can be used +multiple times, and each time the variables are fresh. + +In the following example the variable :e:`P` in :e:`older P Q :- ...` +once takes :e:`bob` and another time takes :e:`mallory`. + +|*) + +Elpi Query lp:{{ + + older bob X, older mallory X, + coq.say "both bob and mallory are older than" X + +}}. + +(*| + +================== +Terms with binders +================== + +So far the syntax of terms is based on constants +(eg :e:`age` or :e:`mallory`) and variables (eg :e:`X`). + +λProlog adds another term constructor: +λ-abstraction (written :e:`x\ ...`). + +.. note:: the variable name before the ``\`` can be a capital + + Given that it is explicitly bound Elpi needs not to guess if it is a global + symbol or a rule variable (that required the convention of using capitals for + variables in the first place). + +------------- +λ-abstraction +------------- + +Functions built using λ-abstraction can be applied +to arguments and honor the usual β-reduction rule +(the argument is substituted for the bound variable). + +In the following example :e:`F 23` reads, once +the β-reduction is performed, :e:`age alice 23`. + +|*) + +Elpi Query lp:{{ + + F = (x\ age alice x), + coq.say "F =" F, + coq.say "F 20 =" (F 20), + coq.say "F 23 =" (F 23) + +}}. + +(*| + +Let's now write the "hello world" of λProlog: an +interpreter and type checker for the simply +typed λ-calculus. We call this program `stlc`. + +We start by declaring that :e:`term` is a type and +that :e:`app` and :e:`fun` are constructors of that type. + +|*) + +Elpi Program stlc lp:{{ + + kind term type. + + type app term -> term -> term. + type fun (term -> term) -> term. + +}}. + +(*| + +The constructor :e:`app` takes two terms +while :e:`fun` only one (of functional type). + +Note that + +* there is no constructor for variables, we will + use the notion of bound variable of λProlog in order + to represent variables +* :e:`fun` takes a function as subterm, i.e. something + we can build using the λ-abstraction :e:`x\ ...` + +As a consequence, the identity function λx.x is written like this: + +.. code:: elpi + + fun (x\ x) + +while the first projection λx.λy.x is written: + +.. code:: elpi + + fun (x\ fun (y\ x)) + +Another consequence of this approach is that there is no +such thing as a free variable in our representation of the λ-calculus. +Variables are only available under the λ-abstraction of the +programming language, that gives them a well defined scope and +substitution operation (β-reduction). + +This approach is called `HOAS `_. + +We can now implement weak head reduction, that is we stop reducing +when the term is a :e:`fun` or a global constant (potentially applied). +If the term is :e:`app (fun F) A` then we compute the reduct :e:`F A`. +Note that :e:`F` is a λProlog function, so passing an argument to it +implements the substitution of the actual argument for the bound variable. + +We first give a type and a mode for our predicate :e:`whd`. It reads +"whd takes a term in input and gives a term in output". We will +explain what input means precisely later, for now just think about it +as a comment. + +|*) + +Elpi Accumulate lp:{{ + + pred whd i:term, o:term. + + % when the head "Hd" of an "app" (lication) is a + % "fun" we substitute and continue + whd (app Hd Arg) Reduct :- whd Hd (fun F), !, + whd (F Arg) Reduct. + + % otherwise a term X is already in normal form. + whd X Reduct :- Reduct = X. + +}}. + +(*| + +Recall that, due to backtracking, all rules are potentially used. +Here whenever the first premise of the first rule succeeds +we want the second rule to be skipped, since we found a redex. + +The premises of a rule are run in order and the :e:`!` operator discards all +other rules following the current one. Said otherwise it commits to +the currently chosen rule for the current query (but leaves +all rules available for subsequent queries, they are not erased from the +program). So, as soon as :e:`whd Hd (fun F)` succeeds we discard the second +rule. + +|*) + +Elpi Query lp:{{ + + I = (fun x\x), + whd I T, coq.say "λx.x ~>" T, + whd (app I I) T1, coq.say "(λx.x) (λx.x) ~>" T1 + +}}. + +(*| + +Another little test using global constants: + +|*) +Elpi Accumulate lp:{{ + + type foo, bar term. + +}}. + +Elpi Query lp:{{ + + Fst = fun (x\ fun y\ x), + T = app (app Fst foo) bar, + whd T T1, coq.say "(Fst foo bar) ~>" T1, + S = app foo bar, + whd S S1, coq.say "(foo bar) ~>" S1 + +}}. + +(*| + +A last test with a lambda term that has no weak head normal form: + +|*) + +Elpi Bound Steps 1000. (* Let's be cautious *) +Fail Elpi Query lp:{{ + + Delta = fun (x\ app x x), + Omega = app Delta Delta, + whd Omega Hummm, coq.say "not going to happen" + +}}. (* .fails *) +Elpi Bound Steps 0. + +(*| + +----------------------- +:e:`pi x\ ` and :e:`=>` +----------------------- + +We have seen how to implement subtitution using the binders of λProlog. +More often than not we need to move under binders rather than remove them by +substituting some term in place of the bound variable. + +In order to move under a binder and inspect the body of a function λProlog +provides the :e:`pi` quantifier and the :e:`=>` connective. + +A good showcase for these features is to implement a type checker +for the simply typed lambda calculus. +See also `the Wikipedia page on the simply typed lambda calculus `_. + +We start by defining the data type of simple types. +We then declare a new predicate :e:`of` (for "type of") and finally +we provide two rules, one for each term constructor. + +|*) + +Elpi Accumulate lp:{{ + + kind ty type. % the data type of types + type arr ty -> ty -> ty. % our type constructor + + pred of i:term, o:ty. % the type checking algorithm + + % for the app node we ensure the head is a function from + % A to B, and that the argument is of type A + of (app Hd Arg) B :- + of Hd (arr A B), of Arg A. + + % for lambda, instead of using a context (a list) of bound + % variables we use pi and => , explained below + of (fun F) (arr A B) :- + pi x\ of x A => of (F x) B. + +}}. + +(*| + +The :e:`pi name\ code` syntax is reserved, as well as +:e:`rule => code`. + +Operationally :e:`pi x\ code` introduces a fresh +constant :e:`c` for :e:`x` and then runs :e:`code`. +Operationally :e:`rule => code` adds :e:`rule` to +the program and runs :e:`code`. Such extra rule is +said to be hypothetical. +Both the constant for :e:`x` and :e:`rule` are +removed once :e:`code` terminates. + +.. important:: hypothetical rules are added at the *top* of the program + + Hypothetical rules hence take precedence over static rules, since + they are tried first. + +Note that in this last example the hypothetical rule is going to be +:e:`of c A` for a fixed :e:`A` and a fresh constant :e:`c`. +The variable :e:`A` is fixed but not assigned yet, meaning +that :e:`c` has a type, and only one, but we may not know it yet. + + +Now let's assign a type to λx.λy.x: + +|*) + +Elpi Query lp:{{ + +of (fun (x\ fun y\ x)) Ty, coq.say "The type of λx.λy.x is:" Ty + +}}. + +(*| + +Let's run this example step by step: + +The rule for :e:`fun` is used: + +* :e:`arrow A1 B1` is assigned to :e:`Ty` by unification +* the :e:`pi x\ ` quantifier creates a fresh constant :e:`c1` to play + the role of :e:`x` +* the :e:`=>` connective adds the rule :e:`of c1 A1` the program +* the new query :e:`of (fun y\ c1) B1` is run. + +Again, the rule for :e:`fun` is used (since its variables are +universally quantified, we use :e:`A2`, :e:`B2`... this time): + +* :e:`arrow A2 B2` is assigned to :e:`B1` by unification +* the :e:`pi x\ ` quantifier creates a fresh constant :e:`c2` to play + the role of :e:`x` +* the :e:`=>` connective adds the rule :e:`of c2 A2` the program +* the new query :e:`of c1 B2` is run. + +The (hypotetical) rule :e:`of c1 A1` is used: + +* unification assigns :e:`A1` to :e:`B2` + +The value of :e:`Ty` is hence :e:`arr A1 (arr A2 A1)`, a good type +for λx.λy.x (the first argument and the output have the same type :e:`A1`). + +What about the term λx.(x x) ? + +|*) + +Elpi Query lp:{{ + + Delta = fun (x\ app x x), + (of Delta Ty ; coq.say "Error:" Delta "has no type") + +}}. + +(*| + +The :e:`;` infix operator stands for disjunction. Since we see the message +:e:`of` failed: the term :e:`fun (x\ app x x)` is not well typed. + +First, the rule for elpi:`fun` is selected: + +* :e:`arrow A1 B1` is assigned to :e:`Ty` by unification +* the :e:`pi x\ ` quantifier creates a fresh constant :e:`c1` to play the + role of :e:`x` +* the :e:`=>` connective adds the rule :e:`of c1 A1` the program +* the new query :e:`of (app c1 c1) B1` is run. + +Then it's the turn of typing the application: + +* the query :e:`of c1 (arr A2 B2)` assignes to :e:`A1` the + value :e:`arr A2 B2`. This means that the + hypothetical rule is now :e:`of c1 (arr A2 B2)`. +* the query :e:`of c1 A2` fails because the unification + + .. code:: elpi + + of c1 A2 = of c1 (arr A2 B2) + + has no solution, in particular the sub problem :e:`A2 = (arr A2 B2)` + fails the so called occur check. + + +.. _foundations: + +=================== +Logical foundations +=================== + +This section tries to link, informally, λProlog with logic, assuming the reader +has some familiarity with first order intuitionistic logic and proof theory. +The reader which is not familiar with that can probably skip this section, +although section `functional-style`_ contains some explanations about +the scope of variables which are based on the logical foundations of +the language. + +The semantics of a λProlog program is given by interpreting +it in terms of logical formulas and proof search in intuitionistic logic. + +A rule + +.. code:: elpi + + p A B :- q A C, r C B. + +has to be understood as a formula + +.. math:: + + ∀A~B~C, (\mathrm{q}~A~C ∧ \mathrm{r}~C~B) → \mathrm{p}~A~B + +A query is a goal that is proved by backchaining +rules. For example :e:`p 3 X` +is solved by unifying it with the conclusion of +the formula above (that sets :e:`A` to :e:`3`) and +generating two new goals, :e:`q 3 C` and +:e:`r C B`. Note that :e:`C` is an argument to both +:e:`q` and :e:`r` and acts as a link: if solving :e:`q` +fixes :e:`C` then the query for :e:`r` sees that. +Similarly for :e:`B`, that is identified with :e:`X`, +and is hence a link from the solution of :e:`r` to +the solution of :e:`p`. + +A rule like: + +.. code:: elpi + + of (fun F) (arr A B) :- + pi x\ of x A => of (F x) B. + +reads, as a logical formula: + +.. math:: + + ∀F~A~B, (∀x, \mathrm{of}~x~A → \mathrm{of}~(F~x)~B) → \mathrm{of}~(\mathrm{fun}~F)~(\mathrm{arr}~A~B) + +where :math:`F` stands for a function. +Alternatively, using the inference rule notation typically used for +type systems: + +.. math:: + + \frac{\Gamma, \mathrm{of}~x~A \vdash \mathrm{of}~(F~x)~B \quad x~\mathrm{fresh}}{\Gamma \vdash \mathrm{of}~(\mathrm{fun}~F)~(\mathrm{arr}~A~B)} + +Hence, :e:`x` and :e:`of x A` are available only +temporarily to prove :e:`of (F x) B` and this is +also why :e:`A` cannot change during this sub proof (:e:`A` is +quantified once and forall outside). + +Each program execution is a proof (tree) of the query +and is made of the program rules seen as proof rules or axioms. + +As we hinted before negation is a black hole, indeed the usual definition of +:math:`\neg A` as :math:`A \to \bot` is the one of a function with no output +(see also the `the Wikipedia page on the Curry-Howard correspondence `_). + +===================== +Modes and constraints +===================== + +Elpi extends λProlog with *syntactic constraints* +and rules to manipulate the store of constraints. + +Syntactic constraints are goals suspended on +a variable which are resumed as soon as that variable +gets instantiated. While suspended they are kept in a store +which can be manipulated by dedicated rules. + +A companion facility is the declaration of *modes*. +The argument of a predicate can be marked as input +to avoid instantiating the goal when it is unified +with the head of a rule (an input argument +is matched, rather than unified). + +A simple example: Peano's addition: + +|*) + +Elpi Program peano lp:{{ + +kind nat type. +type z nat. +type s nat -> nat. + +pred add o:nat, o:nat, o:nat. + +add (s X) Y (s Z) :- add X Y Z. +add z X X. + +}}. + +Elpi Query lp:{{ + + add (s (s z)) (s z) R, coq.say "2 + 1 =" R + +}}. + +(*| + +Unfortunately the relation does not work well +when the first argument is a variable. Depending on the +order of the rules for :e:`add` Elpi can either diverge or pick +:e:`z` as a value for :e:`X` (that may not be what one wants) + +|*) + +Elpi Bound Steps 100. +Fail Elpi Query lp:{{ add X (s z) Y }}. (* .fails *) +Elpi Bound Steps 0. + +(*| + +Indeed the first rule for add can be applied forever. +If one exchanges the two rules in the program, then Elpi +terminates picking :e:`z` for :e:`X`. + +We can use the mode directive in order to +*match* arguments marked as :e:`i:` against the patterns +in the head of rules, rather than unifying them. + +|*) + +Elpi Program peano2 lp:{{ + +kind nat type. +type z nat. +type s nat -> nat. + +pred sum i:nat, i:nat, o:nat. + +sum (s X) Y (s Z) :- sum X Y Z. +sum z X X. +sum _ _ _ :- + coq.error "nothing matched but for this catch all clause!". + +}}. + +Fail Elpi Query lp:{{ sum X (s z) Y }}. (* .fails *) + +(*| + +The query fails because no rule first argument matches :e:`X`. + +Instead of failing we can suspend goals and turn them into +syntactic constraints + +|*) + +Elpi Program peano3 lp:{{ + +kind nat type. +type z nat. +type s nat -> nat. + +pred sum i:nat, i:nat, o:nat. + +sum (s X) Y (s Z) :- sum X Y Z. +sum z X X. +sum X Y Z :- + % the head of the rule always unifies with the query, so + % we double check X is a variable (we could also be + % here because the other rules failed) + var X, + % then we declare the constraint and schedule its resumption + % on the assignment of X + declare_constraint (sum X Y Z) [X]. + +}}. + +Elpi Query lp:{{ sum X (s z) Z }}. + +(*| + +Syntactic constraints are resumed when the variable +they are suspended on is assigned: + +|*) + +Elpi Query lp:{{ + + sum X (s z) Z, X = z, + coq.say "The result is:" Z + +}}. + +(*| + +Here a couple more examples. Keep in mind that: + +* resumption can cause failure +* recall that :e:`;` stands for disjunction + +|*) + +Fail Elpi Query lp:{{ sum X (s z) (s (s z)), X = z }}. (* .fails *) +Elpi Query lp:{{ sum X (s z) (s (s z)), (X = z ; X = s z) }}. + +(*| + +In this example the computation suspends, then makes progess, +then suspends again... + +|*) + +Elpi Query lp:{{ + + sum X (s z) Y, + print_constraints, coq.say "Currently Y =" Y, + X = s Z, + print_constraints, coq.say "Currently Y =" Y, + Z = z, + coq.say "Finally Y =" Y + +}}. + +(*| + +Sometimes the set of syntactic constraints becomes unsatisfiable +and we would like to be able to fail early. + +|*) + +Elpi Accumulate lp:{{ + +pred even i:nat. +pred odd i:nat. + +even z. +even (s X) :- odd X. +odd (s X) :- even X. + +odd X :- var X, declare_constraint (odd X) [X]. +even X :- var X, declare_constraint (even X) [X]. + +}}. + +Elpi Query lp:{{ even (s X), odd (s X) }}. (* hum, not nice *) + +(*| + +------------------------- +Constraint Handling Rules +------------------------- + +A constraint (handling) rule can see the store of syntactic constraints +as a whole, remove constraints and/or create new goals: + +|*) + +Elpi Accumulate lp:{{ + +constraint even odd { + % if two distinct, conflicting, constraints about the same X + % are part of the constraint store + rule (even X) (odd X) <=> + % generate the following goal + (coq.say X "can't be even and odd at the same time", fail). +} + +}}. + +Fail Elpi Query lp:{{ even (s X), odd (s X) }}. (* .fails *) + +(*| + +.. note:: :e:`fail` is a predicate with no solution + +See also the Wikipedia page on `Constraint Handling Rules `_ +for an introduction to the sub language to manipulate constraints. + +.. _functional-style: + +================ +Functional style +================ + +Elpi is a relational language, not a functional one. Still some features +typical of functional programming are available, with some caveats. + +------------------------------- +Spilling (relation composition) +------------------------------- + +Chaining "relations" can be painful, especially when +they look like functions. Here we use :stdlib:`std.append` +and :stdlib:`std.rev` to build a palindrome: + +|*) + +Elpi Program function lp:{{ + +pred make-palindrome i:list A, o:list A. + +make-palindrome L Result :- + std.rev L TMP, + std.append L TMP Result. + +}}. + +Elpi Query lp:{{ + + make-palindrome [1,2,3] A + +}}. + +(*| + +.. note:: variables (capital letters) can be used in + types in order to describe ML-like polymorphism. + +.. note:: :e:`list A` is a built-in data type + + The empty list is written :e:`[]`, while the cons constructor + is written :e:`[Hd | Tail]`. Iterated cons can be written + :e:`[ E1, E2 | Tail ]` and :e:`| Tail` can be omitted if the list + is nil terminated. + +The :e:`make-palindrome` predicate has to use a temporary variable +just to pass the output of a function as the input to another function. + +Spilling is a syntactic elaboration which does that for you. +Expressions between `{` and `}` are +said to be spilled out and placed just before the predicate +that contains them. + +*) + +Elpi Accumulate lp:{{ + +pred make-palindrome2 i:list A, o:list A. + +make-palindrome2 L Result :- + std.append L {std.rev L} Result. + +}}. + +Elpi Query lp:{{ + + make-palindrome2 [1,2,3] A + +}}. + +(*| + +The two versions of :e:`make-palindrome` are equivalent. +Actually the latter is elaborated into the former. + +---------------------- +APIs for built-in data +---------------------- + +Functions about built-in data types are available via the +:stdlib:`calc` predicate or its infix version :e:`is`. Example: + +|*) + +Elpi Query lp:{{ + + calc ( "result " ^ "=" ) X, + Y is 3 + 2, + coq.say X Y + +}}. + +(*| + +The :stdlib:`calc` predicate works nicely with spilling: + +|*) + +Elpi Query lp:{{ coq.say "result =" {calc (2 + 3)} }}. + +(*| + +----------------------- +Allocation of variables +----------------------- + +The language let's one use λ-abstraction also to write anonymous rules +but one has to be wary of where variables are bound (allocated really). + +In our example we use the higher order predicate :stdlib:`std.map`: + +.. code:: elpi + + pred std.map i:list A, i:(A -> B -> prop), o:list B. + +.. note:: :e:`prop` is the type of predicates + + The actual type of the :e:`std.map` symbol is: + + .. code:: elpi + + type std.map list A -> (A -> B -> prop) -> list B -> prop. + + The :e:`pred` directive complements a type declaration for predicates + (the trailing :e:`-> prop` is implicit) with a mode declaration for + each argument. + +The type of the second argument of :e:`std.map` +is the one of a predicate relating :e:`A` with :e:`B`. + +Let's try to call :e:`std.map` passing an anonymous rule (as we +would do in a functional language by passing an anonymous function): + +|*) + +Elpi Accumulate lp:{{ + +pred bad i:list int, o:list int. + +bad L Result :- + std.map L (x\ r\ TMP is x + 1, r = TMP) Result. + +pred good i:list int, o:list int. +good L Result :- + std.map L good.aux Result. +good.aux X R :- TMP is X + 1, R = TMP. + +pred good2 i:list int, o:list int. +good2 L Result :- + std.map L (x\ r\ sigma TMP\ TMP is x + 1, r = TMP) Result. + +}}. + +Elpi Query lp:{{ + + not(bad [1,2,3] R1), + good [1,2,3] R2, + good2 [1,2,3] R3 + +}}. + +(*| + +The problem with :e:`bad` is that :e:`TMP` is fresh each time the rule +is used, but not every time the anonymous rule passed to :stdlib:`map` +is used. Technically :e:`TMP` is quantified (allocated) where :e:`L` +and :e:`Result` are. + +There are two ways to quantify :e:`TMP` correctly, that is inside the +anonymous predicate. One is to actually name the predicate. Another one is +to use the :e:`sigma x\ ` quantifier to allocate :e:`TMP` at every call. +We recommend to name the auxiliary predicate. + +.. tip:: predicates whose name ends in `.aux` don't trigger a missing type + declaration warning + +One last way to skin the cat is to use :e:`=>` as follows. It gives us +the occasion to clarify further the scope of variables. + +|*) + +Elpi Accumulate lp:{{ + +pred good3 i:list int, o:list int. +good3 L Result :- + pi aux\ + (pi TMP X R\ aux X R :- TMP is X + 1, R = TMP) => + std.map L aux Result. + +}}. + +Elpi Query lp:{{ + + good3 [1,2,3] R + +}}. + +(*| + +In this case the auxiliary predicate :e:`aux` +is only visible inside :e:`good3`. +What is interesting to remark is that the quantifications are explicit +in the hypothetical rule, and they indicate clearly that each and every +time :e:`aux` is used :e:`TMP`, :e:`X` and :e:`R` are fresh. + +The :e:`pi x\ ` quantifier is dual to :e:`sigma x\ `: since here it +occurs negatively it has the same meaning. That is, the hypothetical rule +could be written :e:`pi X R\ aux X R :- sigma TMP\ TMP is X + 1, R = TMP`. + +.. tip:: :e:`pi x\ ` and :e:`sigma x\ ` can quantify on a bunch of variables + at once + + That is, :e:`pi x y\ ...` is equivalent to :e:`pi x\ pi y\ ...` and + :e:`sigma x y\ ...` is equivalent to :e:`sigma x\ sigma y\ ...`. + +.. tip:: :e:`=>` can load more than one clause at once + + It is sufficient to put a list on the left hand side, eg :e:`[ rule1, rule2 ] => code`. + Moreover one can synthesize a rule before loading it, eg: + + .. code:: elpi + + Rules = [ one-more-rule | ExtraRules ], Rules => code + +The last remark worth making is that bound variables are intimately related +to universal quantification, while unification variables are related to +existential quantification. It goes without saying that the following +two formulas are not equivalent and while the former is trivial the latter +is in general false: + +.. math:: + + ∀x, ∃Y, Y = x\\ + ∃Y, ∀x, Y = x + +Let's run these two corresponding queries: + +|*) + +Elpi Query lp:{{ pi x\ sigma Y\ Y = x, coq.say "Y =" Y }}. +Fail Elpi Query lp:{{ sigma Y\ pi x\ Y = x, coq.say "Y =" Y }}. (* .fails *) + +(*| + +Another way to put it: :e:`x` is in the scope of :e:`Y` only in the first +formula since it is quantified before it. Hence :e:`x` can be assigned to +:e:`Y` in that case, but not in the second query, where it is quantified +after. + +More in general, λProlog tracks the bound variables that are in scope of each +unification variable. There are only two ways to put a bound variable +in the scope: + +* quantify the unification variable under the bound one (first formula) +* pass the bound variable to the unification variable explicitly: in this + case the unification variable needs to have a functional type. + Indeed :math:`∃Y, ∀x, (Y x) = x` has a solution: :e:`Y` can be + the identity function. + + .. coq:: + + Elpi Query lp:{{ sigma Y\ pi x\ Y x = x, coq.say "Y =" Y }}. + +If we look again at the rule for type checking +λ-abstraction: + +.. code:: elpi + + of (fun F) (arr A B) :- + pi x\ of x A => of (F x) B. + +we can see that the only unification variable that sees the fresh +`x` is :e:`F`, because we pass :e:`x` to :e:`F` explicitly +(recall all unification variables such as :e:`F`, :e:`A`, :e:`B` are +quantified upfront, before the :e:`pi x\ `). +Indeed when we write: + +.. math:: + + \frac{\Gamma, x : A \vdash f : B}{\Gamma \vdash λx.f : A → B} + +on paper, the variable denoted by :e:`x` being bound there can only occur in +:math:`f`, not in :math:`\Gamma` or :math:`B` for example (although a +*different* variable could be named the same, hence the usual freshness side +conditions which are not really necessary using HOAS). + +Remark that in the premise the variable :math:`x` is still bound, this time +not by a λ-abstraction but by the context :math:`\Gamma, x : A`. +In λProlog the context is the set of hypothetical rules and :e:`pi\ ` +-quantified variables and is implicitly handled by the runtime of the +programming language. + +A slogan to keep in mind is that: + +.. important:: There is no such thing as a free variable! + +Indeed the variable bound by the λ-abstraction (of our data) is +replaced by a fresh variable bound by the context (of our program). This is +called binder mobility. See also the paper +`Mechanized metatheory revisited `_ by +Dale Miller which is an excellent +introduction to these concepts. + +========= +Debugging +========= + +The most sophisticated debugging feature can be used via +the Visual Sudio Code extension ``gares.elpi-lang`` and its +``Elpi Tracer`` tab. + +--------------- +Trace browser +--------------- + +In order to generate a trace one needs to execute the +``Elpi Trace Browser.`` command and then run any Elpi code. + +|*) + +(* Elpi Trace Browser. *) + +Elpi Query stlc lp:{{ % We run the query in the stlc program + + of (fun (x\ fun y\ x)) Ty, coq.say Ty + +}}. + +(*| + +The trace file is generated in ``/tmp/traced.tmp.json``. +If it does not load automatically one can do it manually by clicking on +the load icon, in the upper right corner of the Elpi Tracer panel. + +.. note:: partial display of goals + + At the time of writing one may need to disable syntax highlighting in + the extension settings in order to get a correct display. + +The trace browser displays, on the left column, a list of cards corresponding +to a step perfoemd by the interpreter. The right side of the +panel gives more details about the selected step. In the image below one +can see the goal, the rule being applied, the assignments performed by the +unification of the rule's head with the goal, the subgoals generated. + +.. image:: tracer.png + :width: 800 + +One can also look at the trace in text format (if VSCode is not an option, +for example). + +|*) +Elpi Trace. + +Elpi Query stlc lp:{{ % We run the query in the stlc program + + of (fun (x\ fun y\ x)) Ty, coq.say Ty + +}}. + +Fail Elpi Query stlc lp:{{ + + of (fun (x\ app x x)) Ty, coq.say Ty + +}}. (* .fails *) + +(*| + +The trace can be limited to a range of steps. Look at the +numbers ``run HERE {{{``. + +|*) + +Elpi Trace 6 8. +Elpi Query stlc lp:{{ + + of (fun (x\ fun y\ x)) Ty, coq.say Ty + +}}. + +(*| + +The trace can be limited to a (list of) predicates as follows: + +|*) + +Elpi Trace "of". +Elpi Query stlc lp:{{ + + of (fun (x\ fun y\ x)) Ty, coq.say Ty + +}}. + +(*| + +One can combine the range of steps with the predicate: + +|*) + +Elpi Trace 6 8 "of". +Elpi Query stlc lp:{{ + + of (fun (x\ fun y\ x)) Ty, coq.say Ty + +}}. + +(*| + +To switch traces off: + +|*) + +Elpi Trace Off. + +(*| + +--------------- +Good old print +--------------- + +A common λProlog idiom is to have a debug rule +lying around. The :e:`:if` attribute can be used to +make the rule conditionally interpreted (only if the +given debug variable is set). + +|*) + +Elpi Debug "DEBUG_MYPRED". +Elpi Program debug lp:{{ + + pred mypred i:int. + + :if "DEBUG_MYPRED" + mypred X :- + coq.say "calling mypred on " X, fail. + + mypred 0 :- coq.say "ok". + mypred M :- N is M - 1, mypred N. + +}}. +Elpi Query lp:{{ mypred 3 }}. + +(*| + +------------------------ +Printing entire programs +------------------------ + +Given that programs are not written in a single place, but rather obtained by +accumulating code, Elpi is able to print a (full) program to an html file +as follows. The obtained file provides a facility to filter rules by their +predicate. + +|*) + +Elpi Print stlc. + +(*| + +Look at the `generated page `_ +and type :e:`of` in the filter. + +Finally, one can bound the number of backchaining steps +performed by the interpreter: + +|*) + +Elpi Query lp:{{ 0 = 0, 1 = 1 }}. +Elpi Bound Steps 1. +Fail Elpi Query lp:{{ 0 = 0, 1 = 1 }}. (* .fails *) (* it needs 2 steps! *) +Elpi Bound Steps 0. (* Go back to no bound *) + +(*| + +--------------- +Common pitfalls +--------------- + +Well, no programming language is perfect. + +++++++++++++++++++++++++++++++++ +Precedence of :e:`,` and :e:`=>` +++++++++++++++++++++++++++++++++ + + +The precedence of :e:`,` and :e:`=>` can be surprising + +|*) + +Fail Elpi Query stlc lp:{{ + + pi x\ + of x A => of x B, of x C + +}}. (* .fails *) + +Elpi Query stlc lp:{{ + + pi x\ + of x A => (of x B, of x C) % both goals see of x A + +}}. + +(*| + +++++++++++++ +Backtracking +++++++++++++ + + +Backtracking can lead to weird execution traces. The :stdlib:`std.do!` predicate +should be used to write non-backtracking code. + +.. code:: elpi + + pred not-a-backtracking-one. + not-a-backtracking-one :- condition, !, std.do! [ + step, + (generate, test), + step, + ]. + +In the example above once :e:`condition` holds we start a sequence of +steps which we will not reconsider. Locally, backtracking is still +available, e.g. between :e:`generate` and :e:`test`. +See also the :stdlib:`std.spy-do!` predicate which prints each and every step, +and the :stdlib:`std.spy` one which can be used to spy on a single one. + ++++++++++++++++++++++++++++++++++++++++++++++++ +Unification variables v.s. Imperative variables ++++++++++++++++++++++++++++++++++++++++++++++++ + +Unification variables sit in between variables in imperative programming and +functional programming. In imperative programming a variable can hold a value, +and that value can change over time via assignment. In functional languages +variables always hold a value, and that value never changes. In logic programming +a unification variable can either be unset (no value) or set to a value that +never changes. Backtracking goes back in time, it is not visible to the program. + +As a result of this, code like + +.. code:: elpi + + pred bad-example. + bad-example :- X is 1 + 2, X is 4 + 5. + +fails, because :e:`X` cannot be at the same time 3 and 9. Initially +:e:`X` is unset, then it is set to 3, and finally the programmer is +asserting that 3 (the value hold by :e:`X`) is equal to 9. +The second call to :e:`is` does not change the value carried by :e:`X`! + +Unification, and hence the :e:`=` pradicate, plays two roles. +When :e:`X` is unset, :e:`X = v` sets the variable. +When :e:`X` is set to :e:`u`, :e:`X = v` checks if the value +of :e:`X` is equal to :e:`u`: it is equivalent to :e:`u = v`. + +=============== +Further reading +=============== + +The `λProlog website `_ +contains useful links to λProlog related material. + +Papers and other documentation about Elpi can be found at +the `Elpi home on github `_. + +Three more tutorials specific to Elpi as an extension language for Coq +can be found in the `examples folder `_. +You can continue by reading the one about the +`HOAS for Coq terms `_. + +|*) + + diff --git a/tests/vernacular1.t/run.t b/tests/vernacular1.t/run.t new file mode 100644 index 000000000..fd12166b6 --- /dev/null +++ b/tests/vernacular1.t/run.t @@ -0,0 +1,39 @@ + $ . ../setup-project.sh + $ dune build test.vo + test2 + test1 + str hello + test1 + too many arguments + test1 + str hello my + str Dear + test1 + too many arguments + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 49, column 5, character 1005:), + attribute elpi.phase (leaf-str interp), attribute foo (leaf-str bar)] + [get-option foo bar] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 53, column 0, character 1039:), + attribute elpi.phase (leaf-str interp), attribute foo (leaf-str bar), + attribute poly (leaf-str )] + [get-option foo bar, get-option poly tt] + [attribute elpi.test (leaf-str yes), + attribute elpi.str (leaf-str some-string), + attribute elpi.loc + (leaf-loc File "./test.v", line 54, column 0, character 1067:), + attribute elpi.phase (leaf-str interp), attribute foo (leaf-str bar), + attribute poly (leaf-str ), + attribute suppa (node [attribute duppa (leaf-str )])] + [get-option foo bar, get-option poly tt] + Query assignments: + X = 3 + app [global (const «Nat.mul»), X0, X1] type + File "./test.v", line 48, characters 2-11: + Warning: This command does not support this attribute: foo. + [unsupported-attributes,parsing,default] diff --git a/tests/test_vernacular1.v b/tests/vernacular1.t/test.v similarity index 77% rename from tests/test_vernacular1.v rename to tests/vernacular1.t/test.v index 1a173667d..667a32bda 100644 --- a/tests/test_vernacular1.v +++ b/tests/vernacular1.t/test.v @@ -34,9 +34,10 @@ Elpi Command test.att. Elpi Accumulate lp:{{ main _ :- - attributes A, - coq.say A, - A = [attribute "elpi.loc" _, attribute "elpi.phase" _, attribute "foo" (leaf-str "bar")| _], + attributes X, + coq.say X, + std.filter X (x\sigma s\ x = attribute s _, (not(rex.match "^elpi\\." s))) A, + A = [attribute "foo" (leaf-str "bar")| _], coq.parse-attributes A [att "foo" string, att "poly" bool, att-ignore-unknown] CL, @@ -55,8 +56,10 @@ Elpi Export test.att. Elpi Command test.axx. Elpi Accumulate lp:{{ main _ :- - attributes A, coq.parse-attributes A [att "foo" attmap] CL, - CL = [get-option "elpi.loc" _, get-option "elpi.phase" _, get-option "foo" [get-option "A" "3", get-option "b_2" "yes"]]. + attributes X, + std.filter X (x\sigma s\ x = attribute s _, (not(rex.match "^elpi\\." s))) A, + coq.parse-attributes A [att "foo" attmap] CL, + CL = [get-option "foo" [get-option "A" "3", get-option "b_2" "yes"]]. }}. Elpi Typecheck. Elpi Export test.axx. @@ -82,7 +85,8 @@ Elpi Accumulate lp:{{ att "foo.x" string, att "foo.y" bool, ] CL, - CL = [get-option "elpi.loc" _, get-option "elpi.phase" _, + CL = [get-option "elpi.test" _, get-option "elpi.str" _, + get-option "elpi.loc" _, get-option "elpi.phase" _, get-option "only" [get-option "foo" tt], get-option "foo.x" "a", get-option "foo.y" ff]. diff --git a/tests/vernacular2.t/run.t b/tests/vernacular2.t/run.t new file mode 100644 index 000000000..c1d7916ca --- /dev/null +++ b/tests/vernacular2.t/run.t @@ -0,0 +1,10 @@ + $ . ../setup-project.sh + $ dune build test.vo + Warning: in file test.v, library test_vernacular1 is required + from root elpi and has not been found in the loadpath! + [module-not-found,filesystem,default] + File "./test.v", line 1, characters 0-47: + Error: Cannot find a physical path bound to logical path + test_vernacular1 with prefix elpi. + + [1] diff --git a/tests/test_vernacular2.v b/tests/vernacular2.t/test.v similarity index 100% rename from tests/test_vernacular2.v rename to tests/vernacular2.t/test.v diff --git a/theories/dune b/theories/dune new file mode 100644 index 000000000..343a07164 --- /dev/null +++ b/theories/dune @@ -0,0 +1,7 @@ +(coq.theory + (name elpi) + (package coq-elpi) + (plugins coq-elpi.elpi) + (theories elpi_elpi)) + +; (include_subdirs qualified) diff --git a/theories/elpi.v b/theories/elpi.v index 145c9d3eb..489e94fd6 100644 --- a/theories/elpi.v +++ b/theories/elpi.v @@ -5,11 +5,11 @@ Declare ML Module "coq-elpi.elpi". Elpi Document Builtins. (* Load once and forall these files in this .vo, to ease redistribution *) -Elpi Checker "coq://elpi/coq-elpi-checker.elpi" "coq://elpi/coq-elpi-checker.elpi". +Elpi Checker "coq://elpi_elpi/coq-elpi-checker.elpi" "coq://elpi_elpi/coq-elpi-checker.elpi". Elpi Printer "elpi2html.elpi" "elpi2html.elpi". (* this one is from elpi *) -Elpi Template Command "coq://elpi/elpi-command-template-synterp.elpi" "coq://elpi/elpi-command-template.elpi". -Elpi Template Tactic "coq://elpi/elpi-tactic-template.elpi". +Elpi Template Command "coq://elpi_elpi/elpi-command-template-synterp.elpi" "coq://elpi_elpi/elpi-command-template.elpi". +Elpi Template Tactic "coq://elpi_elpi/elpi-tactic-template.elpi". (* Special constant used for HOAS of holes, see coq-bultins.elpi *) Lemma hole : True. Proof. exact I. Qed.