Skip to content

Commit 0058048

Browse files
authored
Merge pull request #269 from LPCIC/scoped-term
New backend (elpi 2.0)
2 parents 00da01b + e540bd7 commit 0058048

File tree

354 files changed

+7982
-11442
lines changed

Some content is hidden

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

354 files changed

+7982
-11442
lines changed

.github/workflows/users.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ jobs:
2626
env:
2727
OPAMWITHTEST: false
2828

29-
- run: opam pin add coq-elpi https://github.com/LPCIC/coq-elpi.git#master
30-
- run: opam pin add coq-hierarchy-builder https://github.com/math-comp/hierarchy-builder.git#fix-elpi-loc
31-
- run: opam pin add coq-mathcomp-ssreflect https://github.com/math-comp/math-comp.git#master
32-
- run: opam pin add coq-mathcomp-fingroup https://github.com/math-comp/math-comp.git#master
33-
- run: opam pin add coq-mathcomp-algebra https://github.com/math-comp/math-comp.git#master
34-
- run: opam pin add coq-mathcomp-solvable https://github.com/math-comp/math-comp.git#master
35-
- run: opam pin add coq-mathcomp-field https://github.com/math-comp/math-comp.git#master
29+
- run: opam pin --ignore-constraints-on elpi add coq-elpi https://github.com/LPCIC/coq-elpi.git#master
30+
- run: opam pin --ignore-constraints-on elpi add coq-hierarchy-builder https://github.com/math-comp/hierarchy-builder.git#master
31+
- run: opam pin --ignore-constraints-on elpi add coq-mathcomp-ssreflect https://github.com/math-comp/math-comp.git#master
32+
- run: opam pin --ignore-constraints-on elpi add coq-mathcomp-fingroup https://github.com/math-comp/math-comp.git#master
33+
- run: opam pin --ignore-constraints-on elpi add coq-mathcomp-algebra https://github.com/math-comp/math-comp.git#master
34+
- run: opam pin --ignore-constraints-on elpi add coq-mathcomp-solvable https://github.com/math-comp/math-comp.git#master
35+
- run: opam pin --ignore-constraints-on elpi add coq-mathcomp-field https://github.com/math-comp/math-comp.git#master

CHANGES.md

+71-17
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,78 @@
33
Requires Menhir 20211230 and OCaml 4.08 or above.
44

