;;; proof-syntax.el --- Functions for dealing with syntax ;; This file is part of Proof General. ;; Portions © Copyright 1994-2012 David Aspinall and University of Edinburgh ;; Portions © Copyright 2003-2018 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: David Aspinall, Healfdene Goguen, ;; Thomas Kleymann, Dilip Sequiera ;; License: GPL (GNU GENERAL PUBLIC LICENSE) ;;; Commentary: ;; ;;; Code: (require 'font-lock) (require 'proof-config) ; proof-case-fold-search (require 'pg-pamacs) ; proof-ass-sym (defsubst proof-ids-to-regexp (l) "Maps a non-empty list of tokens L to a regexp matching any element. Uses a regexp of the form \\_<...\\_>." (concat "\\_<" (regexp-opt l) ; was: (mapconcat 'identity l "\\|") "\\_>")) (defsubst proof-anchor-regexp (e) "Anchor (\\`) and group the regexp E." (concat "\\`\\(" e "\\)")) (defconst proof-no-regexp "\\<\\>" "A regular expression that never matches anything.") (defsubst proof-regexp-alt-list (args) "Return the regexp which matches any of the regexps ARGS." (mapconcat #'identity args "\\|")) (defsubst proof-regexp-alt (&rest args) "Return the regexp which matches any of the regexps ARGS." ;; see regexp-opt (NB: but that is for strings, not regexps) (proof-regexp-alt-list args)) (defsubst proof-re-search-forward-region (startre endre) "Search for a region delimited by regexps STARTRE and ENDRE. Return the start position of the match for STARTRE, or nil if a region cannot be found." (if (re-search-forward startre nil t) (let ((start (match-beginning 0))) (if (re-search-forward endre nil t) start)))) ;; Functions for string matching and searching that take into account ;; value of proof-case-fold-search. Last arg to string-match is not ;; applicable. (defsubst proof-search-forward (string &optional bound noerror count) "Like ‘search-forward’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (let ((case-fold-search proof-case-fold-search)) (search-forward string bound noerror count))) ;;;###autoload (defun proof-replace-regexp-in-string (regexp rep string) "Like ‘replace-regexp-in-string’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (let ((case-fold-search proof-case-fold-search)) (replace-regexp-in-string regexp rep string))) (defsubst proof-re-search-forward (regexp &optional bound noerror count) "Like ‘re-search-forward’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (let ((case-fold-search proof-case-fold-search)) (re-search-forward regexp bound noerror count))) (defsubst proof-re-search-backward (regexp &optional bound noerror count) "Like ‘re-search-backward’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (let ((case-fold-search proof-case-fold-search)) (re-search-backward regexp bound noerror count))) (defsubst proof-re-search-forward-safe (regexp &optional bound noerror count) "Like ‘re-search-forward’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (and regexp (let ((case-fold-search proof-case-fold-search)) (re-search-forward regexp bound noerror count)))) (defsubst proof-string-match (regexp string &optional start) "Like ‘string-match’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (let ((case-fold-search proof-case-fold-search)) (string-match regexp string start))) (defsubst proof-string-match-safe (regexp string &optional start) "Like ‘string-match’, but return nil if REGEXP or STRING is nil." (if (and regexp string) (proof-string-match regexp string start))) (defsubst proof-stringfn-match (regexp-or-fn string) "Like ‘proof-string-match’ if first arg is regexp, otherwise call it." (cond ((stringp regexp-or-fn) (proof-string-match regexp-or-fn string)) ((functionp regexp-or-fn) (funcall regexp-or-fn string)))) (defsubst proof-looking-at (regexp) "Like ‘looking-at’, but set ‘case-fold-search’ to ‘proof-case-fold-search’." (let ((case-fold-search proof-case-fold-search)) (looking-at regexp))) (defsubst proof-looking-at-safe (regexp) "Like ‘proof-looking-at’, but return nil if REGEXP is nil." (if regexp (proof-looking-at regexp))) ;; ;; Syntactic context ;; ;; A function named after one in XEmacs (defun proof-buffer-syntactic-context (&optional buffer) "Return the syntactic context of BUFFER at point. If BUFFER is nil or omitted, the current buffer is assumed. The returned value is one of the following symbols: nil ; meaning no special interpretation string ; meaning point is within a string comment ; meaning point is within a line comment" (save-excursion (if buffer (set-buffer buffer)) (let ((pp (syntax-ppss))) ;;(parse-partial-sexp (point-min) (point)))) (cond ((nth 3 pp) 'string) ;; ((nth 7 pp) 'block-comment) ;; "Stefan Monnier" suggests ;; distinguishing between block comments and ordinary comments ;; is problematic: not what XEmacs claims and different to what ;; (nth 7 pp) tells us in GNU Emacs. ((nth 4 pp) 'comment))))) (defsubst proof-looking-at-syntactic-context-default () "Default function for `proof-looking-at-syntactic-context'." (or (proof-buffer-syntactic-context) (save-match-data (when (proof-looking-at-safe proof-script-comment-start-regexp) 'comment)) (save-match-data (when (proof-looking-at-safe proof-string-start-regexp) 'string)))) (defun proof-looking-at-syntactic-context () "Determine if current point is at beginning or within comment/string context. If so, return a symbol indicating this ('comment or 'string). This function invokes if that is defined, otherwise it calls `proof-looking-at-syntactic-context'." (if (fboundp (proof-ass-sym syntactic-context)) (funcall (proof-ass-sym syntactic-context)) (proof-looking-at-syntactic-context-default))) (defun proof-inside-comment (pos) "Return non-nil if POS is inside a comment." (save-excursion (goto-char pos) (eq (proof-buffer-syntactic-context) 'comment))) (defun proof-inside-string (pos) "Return non-nil if POS is inside a comment." (save-excursion (goto-char pos) (eq (proof-buffer-syntactic-context) 'string))) ;; ;; Replacing matches ;; (defsubst proof-replace-string (string to-string) "Non-interactive `replace-string', using `proof-case-fold-search'." (while (proof-search-forward string nil t) (replace-match to-string nil t))) (defsubst proof-replace-regexp (regexp to-string) "Non-interactive `replace-regexp', using `proof-case-fold-search'." (while (proof-re-search-forward regexp nil t) (replace-match to-string nil nil))) (defsubst proof-replace-regexp-nocasefold (regexp to-string) "Non-interactive `replace-regexp', forcing `case-fold-search' to nil." (let ((case-fold-search nil)) (while (proof-re-search-forward regexp nil t) (replace-match to-string nil nil)))) ;; ;; Generic font-lock ;; (defvar proof-id "\\(\\w\\(\\w\\|\\s_\\)*\\)" "A regular expression for parsing identifiers.") ;; For font-lock, we treat ,-separated identifiers as one identifier ;; and refontify commata using \{proof-zap-commas}. (defun proof-zap-commas (limit) "Remove the face of all `,' from point to LIMIT. Meant to be used from `font-lock-keywords' as a way to unfontify commas in declarations and definitions. Useful for provers which have declarations of the form x,y,z:Ty All that can be said for it is that the previous ways of doing this were even more bogus...." (while (proof-search-forward "," limit t) (if (memq (get-text-property (1- (point)) 'face) '(proof-declaration-name-face font-lock-variable-name-face font-lock-function-name-face)) (put-text-property (1- (point)) (point) 'face nil)))) ;; ;; Font lock: providing an alternative syntactic fontify ;; region function. ;; ;; The hook font-lock-fontify-region-function is tempting but not ;; really a convenient place. We just want to replace the syntactic ;; fontification function. ;; ;; (defadvice font-lock-fontify-keywords-region ;; (before font-lock-fontify-keywords-advice (beg end &optional loudly)) ;; "Call proof assistant specific syntactic region fontify. ;; If it's bound, we call -font-lock-fontify-syntactically-region." ;; (when (and proof-buffer-type ;; (fboundp (proof-ass-sym font-lock-fontify-syntactically-region))) ;; (funcall (proof-ass-sym font-lock-fontify-syntactically-region) ;; beg end loudly))) ;; (ad-activate 'font-lock-fontify-keywords-region) ;; ;; Functions for doing something like "format" but with customizable ;; control characters. ;; ;;;###autoload (defun proof-format (alist string) "Format a string by matching regexps in ALIST against STRING. ALIST contains (REGEXP . REPLACEMENT) pairs where REPLACEMENT may be a string or sexp evaluated to get a string." (while alist (let ((idx 0)) (while (string-match (car (car alist)) string idx) (setq string (concat (substring string 0 (match-beginning 0)) (cond ((stringp (cdr (car alist))) (cdr (car alist))) (t (eval (cdr (car alist))))) (substring string (match-end 0)))) (setq idx (+ (match-beginning 0) (length (cdr (car alist))))))) (setq alist (cdr alist))) string) (defun proof-format-filename (string filename) "Format STRING by replacing quoted chars by escaped version of FILENAME. %e uses the canonicalized expanded version of filename (including directory, using `default-directory' -- see `expand-file-name'). %r uses the unadjusted (possibly relative) version of FILENAME. %m ('module') uses the basename of the file, without directory or extension. %s means the same as %e. Using %e can avoid problems with dumb proof assistants who don't understand ~, for example. For all these cases, the escapes in `proof-shell-filename-escapes' are processed. If STRING is in fact a function, instead invoke it on FILENAME and return the resulting (string) value." (cond ((functionp string) (funcall string filename)) (t (proof-format (list (cons "%s" (proof-format proof-shell-filename-escapes (expand-file-name filename))) (cons "%e" (proof-format proof-shell-filename-escapes (expand-file-name filename))) (cons "%r" (proof-format proof-shell-filename-escapes filename)) (cons "%m" (proof-format proof-shell-filename-escapes (file-name-nondirectory (file-name-sans-extension filename))))) string)))) ;; ;; Functions for inserting text into buffer. ;; ; Taken from Isamode ; ; %l - insert the value of isa-logic-name ; %s - insert the value returned by isa-current-subgoal (defun proof-insert (text) "Insert TEXT into the current buffer. TEXT may include these special characters: %p - place the point here after input Any other %-prefixed character inserts itself." ; would be quite nice to have this function: ;(isa-delete-pending-input) (let ((i 0) pos acc) (while (< i (length text)) (let ((ch (elt text i))) (if (not (eq ch ?%)) (setq acc (concat acc (char-to-string ch))) (setq i (1+ i)) (setq ch (elt text i)) (cond ;((eq ch ?l) ; (setq acc (concat acc isa-logic-name))) ;((eq ch ?s) ; (setq acc ; (concat acc ; (int-to-string ; (if (boundp 'isa-denoted-subgoal) ; isa-denoted-subgoal ; 1))))) ;((eq ch ?n) ; (if acc (insert acc)) ; (setq acc nil) ; (scomint-send-input)) ((eq ch ?p) (if acc (insert acc)) (setq acc nil) (setq pos (point))) (t (setq acc (concat acc (char-to-string ch))))))) (setq i (1+ i))) (if acc (insert acc)) (if pos (goto-char pos)))) (provide 'proof-syntax) ;;; proof-syntax.el ends here