1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
|
;;; easycrypt.el --- Major mode for EasyCrypt
;; --------------------------------------------------------------------
;; Copyright (c) - 2012--2016 - IMDEA Software Institute
;; Copyright (c) - 2012--2016 - Inria
;;
;; Distributed under the terms of the GPL-v3 license
;; --------------------------------------------------------------------
;;; Commentary:
;;
(require 'cl-lib) ;cl-every
(require 'proof)
(require 'easycrypt-syntax)
(require 'easycrypt-hooks)
(require 'easycrypt-abbrev)
;;; Code:
(add-to-list 'hs-special-modes-alist
'(easycrypt-mode "{" "}" "/[*/]" nil nil))
;; --------------------------------------------------------------------
(defun easycrypt-load-path-safep (path)
(and
(listp path)
(cl-every #'stringp path)))
;; --------------------------------------------------------------------
(defcustom easycrypt-prog-name "easycrypt"
"*Name of program to run EasyCrypt."
:type 'file
:group 'easycrypt)
(defcustom easycrypt-load-path nil
"Non-standard EasyCrypt library load path.
This list specifies the include path for EasyCrypt. The elements of
this list are strings."
:type '(repeat (string :tag "simple directory (-I)"))
:safe 'easycrypt-load-path-safep
:group 'easycrypt)
(defcustom easycrypt-web-page
"http://www.easycrypt.info/"
"URL of web page for EasyCrypt."
:type 'string
:group 'easycrypt-config)
;; --------------------------------------------------------------------
(defun easycrypt-option-of-load-path-entry (entry)
(list "-I" (expand-file-name entry)))
;; --------------------------------------------------------------------
(defun easycrypt-include-options ()
(let ((result nil))
(when easycrypt-load-path
(dolist (entry easycrypt-load-path)
(setq result (append result (easycrypt-option-of-load-path-entry entry)))))
result))
;; --------------------------------------------------------------------
(defun easycrypt-build-prog-args ()
(delete "-emacs" easycrypt-prog-args)
(push "-emacs" easycrypt-prog-args))
(easycrypt-build-prog-args)
;; --------------------------------------------------------------------
(defun easycrypt-prog-args ()
(append easycrypt-prog-args (easycrypt-include-options)))
;; --------------------------------------------------------------------
;; Generic mode
(defun easycrypt-config ()
"Configure Proof General scripting for EasyCrypt."
(easycrypt-init-output-syntax-table)
(setq proof-terminal-string easycrypt-terminal-string)
(setq proof-script-command-end-regexp easycrypt-command-end-regexp)
(setq proof-script-comment-start "(*"
proof-script-comment-end "*)")
;; For undo
(setq proof-find-and-forget-fn 'easycrypt-find-and-forget
proof-completed-proof-behaviour nil
proof-non-undoables-regexp easycrypt-non-undoables-regexp
proof-shell-restart-cmd "pragma restart. ")
(set (make-local-variable 'comment-quote-nested) nil)
;; For func-menu and finding goal...save regions
(setq proof-save-command-regexp easycrypt-proof-save-regexp
proof-really-save-command-p 'easycrypt-save-command-p
proof-save-with-hole-regexp nil
proof-goal-command-p 'easycrypt-goal-command-p
proof-goal-with-hole-regexp easycrypt-goal-command-regexp
proof-goal-with-hole-result 1)
(setq proof-goal-command "lemma %s: ."
proof-save-command "qed.")
(setq proof-prog-name easycrypt-prog-name
proof-assistant-home-page easycrypt-web-page)
; Options
(setq proof-three-window-enable t
proof-three-window-mode-policy (quote hybrid)
proof-auto-multiple-files t)
; Setting indents
(set (make-local-variable 'indent-tabs-mode) nil)
(setq proof-indent-enclose-offset (- proof-indent)
proof-indent-open-offset 0
proof-indent-close-offset 0
proof-indent-any-regexp easycrypt-indent-any-regexp
proof-indent-enclose-regexp easycrypt-indent-enclose-regexp
proof-indent-open-regexp easycrypt-indent-open-regexp
proof-indent-close-regexp easycrypt-indent-close-regexp)
; Silent/verbose mode for batch processing
(setq proof-shell-start-silent-cmd "pragma silent. "
proof-shell-stop-silent-cmd "pragma verbose. ")
; Ask for the current goal
(setq proof-showproof-command "pragma noop. ")
(easycrypt-init-syntax-table)
;; we can cope with nested comments
(set (make-local-variable 'comment-quote-nested) nil)
(setq proof-script-font-lock-keywords
easycrypt-font-lock-keywords))
(defun easycrypt-shell-config ()
"Configure Proof General shell for EasyCrypt."
(easycrypt-init-output-syntax-table)
(setq proof-shell-auto-terminate-commands easycrypt-terminal-string)
(setq proof-shell-eager-annotation-start
(concat "\\(?:^\\[W\\] *\\)\\|\\(?:" easycrypt-shell-proof-completed-regexp "\\)"))
(setq proof-shell-strip-crs-from-input nil)
(setq proof-shell-annotated-prompt-regexp "^\\[[0-9]+|\\sw+\\]>")
(setq proof-shell-clear-goals-regexp easycrypt-shell-proof-completed-regexp)
(setq proof-shell-proof-completed-regexp easycrypt-shell-proof-completed-regexp)
(setq proof-shell-error-regexp easycrypt-error-regexp)
(setq proof-shell-truncate-before-error nil)
(setq proof-shell-start-goals-regexp "^Current")
(setq proof-shell-end-goals-regexp nil) ; up to next prompt
(setq proof-shell-font-lock-keywords easycrypt-font-lock-keywords))
;; --------------------------------------------------------------------
;; Derived modes
(define-derived-mode easycrypt-mode proof-mode
"EasyCrypt script" nil
(easycrypt-config)
(proof-config-done))
(define-derived-mode easycrypt-shell-mode proof-shell-mode
"EasyCrypt shell" nil
(easycrypt-shell-config)
(proof-shell-config-done))
(define-derived-mode easycrypt-response-mode proof-response-mode
"EasyCrypt response" nil
(easycrypt-init-output-syntax-table)
(setq proof-response-font-lock-keywords
easycrypt-font-lock-keywords)
(proof-response-config-done))
(define-derived-mode easycrypt-goals-mode proof-goals-mode
"EasyCrypt goals" nil
(easycrypt-init-output-syntax-table)
(setq proof-goals-font-lock-keywords
easycrypt-font-lock-keywords)
(proof-goals-config-done))
(defun easycrypt-get-last-error-location ()
"Remove [error] in the error message and extract the position and
length of the error."
(proof-with-current-buffer-if-exists proof-response-buffer
(goto-char (point-max))
(when (re-search-backward "\\[error-\\([0-9]+\\)-\\([0-9]+\\)\\]" nil t)
(let* ((inhibit-read-only t)
(pos1 (string-to-number (match-string 1)))
(pos2 (string-to-number (match-string 2)))
(len (- pos2 pos1)))
(delete-region (match-beginning 0) (match-end 0))
(list pos1 len)))))
(defun easycrypt-advance-until-command ()
(while (proof-looking-at "\\s-") (forward-char 1)))
(defun easycrypt-highlight-error ()
"Use ‘easycrypt-get-last-error-location’ to know the position of the
error and then highlight in the script buffer."
(proof-with-current-buffer-if-exists proof-script-buffer
(let ((mtch (easycrypt-get-last-error-location)))
(when mtch
(let ((pos (car mtch))
(lgth (cadr mtch)))
(if (eq (proof-unprocessed-begin) (point-min))
(goto-char (proof-unprocessed-begin))
(goto-char (+ (proof-unprocessed-begin) 1)))
(easycrypt-advance-until-command)
(goto-char (+ (point) pos))
(span-make-self-removing-span
(point) (+ (point) lgth)
'face 'proof-script-highlight-error-face))))))
(defun easycrypt-highlight-error-hook ()
(easycrypt-highlight-error))
(defun easycrypt-redisplay-hook ()
(easycrypt-redisplay))
(add-hook 'proof-shell-handle-error-or-interrupt-hook
'easycrypt-highlight-error-hook t)
;; --------------------------------------------------------------------
;; Check mode related commands
(defun easycrypt-cmode-check ()
"Set EasyCrypt in check mode."
(interactive)
(proof-shell-invisible-command "pragma Proofs:check."))
(defun easycrypt-cmode-weak-check ()
"Set EasyCrypt in weak-check mode."
(interactive)
(proof-shell-invisible-command "pragma Proofs:weak."))
;; --------------------------------------------------------------------
(defun easycrypt-ask-do (do)
(let* ((cmd))
(setq cmd (read-string (format "Term for `%s': " do)))
(proof-shell-ready-prover)
(proof-shell-invisible-command (format " %s %s . " do cmd))))
;; --------------------------------------------------------------------
(defun easycrypt-Print ()
"Ask for a term and print its type."
(interactive)
(easycrypt-ask-do "print"))
;; --------------------------------------------------------------------
(defun easycrypt-Check ()
(easycrypt-Print))
;; --------------------------------------------------------------------
;; Key bindings
(define-key easycrypt-keymap "\C-p" 'easycrypt-Print)
(define-key easycrypt-goals-mode-map "\C-c\C-a\C-p" 'easycrypt-Print)
(define-key easycrypt-response-mode-map "\C-c\C-a\C-p" 'easycrypt-Print)
(define-key easycrypt-keymap "\C-c" 'easycrypt-Check)
(define-key easycrypt-goals-mode-map "\C-c\C-a\C-c" 'easycrypt-Check)
(define-key easycrypt-response-mode-map "\C-c\C-a\C-c" 'easycrypt-Check)
;; --------------------------------------------------------------------
;; 3-window pane layout hack
(add-hook
'proof-activate-scripting-hook
'(lambda () (when proof-three-window-enable (proof-layout-windows))))
;; --------------------------------------------------------------------
(provide 'easycrypt)
;;; easycrypt.el ends here
|