Skip to content

Commit d60382d

Browse files
authored
Merge pull request #847 from Matafou/fix-elpi-parsing
Fixing elpi syntax Initial idea by Philip Kaludercic.
2 parents b82c219 + 74ba7fc commit d60382d

File tree

4 files changed

+98
-67
lines changed

4 files changed

+98
-67
lines changed

ci/coq-tests.el

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ then evaluate the BODY function and finally tear-down (exit Coq)."
137137
;;; For info on macros: https://mullikine.github.io/posts/macro-tutorial
138138
;;; (pp (macroexpand '(macro args)))
139139
(save-excursion
140+
(if file (should (file-exists-p file)))
140141
(let* (;; avoids bad width detection in batch mode
141142
(coq-auto-adapt-printing-width nil)
142143
(openfile (or file
@@ -503,6 +504,23 @@ For example, COMMENT could be (*test-definition*)"
503504
(equal (span-end sp) (+ 1 proof-cmd-point (length "bar")))))
504505
)
505506
(should (equal (proof-queue-or-locked-end) (point-min))))))))
507+
508+
(ert-deftest 200_test-command-spliting ()
509+
"Test command splitting of a file."
510+
(coq-fixture-on-file
511+
(coq-test-full-path "test_command_parsing.v")
512+
(lambda ()
513+
(coq-test-goto-before "(*init*)")
514+
(proof-goto-point)
515+
(proof-shell-wait)
516+
(goto-char (point-min))
517+
(let ((cpt 0) type)
518+
(while (setq type (funcall proof-script-parse-function))
519+
(setq cpt (+ 1 cpt))
520+
(should (equal type 'cmd)))
521+
(should (equal cpt 17))))))
522+
523+
506524
(provide 'coq-tests)
507525

508526
;;; coq-tests.el ends here

ci/test_command_parsing.v

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Definition Foo := nat.
2+
Definition Bar := nat.
3+
(*init*)
4+
From elpi Require Import elpi.
5+
6+
7+
Lemma le_prop: forall n m p:entier, le n m -> le m p -> le n p.
8+
Proof.
9+
intros n m p.
10+
intro H.
11+
revert p.
12+
induction H;intros.
13+
- assumption.
14+
- { + apply IHle.
15+
apply le_Suuc_a_gauche.
16+
assumption. }
17+
Qed.
18+
19+
20+
21+
Elpi Tactic show.
22+
Elpi Accumulate lp:{{
23+
24+
solve (goal Ctx _Trigger Type Proof _) _ :-
25+
coq.say "Goal:" Ctx "|-" Proof ":" Type.
26+
27+
}}.

coq/coq-indent.el

Lines changed: 51 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
;; This file is part of Proof General.
44

55
;; Portions © Copyright 1994-2012 David Aspinall and University of Edinburgh
6-
;; Portions © Copyright 2003-2021 Free Software Foundation, Inc.
6+
;; Portions © Copyright 2003-2021, 2023 Free Software Foundation, Inc.
77
;; Portions © Copyright 2001-2017 Pierre Courtieu
88
;; Portions © Copyright 2010, 2016 Erik Martin-Dorel
99
;; Portions © Copyright 2011-2013, 2016-2017 Hendrik Tews
@@ -37,7 +37,7 @@
3737
(defconst coq-comment-start-or-end-regexp
3838
(concat coq-comment-start-regexp "\\|" coq-comment-end-regexp))
3939

40-
(defconst coq-bullet-regexp-nospace "\\(-\\)+\\|\\(+\\)+\\|\\(\\*\\)+"
40+
(defconst coq-bullet-regexp-nospace "\\(-\\)+\\|\\(\\+\\)+\\|\\(\\*\\)+"
4141
"Matches single bullet, WARNING: Lots of false positive.
4242
4343
No context checking.")
@@ -53,9 +53,9 @@ No context checking.")
5353
;; use of the fact that the file is processed from top to bottom. At
5454
;; each step the point is put just after the last recognized chunk,
5555
;; then spaces are jumped, and THEN the regexp for command end is
56-
;; searched. Since bullets are are command ends occurring at command
56+
;; searched. Since bullets are command ends occurring at command
5757
;; start, we use the "\\=" regexp to tell if we are at the beginning
58-
;; of a command. We don't car for the presence of comments, as the
58+
;; of a command. We don't care for the presence of comments, as the
5959
;; regexp search is launched once coments are passed.
6060
;; On the contrary when going backward we cannot use this trick.
6161

@@ -96,9 +96,11 @@ There are 3 substrings (2 and 3 may be nil):
9696
* number 2 is the left context matched that is not part of the bullet
9797
* number 3 is the right context matched that is not part of the bullet")
9898

99-
;; captures a lot of false bullets, unless called at the first non
100-
;; space character of a command. The primary use of this variable is
101-
;; to split the buffer into commands, from top to bottom.
99+
;; captures a lot of false bullets, unless called at the first non space character
100+
;; of a command. The primary use of this variable is to split the buffer into
101+
;; commands, from top to bottom. We use the \= regexp for the special case where we
102+
;; match the regexp at the very starting point (in which case we don't look at what
103+
;; is before the main regexp)
102104
(defconst coq-bullet-end-command-forward
103105
(concat "\\(?:\\=\\(?1:" coq-bullet-regexp-nospace "\\)\\)")
104106
"Matches ltac bullets. WARNING: lots of false positive.
@@ -110,7 +112,7 @@ only when searching backward).")
110112

111113
;; Context aware detecting regexp, usefull when search backward.
112114
(defconst coq-bullet-end-command-backward
113-
(concat "\\(?:\\(?2:" coq-bullet-prefix-regexp-backward "\\)\\(?1:\\(-\\)+\\|\\(+\\)+\\|\\(\\*\\)+\\)\\)")
115+
(concat "\\(?:\\(?2:" coq-bullet-prefix-regexp-backward "\\)\\(?1:\\(-\\)+\\|\\(\\+\\)+\\|\\(\\*\\)+\\)\\)")
114116
"Matches ltac bullets when searching backward.
115117
116118
This should match EXACTLY bullets. No false positive should be accepted.
@@ -122,7 +124,7 @@ There are 2 substrings:
122124
(concat
123125
"\\(?:"
124126
"\\(?2:"
125-
"\\(?:" coq-bullet-prefix-regexp-forward"\\)\\)"
127+
"\\(?:" coq-bullet-prefix-regexp-forward "\\)\\)"
126128
"\\(?1:\\(?:" coq-goal-selector-regexp "\\)?{\\)"
127129
"\\(?3:\\s-*[^|{]\\)"
128130
"\\|"
@@ -191,7 +193,6 @@ There are 3 substrings (2 and 3 may be nil):
191193
Remark: This regexp is much more precise than `coq-end-command-regexp-forward'
192194
but only works when searching backward.")
193195

194-
(defconst coq-cmd-end-backward-matcher (concat "\\(?2:" coq-simple-cmd-ender-prefix-regexp-backward "\\)\\.\\s-"))
195196

196197
(defun coq-looking-at-comment ()
197198
"Return non-nil if point is inside a comment."
@@ -345,9 +346,12 @@ a comment, return nil and does not move the point."
345346
;; )))
346347
;; (when found (point))))
347348

348-
;; check if we are in the middle of an command ender. Return the
349-
;; number of shift needed to have to move one char to see the end of a
350-
;; command. typically if we are ( >< is the cursor). intro.><
349+
;; check if we are in the middle of an command ender. Return the number of left
350+
;; shifts needed to move to see the whole command ender a command. typically if we
351+
;; are ( >< is the cursor):
352+
;; intro.><, then we return 1
353+
;; intro><., then we return 0
354+
;; int><ro., then we return 0
351355
(defun coq-is-on-ending-context ()
352356
(cond
353357
((looking-at "}") 0)
@@ -388,6 +392,32 @@ Comments are ignored, of course."
388392
))
389393

390394

395+
;; Strictly speaking lp:{{ could be a goal selector?
396+
(defun coq-is-at-elpi-block (pos)
397+
(save-excursion (goto-char pos) (and (looking-at "{{") (looking-back "lp:"))))
398+
399+
(defun coq-in-elpi-block (lopen)
400+
(cl-find-if 'coq-is-at-elpi-block lopen))
401+
402+
(defun coq-confirm-cmdend (&optional pos)
403+
"Return t if POS is really a Rocq command end.
404+
405+
WARNING: POS should be looking at a command that matched command end
406+
regexp. This function only checks if it is not a false positive, like
407+
something like a bullet (-,+,*) but actually not at the beginning of a
408+
command, or a regular command end but located in a comment or inside an
409+
elpi block."
410+
(save-excursion
411+
(if pos (goto-char pos))
412+
(let ((ppss (syntax-ppss)))
413+
(cond
414+
((nth 3 ppss) nil) ;; inside a string
415+
((nth 4 ppss) nil) ;; inside a comment
416+
((coq-in-elpi-block (nth 9 ppss)) nil)
417+
((looking-at "\\+\\|\\*\\|-\\|{\\|}") (coq-empty-command-p))
418+
(t)))))
419+
420+
391421
; slight modification of proof-script-generic-parse-cmdend (one of the
392422
; candidate for proof-script-parse-function), to allow "{" and "}" to
393423
; be command terminator when the command is empty. This function is
@@ -411,36 +441,15 @@ regexp."
411441
(and
412442
(re-search-forward coq-end-command-regexp-forward limit t)
413443
(match-end 1)))
414-
(or
415-
(and (not (or (string-equal (match-string 1) ".")
416-
(string-equal (match-string 1) "...")))
417-
;; Checking that this is really a bullet
418-
;; command-end that are not a dot are + ++ -
419-
;; -- etc or { or }. To ensure this is really
420-
;; a bullet (and not one of the numerous
421-
;; other possible uses of those tokens) we
422-
;; check that the command ended by it is
423-
;; empty. example:
424-
;; destruct x.
425-
;; - (* - here ends an empty command*)
426-
(save-excursion
427-
(goto-char (match-beginning 1))
428-
(not (coq-empty-command-p))))
429-
(and
430-
(goto-char foundend)
431-
(nth 8 (syntax-ppss)))))
444+
(not (coq-confirm-cmdend (match-beginning 1))))
432445
;; Given the form of coq-end-command-regexp-forward
433446
;; match-end 1 is the right place to start again
434447
;; to search backward, next time we start from just
435448
;; there
436449
(ignore-errors (goto-char foundend)))
437-
(if (and foundend
438-
(goto-char foundend) ; move to command end
439-
(not (nth 8 (syntax-ppss))))
440-
;; Found command end outside string/comment
441-
'cmd
442-
;; Didn't find command end
443-
nil))))
450+
(if (not foundend) nil
451+
(goto-char foundend)
452+
'cmd))))
444453

445454

446455
;; This is not used by generic pg, just by a few functions in here.
@@ -464,31 +473,11 @@ and return nil."
464473
(and
465474
(re-search-backward coq-end-command-regexp-backward limit 'dummy)
466475
(match-beginning 1)))
467-
;; Given the form of coq-end-command-regexp-backward
468-
;; - bullets should be correctly detected
469-
;; - match-beginning 1 is the right place to start again
470-
;; to search backward, next time we start from just
471-
;; there, unless we are in a comment
472-
(goto-char foundbeg)
473-
(let ((ppss (syntax-ppss)))
474-
;; If neither within a string nor a comment, just exit the
475-
;; loop. Otherwise see what kind of syntactic
476-
(and (nth 8 ppss)
477-
(cond
478-
;; jump directly out of a comment
479-
((nth 4 ppss)
480-
(setq foundbeg (goto-char (nth 8 ppss))))
481-
((nth 3 ppss) t) ;FIXME: Why?
482-
;; nil captured before entering the cond
483-
(t (message "assert false"))))))
476+
(not (coq-confirm-cmdend (match-beginning 1))))
484477
(ignore-errors (goto-char foundbeg)))
485-
(if (and foundbeg
486-
(goto-char foundbeg) ; move to command end
487-
(not (nth 8 (syntax-ppss))))
488-
;; Found command end outside string/comment
489-
'cmd
490-
;; Didn't find command end
491-
nil))))
478+
(if (not foundbeg) nil
479+
(goto-char foundbeg)
480+
'cmd))))
492481

493482

494483
(defun coq-find-current-start ()

coq/coq.el

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,15 +488,12 @@ This is a subroutine of `proof-shell-filter'."
488488

489489

490490
;; slight modification of proof-script-generic-parse-cmdend (one of the
491-
;; candidate for proof-script-parse-function), to allow "{" and "}" to be
492-
;; command terminator when the command is empty. TO PLUG: swith the comment
493-
;; below and rename coq-script-parse-function2 into coq-script-parse-function
491+
;; candidate for proof-script-parse-function). See its definition in
492+
;; coq-indent.el.
494493
(defun coq-script-parse-function ()
495494
"For `proof-script-parse-function' if `proof-script-command-end-regexp' set."
496495
(coq-script-parse-cmdend-forward))
497496

498-
;;;;;;;;;;;;;;;;;;;;;;;;;; End of "{" and "} experiments ;;;;;;;;;;;;
499-
500497

501498
;;;;;;;;;;;;;;;;;;;;;;;;;; Freeze buffers ;;;;;;;;;;;;
502499
;; For storing output of respnse and goals buffers into a permanent buffer.

0 commit comments

Comments
 (0)