aboutsummaryrefslogtreecommitdiffhomepage
path: root/coq/coq-smie.el
diff options
context:
space:
mode:
Diffstat (limited to 'coq/coq-smie.el')
-rw-r--r--coq/coq-smie.el136
1 files changed, 92 insertions, 44 deletions
diff --git a/coq/coq-smie.el b/coq/coq-smie.el
index c488e73f..15697354 100644
--- a/coq/coq-smie.el
+++ b/coq/coq-smie.el
@@ -1,10 +1,18 @@
;;; coq-smie.el --- SMIE lexer, grammar, and indent rules for Coq
-;; Copyright (C) 2014 Free Software Foundation, Inc
+;; This file is part of Proof General.
+
+;; Portions © Copyright 1994-2012 David Aspinall and University of Edinburgh
+;; Portions © Copyright 2003, 2012, 2014 Free Software Foundation, Inc.
+;; Portions © Copyright 2001-2017 Pierre Courtieu
+;; Portions © Copyright 2010, 2016 Erik Martin-Dorel
+;; Portions © Copyright 2011-2013, 2016-2017 Hendrik Tews
+;; Portions © Copyright 2015-2017 Clément Pit-Claudel
;; Authors: Pierre Courtieu
;; Stefan Monnier
;; Maintainer: Pierre Courtieu <Pierre.Courtieu@cnam.fr>
+
;; License: GPLv3+ (GNU GENERAL PUBLIC LICENSE version 3 or later)
;;; Commentary:
@@ -12,7 +20,7 @@
;; Lexer.
;; Due to the verycomplex grammar of Coq, and to the architecture of
-;; smie, we deambiguate all kinds of tokens during lexing. This is a
+;; smie, we deambiguate all kinds of tokens during lexing. This is a
;; complex piece of code but it allows for all smie goodies.
;; Some examples of deambigations:
;; - We distinguish ":=" from ":= inductive" to avoid the circular precedence
@@ -42,6 +50,19 @@
; ,@body
; (message "%.06f" (float-time (time-since time)))))
+(defcustom coq-smie-user-tokens nil
+ "Alist of (syntax . token) pairs to extend the coq smie parser.
+These are user configurable additional syntax for smie tokens. It
+allows to define alternative syntax for smie token. Typical
+example: if you define a infix operator \"xor\" you may want to
+define it as a new syntax for token \"or\" in order to have the
+indentation rules of or applied to xor. Other exemple: if you
+want to define a new notation \"ifb\" ... \"then\" \"else\" then
+you need to declare \"ifb\" as a new syntax for \"if\" to make
+indentation work well."
+ :type '(alist :key-type string :value-type string)
+ :group 'coq)
+
(defun coq-string-suffix-p (str1 str2 &optional ignore-case)
"Return non-nil if STR1 is a prefix of STR2.
@@ -92,7 +113,7 @@ attention to case differences."
(defun coq-smie-is-ltacdef ()
(let ((case-fold-search nil))
- (save-excursion
+ (save-excursion
(coq-find-real-start)
(looking-at "\\(\\(Local\\|Global\\)\\s-+\\)?\\(Ltac\\|Tactic\\s-+Notation\\)\\s-"))))
@@ -216,11 +237,11 @@ the token of \".\" is simply \".\"."
;; tokens and ignore-bteween are not disjoint
(defun coq-smie-search-token-forward (tokens &optional end ignore-between)
"Search for one of TOKENS between point and END.
-If some enclosing parenthesis is reached, stop there and return
-nil. Token \".\" is considered only if followed by a space.
-optional IGNORE-BETWEEN defines opener/closer to ignore during
-search. Careful: the search for a opener stays inside the current
-command (and inside parenthesis)."
+If some enclosing parenthesis is reached, stop there and return nil.
+Token \".\" is considered only if followed by a space. Optional
+IGNORE-BETWEEN defines opener/closer to ignore during search.
+Careful: the search for a opener stays inside the current command (and
+inside parenthesis)."
(unless end (setq end (point-max)))
(condition-case nil
(catch 'found
@@ -261,11 +282,12 @@ command (and inside parenthesis)."
;; tokens and ignore-bteween are not disjoint
(defun coq-smie-search-token-backward (tokens &optional end ignore-between)
"Search for one of TOKENS between point and END.
-If some enclosing parenthesis is reached, stop there and return
-nil. Token \".\" is considered only if followed by a space.
+If some enclosing parenthesis is reached, stop there and return nil.
+Token \".\" is considered only if followed by a space.
optional IGNORE-BETWEEN defines opener/closer to ignore during
-search. Careful: the search for a opener stays inside the current
-command (and inside parenthesis). "
+search.
+Careful: the search for a opener stays inside the current command (and
+inside parenthesis)."
(unless end (setq end (point-min)))
(condition-case nil
(catch 'found
@@ -322,9 +344,9 @@ proof-mode starter in Coq."
;; each goal anyway.
(defun coq-smie-detect-goal-command ()
"Return t if the next command is a goal starting to be indented.
-The point should be at the beginning of the command name. As
-false positive are more annoying than false negative, return t
-only if it is FOR SURE a goal opener. Put a \"Proof.\" when you want to
+The point should be at the beginning of the command name.
+As false positive are more annoying than false negative, return t only
+if it is FOR SURE a goal opener. Put a \"Proof.\" when you want to
force indentation."
(save-excursion ; FIXME add other commands that potentialy open goals
(when (proof-looking-at "\\(Local\\|Global\\)?\
@@ -341,7 +363,7 @@ force indentation."
The point should be at the beginning of the command name."
(save-excursion ; FIXME Is there other module starting commands?
(cond
- ((looking-back "with\\s-+" nil) "module") ; lowecase means Module that is not a declaration keyword (like in with Module)
+ ((looking-back "with\\s-+" nil) "module") ; lowecase means Module that is not a declaration keyword (like in with Module)
((proof-looking-at "\\(Module\\|Section\\)\\>")
(if (coq-lonely-:=-in-this-command) "Module start" "Module def")))))
@@ -373,8 +395,11 @@ The point should be at the beginning of the command name."
(defun coq-smie-forward-token ()
- (let ((tok (coq-forward-token-fast-nogluing-dot-friends)))
+ (let ((tok (smie-default-forward-token)))
(cond
+ ((assoc tok coq-smie-user-tokens)
+ (let ((res (assoc tok coq-smie-user-tokens)))
+ (cdr res)))
;; @ may be ahead of an id, it is part of the id.
((and (equal tok "@") (looking-at "[[:alpha:]_]"))
(let ((newtok (coq-smie-forward-token))) ;; recursive call
@@ -481,7 +506,7 @@ The point should be at the beginning of the command name."
":= with"
(goto-char p)
":= module")))
- ((member corresp '("Inductive" "CoInductive")) ":= inductive")
+ ((member corresp '("Inductive" "CoInductive" "Variant")) ":= inductive")
((equal corresp "let") ":= let")
((equal corresp "where") ":= inductive") ;; inductive or fixpoint, nevermind
((or (looking-back "{" nil)) ":= record")
@@ -492,6 +517,9 @@ The point should be at the beginning of the command name."
(defun coq-smie-backward-token ()
(let* ((tok (smie-default-backward-token)))
(cond
+ ((assoc tok coq-smie-user-tokens)
+ (let ((res (assoc tok coq-smie-user-tokens)))
+ (cdr res)))
;; Distinguish between "," from quantification and other uses of
;; "," (tuples, tactic arguments)
((equal tok ",")
@@ -530,7 +558,7 @@ The point should be at the beginning of the command name."
(equal (coq-smie-backward-token) "; tactic")) ;; recursive
"|| tactic")
;; this is wrong half of the time but should not harm indentation
- ((and (equal backtok nil) (looking-back "(" nil)) "||")
+ ((and (equal backtok nil) (looking-back "(" nil)) "||")
((equal backtok nil)
(if (or (looking-back "\\[" nil)
(and (looking-back "{" nil)
@@ -567,12 +595,28 @@ The point should be at the beginning of the command name."
(goto-char (1- (point))) "{|")
((and (zerop (length tok)) (member (char-before) '(?\{ ?\}))
- (save-excursion
- (forward-char -1)
- (let ((nxttok (coq-smie-backward-token))) ;; recursive call
- (coq-is-cmdend-token nxttok))))
+ (save-excursion
+ (forward-char -1)
+ (if (and (looking-at "{")
+ (looking-back "\\([0-9]+\\s-*:\\s-*\\)" nil t))
+ (goto-char (match-beginning 0)))
+ (let ((nxttok (coq-smie-backward-token))) ;; recursive call
+ (coq-is-cmdend-token nxttok))))
(forward-char -1)
- (if (looking-at "{") "{ subproof" "} subproof"))
+ (if (looking-at "}") "} subproof"
+ (if (and (looking-at "{")
+ (looking-back "\\([0-9]+\\s-*:\\s-*\\)" nil t))
+ (goto-char (match-beginning 0)))
+ "{ subproof"
+ ))
+
+ ;; ((and (zerop (length tok)) (member (char-before) '(?\{ ?\}))
+ ;; (save-excursion
+ ;; (forward-char -1)
+ ;; (let ((nxttok (coq-smie-backward-token))) ;; recursive call
+ ;; (coq-is-cmdend-token nxttok))))
+ ;; (forward-char -1)
+ ;; (if (looking-at "{") "{ subproof" "} subproof"))
((and (equal tok ":") (looking-back "\\<\\(constr\\|ltac\\|uconstr\\)" nil))
": ltacconstr")
@@ -592,9 +636,16 @@ The point should be at the beginning of the command name."
;; FIXME: no token should end with "." except "." itself
; for "unfold in *|-*."
- ((member tok '("*." "-*." "|-*." "*|-*.")) (forward-char 1) ".")
+ ((member tok '("*." "-*." "|-*." "*|-*."))
+ (forward-char (- (length tok) 1))
+ (coq-smie-.-deambiguate))
; for "unfold in *|-*;"
- ((member tok '("*;" "-*;" "|-*;" "*|-*;")) (forward-char 1) "; tactic") ;; FIXME; can be "; ltac" too
+ ((member tok '("*;" "-*;" "|-*;" "*|-*;"))
+ ;; FIXME; can be "; ltac" too
+ (forward-char (- (length tok) 1)) "; tactic")
+ ;; bullet detected, is it really a bullet? we have to traverse
+ ;; recursively any other bullet or "n:{" "}". this is the work of
+ ;; coq-empty-command-p
((and (string-match coq-bullet-regexp-nospace tok)
(save-excursion (coq-empty-command-p)))
(concat tok " bullet"))
@@ -719,8 +770,7 @@ Lemma foo: forall n,
instead of:
Lemma foo: forall n,
- n = n.
-"
+ n = n."
:type 'boolean
:group 'coq)
@@ -734,19 +784,18 @@ Lemma foo: forall n,
:safe #'coq-indent-safep)
(defcustom coq-indent-semicolon-tactical 2
- "Number of spaces used to indent after the first tactical semi colon of a serie.
- If set to 0, indetation is as follows:
- tac1;
- tac2;
- tac3;
- tac4.
-
- if set to 2 (default):
-
- tac1;
- tac2;
- tac3;
- tac4."
+ "Number of spaces used to indent after the 1st tactical semicolon of a serie.
+If set to 0, indentation is as follows:
+tac1;
+tac2;
+tac3;
+tac4.
+
+If set to 2 (default):
+tac1;
+ tac2;
+ tac3;
+ tac4."
:type 'integer
:group 'coq
:safe #'coq-indent-safep)
@@ -770,8 +819,7 @@ for example, if set to 0 the indentation is as follows:
If it is set to 2 (default) it is as follows:
Lemma foo: forall x:nat,
- x <= 0 -> x = 0.
-"
+ x <= 0 -> x = 0."
:type 'integer
:group 'coq
:safe #'coq-indent-safep)
@@ -956,7 +1004,7 @@ Typical values are 2 or 4."
;; copied from elixir-smie.el
(defun coq-smie--same-line-as-parent (parent-pos child-pos)
- "Return non-nil if `child-pos' is on same line as `parent-pos'."
+ "Return non-nil if PARENT-POS is on same line as CHILD-POS."
(= (line-number-at-pos parent-pos) (line-number-at-pos child-pos)))
(defun coq-smie-rules (kind token)