55
- Compiler:
6-
- New syntax: anonymous predicates can be passed to type signatures in order
7-
to have more information about modes and attributes of higher-order
8-
arguments, eg: `pred p i:(pred i:A, o:B)` tells that the first argument of
9-
`p` is a predicate whose first argument is in input and the second in
10-
output.
11-
- Separated terms from types; the parser generates
12-
- `TypeExpression.t` objects for `pred` and `type` objects
13-
- `TypeAbbreviation.closedTypeexpression` objects for `typeabbrev`, that is
14-
the `TypeExpression.t` type decorated with the `TLam` constructor
15-
- The attribute `:functional` can be passed to predicates (not types),
16-
for example, `:functional pred q i:int, o:int` tells the interpreter that `q` is
17-
a predicate meant to be functional. Note that, due to anonymous predicates,
18-
the `:functional` attributes can be passed to higher-order arguments
19-
- The piece of information likes modes and functionality is transmitted to the
20-
checker (currently this information is not taken into account)
6+
- Change the pipeline completely to make unit relocation unnecessary. Current
7+
phases are (roughly):
8+
1. `Ast.program`[`RecoverStructure`]—> `Ast.Structured.program`
9+
2. `Ast.Structured.program`[`Scope`,`Quotation`,`Macro`]—> `Scoped.program` (aka `API.Compile.scoped_program`)
10+
3. `Scoped.program`[`Flatten`]—> `Flat.program`
11+
4. `Flat.program`[`Check`]—> `CheckedFlat.program` (aka `API.Compile.compilation_unit`)
12+
5. `CheckedFlat.program`[`Spill`,`ToDbl`]—> `Assembled.program`
13+
14+
Steps 4 and 5 operate on a base, that is an `Assembled.program` being
15+
extended. `ToDbl` is in charge of allocating constants (numbers) for global
16+
names and takes place when the unit is assembled on the base. These
17+
constants don't need to be relocated as in the previous backend that
18+
would allocate these constants much earlier.
19+
- Change compilation units can declare new builtin predicates
20+
- Fix macros are hygienic
21+
- New type checker written in OCaml. The new type checker is faster,
22+
reports error messages with a precise location and performs checking
23+
incrementally when the API for separate compilation is used.
24+
The new type checker is a bit less permissive since the old one would
25+
merged together all types declaration before type checking the entire
26+
program, while the new one type checks each unit using the types declared
27+
inside the unit or declared in the base it extends, but not the types
28+
declared in units that (will) follow it.
29+
- Remove the need of `typeabbrv string (ctype "string")` and similar
30+
- New type check types and kinds (used to be ignored).
31+
32+
- API:
33+
- Change quotations generate `Ast.Term.t` and not `RawData.t`. The data
34+
type `Ast.Term.t` contains locations (for locating type errors) and
35+
has named (bound) variables and type annotations in `Ast.Type.t`.
36+
- New `Compile.extend_signature` and `Compile.signature` to extend a
37+
program with the signature (the types, not the code) of a unit
38+
- New `Ast.Loc.t` carries a opaque payload defined by the host application
39+
- Remove `Query`, only `RawQuery` is available (or `Compile.query`)
40+
41+
- Parser:
42+
- Remove legacy parser
43+
- New `% elpi:if version op A.B.C` and `% elpi:endif` lexing directives
44+
- New warning for `A => B, C` to be disabled by putting parentheses
45+
around `A => B`.
46+
47+
- Language:
48+
- New infix `==>` standing for application but with "the right precedence™",
49+
i.e. `A ==> B, C` means `A => (B, C)`.
50+
- New `pred` is allowed in anonymous predicates, eg:
51+
`pred map i:list A, i:(pred i:A, o:B), o:list B` declares that the first
52+
argument of `map` is a predicate whose first argument is in input and
53+
the second in output. Currently the mode checker is still in development,
54+
annotations for higher order arguments are ignored.
55+
- New attribute `:functional` can be passed to predicates (but not types).
56+
For example, `:functional pred map i:list A, i:(:functional pred i:A, o:B), o:list B`
57+
declares `map` to be a functional predicate iff its higher order argument is
58+
functional. Currently the determinacy checker is still in development, these
59+
annotations are ignored.
60+
- New `func` keyword standing for `:functional pred`. The declaration above
61+
can be shortened to `func map i:list A, i:(func i:A, o:B), o:list B`.
62+
- New type annotations on variables quantified by `pi` as in `pi x : term \ ...`
63+
- New type casts on terms, as in `f (x : term)`
64+
- New attribute `:untyped` to skip the type checking of a rule.
65+
66+
- Stdlib:
67+
- New `std.list.init N E L` builds a list `L = [E, ..., E]` with length `N`
68+
- New `std.list.make N F L` builds the list `L = [F 0, F 1, ..., F (N-1)]`
69+
- New `triple` data type with constructor `triple` and projections `triple_1`...
70+
2171
- Builtins:
22-
- `std.list.init N E L` builds a list `L = [E, ..., E]` with length `N`
23-
- `std.list.make N F L` builds the list `L = [F 0, F 1, ..., F (N-1)]`
72+
- Remove `string_to_term`, `read`, `readterm`, `quote_syntax`
73+
74+
- REPL:
75+
- Remove `-no-tc`, `-legacy-parser`, `-legacy-parser-available`
76+
- New `-document-infix-syntax`
77+
2478

2579
# v1.20.0 (September 2024)
2680

ELPI.md

+25-38
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,30 @@ to `elpi`.
298298

299299
The attribute `:if` can also be used on CHR rules.
300300

301+
### Compatibility ifdefs
302+
303+
It is also possible ask the lexer to discard text before it reaches the parser.
304+
305+
```prolog
306+
% elpi:if version < 2.0.0
307+
This text is ignored if the version of Elpi old
308+
% elpi:endif
309+
```
310+
311+
Currently the only variable available is `version` and it must be placed
312+
on the left of the operator (either `<` or `>` or `=`) and ifdefs cannot
313+
be nested. If not available (e.g. `dune subst` did not run) the version
314+
defaults to `99.99.99`.
315+
316+
One can also ask the lexer to always skip some text. That can be useful if one
317+
wants to keep around code that is not meant for Elpi (but for example for Teyjus).
318+
319+
```prolog
320+
% elpi:skip 2
321+
infixr ==> 120. % directive not supported by Elpi
322+
infixr || 120. % last line being skipped
323+
```
324+
301325
## Configurable argument indexing
302326

303327
By default the clauses for a predicate are indexed by looking
@@ -939,8 +963,7 @@ A macro is declared with the following syntax
939963
```prolog
940964
macro @name Args :- Body.
941965
```
942-
It is expanded everywhere (even in type declarations)
943-
at compilation time.
966+
It is expanded at compilation time.
944967
945968
#### Example: literlas
946969
@@ -956,39 +979,3 @@ macro @of X N T :- (of X T, pp X N).
956979
of (lambda Name F) (arr A B) :- pi x\ @of x Name A => of (F x) B.
957980
of (let-in Name V F) R :- of V T, pi x\ @of x Name T => val x V => of (F x) R.
958981
```
959-
960-
#### Example: optional cut.
961-
```prolog
962-
macro @neck-cut-if P Hd Hyps :- (
963-
(Hd :- P, !, Hyps),
964-
(Hd :- not P, Hyps)
965-
).
966-
967-
@neck-cut-if greedy
968-
(f X) (X = 1).
969-
f X :- X = 2.
970-
```
971-
972-
```
973-
goal> greedy => f X.
974-
Success:
975-
X = 1
976-
goal> f X.
977-
Success:
978-
X = 1
979-
More? (Y/n)
980-
Success:
981-
X = 2
982-
```
983-
984-
### Caveat
985-
Currently macros are not truly "hygienic",
986-
that is the body of the macro is not lexically analyzed before
987-
expansion and its free names (of constants) may be captured.
988-
989-
```prolog
990-
macro @m A :- x = A.
991-
main :- pi x\ @m x. % works, but should not!
992-
```
993-
994-
Use with care.

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ help:
1212
@echo ' tests ONLY=rex runs only tests matching rex'
1313
@echo ' tests PROMOTE=true runs and promote tests if different'
1414
@echo ' (can be combined with ONLY)'
15+
@echo ' tests LN_NB=nb sets max number of lines to print of failing tests'
16+
@echo ' (negave numbers means print all file)'
1517
@echo ' tests STOP_ON_FST_ERROR=true stops the test suite after first error'
1618
@echo
1719
@echo ' git/treeish checkout treeish and build elpi.git.treeish'
@@ -29,6 +31,7 @@ BUILD=_build/default
2931
SHELL:=/usr/bin/env bash
3032
TIMEOUT=90.0
3133
PROMOTE=false
34+
LN_NB=-1
3235
STOP_ON_FST_ERROR=false
3336
PWD=$(shell pwd)
3437
RUNNERS=\
@@ -84,6 +87,7 @@ tests:
8487
tests/test.exe \
8588
--seed $$RANDOM \
8689
--promote $(PROMOTE) \
90+
--ln_nb=$(LN_NB) \
8791
--timeout $(TIMEOUT) \
8892
--stop-on-first-error=$(STOP_ON_FST_ERROR) \
8993
$(TIME) \

dune

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
(executable
22
(name elpi_REPL)
33
(public_name elpi)
4-
(libraries elpi)
4+
(libraries elpi elpi.parser ;memtrace
5+
)
56
(modules elpi_REPL)
67
(package elpi)
78
)
89

910
(env
1011
(dev
11-
(flags (:standard -w -9 -w -32 -w -27 -w -6 -w -37 -warn-error -A)))
12+
(flags (:standard -w -9 -w -32 -w -27 -warn-error -A)))
1213
(fatalwarnings
13-
(flags (:standard -w -9 -w -32 -w -27 -w -6 -w -37 -warn-error +A))))
14+
(flags (:standard -w -9 -w -32 -w -27 -warn-error +A))))

elpi_REPL.ml

+16-27
Original file line numberDiff line numberDiff line change
@@ -58,60 +58,54 @@ let usage =
5858
"\t-exec pred runs the query \"pred ARGS\"\n" ^
5959
"\t-D var Define variable (conditional compilation)\n" ^
6060
"\t-document-builtins Print documentation for built-in predicates\n" ^
61-
"\t-no-tc don't typecheck the program\n" ^
61+
"\t-document-infix-syntax Print the documentation for infix operators\n" ^
6262
"\t-I PATH search for accumulated files in PATH\n" ^
6363
"\t-delay-problems-outside-pattern-fragment (deprecated, for Teyjus\n" ^
6464
"\t compatibility)\n" ^
65-
"\t-legacy-parser enable the legacy parser (deprecated)\n"^
66-
"\t-legacy-parser-available exists with 0 if it is the case\n"^
6765
"\t--version prints the version of Elpi (also -v or -version)\n" ^
6866
"\t--help prints this help (also -h or -help)\n" ^
6967
API.Setup.usage ^
7068
"\nDebug options (for debugging Elpi, not your program):\n" ^
7169
"\t-parse-term parses a term from standard input and prints it\n" ^
7270
"\t-print-ast prints files as parsed, then exit\n" ^
7371
"\t-print prints files after most compilation passes, then exit\n" ^
74-
"\t-print-passes prints intermediate data during compilation, then exit\n" ^
7572
"\t-print-units prints compilation units data, then exit\n"
7673
;;
7774

7875
(* For testing purposes we declare an identity quotation *)
7976
let quotations = API.Quotation.new_quotations_descriptor ()
8077
let _ =
8178
API.Quotation.register_named_quotation ~descriptor:quotations ~name:"elpi"
82-
API.Quotation.lp
79+
API.Quotation.elpi
8380

8481
let _ =
82+
(* Memtrace.trace_if_requested (); <-- new line *)
83+
(* Hashtbl.randomize (); *)
8584
let test = ref false in
8685
let exec = ref "" in
8786
let print_lprolog = ref false in
8887
let print_ast = ref false in
89-
let typecheck = ref true in
9088
let batch = ref false in
9189
let doc_builtins = ref false in
90+
let doc_infix = ref false in
9291
let delay_outside_fragment = ref false in
9392
let print_passes = ref false in
9493
let print_units = ref false in
9594
let extra_paths = ref [] in
96-
let legacy_parser = ref false in
9795
let parse_term = ref false in
9896
let vars =
9997
ref API.Compile.(default_flags.defined_variables) in
10098
let rec eat_options = function
10199
| [] -> []
102100
| "-delay-problems-outside-pattern-fragment" :: rest -> delay_outside_fragment := true; eat_options rest
103-
| "-legacy-parser" :: rest -> legacy_parser := true; eat_options rest
104-
| "-legacy-parser-available" :: _ ->
105-
if API.Setup.legacy_parser_available then exit 0 else exit 1
106101
| "-test" :: rest -> batch := true; test := true; eat_options rest
107102
| "-exec" :: goal :: rest -> batch := true; exec := goal; eat_options rest
108103
| "-print" :: rest -> print_lprolog := true; eat_options rest
109104
| "-print-ast" :: rest -> print_ast := true; eat_options rest
110-
| "-print-passes" :: rest -> print_passes := true; eat_options rest
111105
| "-print-units" :: rest -> print_units := true; eat_options rest
112106
| "-parse-term" :: rest -> parse_term := true; eat_options rest
113-
| "-no-tc" :: rest -> typecheck := false; eat_options rest
114107
| "-document-builtins" :: rest -> doc_builtins := true; eat_options rest
108+
| "-document-infix-syntax" :: rest -> doc_infix := true; eat_options rest
115109
| "-D" :: var :: rest -> vars := API.Compile.StrSet.add var !vars; eat_options rest
116110
| "-I" :: p :: rest -> extra_paths := !extra_paths @ [p]; eat_options rest
117111
| ("-h" | "--help" | "-help") :: _ -> Printf.eprintf "%s" usage; exit 0
@@ -133,12 +127,14 @@ let _ =
133127
let paths = tjpath @ installpath @ [execpath] @ !extra_paths in
134128
let flags = {
135129
API.Compile.defined_variables = !vars;
136-
API.Compile.print_passes = !print_passes;
137130
API.Compile.print_units = !print_units;
138131
} in
132+
if !doc_infix then begin
133+
Printf.eprintf "%s" Elpi_parser.Parser_config.legacy_parser_compat_error;
134+
exit 0
135+
end;
139136
let elpi =
140137
API.Setup.init
141-
~legacy_parser:!legacy_parser
142138
~quotations
143139
~flags:(API.Compile.to_setup_flags flags)
144140
~builtins:[Builtin.std_builtins]
@@ -199,29 +195,22 @@ let _ =
199195
end;
200196

201197
Format.eprintf "@\nParsing time: %5.3f@\n%!" (Unix.gettimeofday () -. t0_parsing);
202-
let query, exec =
198+
let query, prog, exec, type_checking_time =
203199
let t0_compilation = Unix.gettimeofday () in
204200
try
205201
let prog = API.Compile.program ~flags ~elpi [p] in
206202
let query = API.Compile.query prog g in
203+
let type_checking_time = API.Compile.total_type_checking_time query in
207204
let exec = API.Compile.optimize query in
208205
Format.eprintf "@\nCompilation time: %5.3f@\n%!" (Unix.gettimeofday () -. t0_compilation);
209-
query, exec
206+
query, prog, exec, type_checking_time
210207
with API.Compile.CompileError(loc,msg) ->
211208
API.Utils.error ?loc msg
212209
in
213-
if !typecheck then begin
214-
let t0 = Unix.gettimeofday () in
215-
let b = API.Compile.static_check ~checker:(Builtin.default_checker ()) query in
216-
Format.eprintf "@\nTypechecking time: %5.3f@\n%!" (Unix.gettimeofday () -. t0);
217-
if not b then begin
218-
Format.eprintf "Type error. To ignore it, pass -no-tc.\n";
219-
exit 1
220-
end;
221-
end;
210+
Format.eprintf "@\nTypechecking time: %5.3f@\n%!" type_checking_time;
222211
if !print_lprolog then begin
223-
API.Pp.program Format.std_formatter query;
224-
Format.printf "?- ";
212+
API.Pp.program Format.std_formatter prog;
213+
Format.printf "\n\n%% query\n?- ";
225214
API.Pp.goal Format.std_formatter query;
226215
exit 0;
227216
end;

0 commit comments

Comments
 (0)