aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL56
-rw-r--r--Makefile.devel20
-rw-r--r--coq-syntax.el275
-rw-r--r--coq.el535
-rw-r--r--coqtags56
-rw-r--r--isa-print-functions.ML172
-rw-r--r--isa-syntax.el112
-rw-r--r--isa.el434
-rw-r--r--lego-syntax.el100
-rw-r--r--lego.el469
-rw-r--r--legotags87
-rw-r--r--pbp.el2
-rw-r--r--proof-indent.el124
-rw-r--r--proof-syntax.el146
-rw-r--r--proof.el1818
-rw-r--r--script-management.texinfo440
-rw-r--r--span-extent.el79
-rw-r--r--span-overlay.el288
-rw-r--r--todo175
19 files changed, 5388 insertions, 0 deletions
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..d3ad3e70
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,56 @@
+This file describes what to do to be able to run our script management
+mode for xemacs. Please let us know if you have any problems in
+trying to install it.
+
+Check the values of coq-tags and coq-prog-name in coq.el to see that
+they correspond to the paths for coqtop and the library on your system.
+
+To install, begin by making sure that your load-path has the current
+directory in it by typing:
+ load-path C-j
+in the *scratch* buffer. If it does not, type:
+ (setq load-path (cons "." load-path)) C-j
+again in the *scratch* buffer (or add it to your .emacs file).
+
+Then put the .el files in an appropriate directory and compile them
+using `byte-recompile-file' in xemacs:
+ M-0 M-x byte-recompile-directory
+
+Put the compiled emacs files and the file script-management.info in a
+suitable directory for local emacs files, as suggested by your system
+administrator. Otherwise, if you prefer to keep your own private
+copy, alter the variable coq-info-dir in coq.el to that directory and
+add the line:
+ (setq load-path (cons <directory> load-path))
+to your .emacs file, where <directory> is your local directory.
+
+If you want to use this mode for Coq, you need to make sure you have
+an appropriate version, which is from later than 1 March 1998.
+
+Install coqtags or legotags in a standard place.
+
+If you are running Coq, generate a TAGS file for the library by running
+ coqtags `find . -name \*.v -print`
+in the root directory of the library, $COQTOP/theories. If you are
+running LEGO, do the same using legotags in the appropriate directory.
+
+Finally, you should add the following lines to your .emacs file.
+
+;;; LEGO and Coq
+(setq auto-mode-alist
+ (cons '("\\.v" . coq-mode)
+ (cons '("\\.l$" . lego-mode) auto-mode-alist)))
+
+(autoload 'coq-mode "coq"
+ "Major mode for editing Coq vernacular." t)
+
+(autoload 'lego-mode "lego"
+ "Major mode for editing Lego proof scripts." t)
+
+; Tags is unusable with Coq library otherwise:
+(setq tag-always-exact t)
+
+After this, simply load a LEGO or Coq file and the appropriate mode
+will be run automatically.
+
+Healfdene GOGUEN
diff --git a/Makefile.devel b/Makefile.devel
new file mode 100644
index 00000000..4cda4a31
--- /dev/null
+++ b/Makefile.devel
@@ -0,0 +1,20 @@
+CVSROOT = /home/lego/src
+EXPORTDIR = /home/lego/pub/emacs
+RELEASENAME = emacs-2.0
+TRELEASENAME = $(RELEASENAME).tar
+
+release :
+ cd /tmp; \
+ rm -fr lego;\
+ mkdir lego;\
+ cd lego;\
+ cvs -d $(CVSROOT) export -D today elisp;\
+ cd elisp; \
+ tar cf $(TRELEASENAME) *;\
+ compress -c $(TRELEASENAME) > $(TRELEASENAME).Z;\
+ gzip -c $(TRELEASENAME) > $(TRELEASENAME).gz;\
+ cp -p $(RELEASENAME).* $(EXPORTDIR);\
+ cd ..; cvs release -d elisp
+
+
+
diff --git a/coq-syntax.el b/coq-syntax.el
new file mode 100644
index 00000000..b81a93e8
--- /dev/null
+++ b/coq-syntax.el
@@ -0,0 +1,275 @@
+;; coq-syntax.el Font lock expressions for Coq
+;; Copyright (C) 1997, 1998 LFCS Edinburgh.
+;; Author: Thomas Kleymann and Healfdene Goguen
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+;; $Log$
+;; Revision 2.0 1998/08/11 14:59:53 da
+;; New branch
+;;
+;; Revision 1.2 1998/08/11 11:43:13 da
+;; Renamed <file>-fontlock to <file>-syntax
+;;
+;; Revision 1.14 1998/06/11 12:20:14 hhg
+;; Added "Scheme" as definition keyword.
+;;
+;; Revision 1.13 1998/06/10 11:38:04 hhg
+;; Added "Mutual Inductive" as definition keyword.
+;; Changed "\\s " into "\\s-" as whitespace pattern.
+;;
+;; Revision 1.12 1998/06/03 18:01:54 hhg
+;; Changed Compute from command to tactic.
+;; Added Fix, Destruct and Cofix as tactics.
+;; Added Local as goal.
+;;
+;; Revision 1.11 1998/06/02 15:33:16 hhg
+;; Minor modifications to comments
+;;
+;; Revision 1.10 1998/05/15 16:13:23 hhg
+;; Added CoFixpoint and tactics.
+;; Changed indentation.
+;;
+;; Revision 1.9 1998/05/05 14:19:39 hhg
+;; Added CoInductive.
+;; Made updates to reflect problem with "Definition", which couldn't be
+;; used with proof scripts.
+;;
+;; Revision 1.8 1998/01/15 13:30:17 hhg
+;; Added coq-shell-cd
+;; Some new fontlocks
+;;
+;; Revision 1.7 1997/11/26 17:12:55 hhg
+;; Incorporated tms's suggestion for simplifying coq-font-lock-keywords-1
+;;
+;; Revision 1.6 1997/11/06 16:46:20 hhg
+;; Updates to Coq fontlock tables
+;;
+;; Revision 1.5 1997/10/30 15:58:29 hhg
+;; Updates for coq, including:
+;; * pbp-goal-command and pbp-hyp-command use proof-terminal-string
+;; * updates to keywords
+;; * fix for goal regexp
+;;
+;; Revision 1.4 1997/10/24 14:51:07 hhg
+;; Changed order of "Inversion_clear" and "Inversion" so that former is
+;; fontified first.
+;; Added "Print" to list of commands.
+;;
+;; Revision 1.3 1997/10/17 14:45:53 hhg
+;; Added "Induction" as tactic
+;;
+;; Revision 1.2 1997/10/13 17:10:29 tms
+;; *** empty log message ***
+;;
+;; Revision 1.1.2.2 1997/10/08 08:22:28 hhg
+;; Updated undo, fixed bugs, more modularization
+;;
+;; Revision 1.1.2.1 1997/10/07 13:34:10 hhg
+;; New structure to share as much as possible between LEGO and Coq.
+;;
+;;
+
+(require 'proof-syntax)
+
+;; ----- keywords for font-lock.
+
+(defvar coq-keywords-decl
+ '(
+"Axiom"
+"Hypothesis"
+"Parameter"
+"Variable"
+))
+
+(defvar coq-keywords-defn
+ '(
+"CoFixpoint"
+"CoInductive"
+"Fixpoint"
+"Inductive"
+"Mutual\\s-+Inductive"
+"Scheme"
+))
+
+(defvar coq-keywords-goal
+ '(
+"Definition"
+"Fact"
+"Goal"
+"Lemma"
+"Local"
+"Remark"
+"Theorem"
+))
+
+(defvar coq-keywords-save
+ '(
+"Defined"
+"Save"
+"Qed"
+))
+
+(defvar coq-keywords-kill-goal '(
+"Abort"
+))
+
+(defvar coq-keywords-commands
+ '(
+"AddPath"
+"Cd"
+"Check"
+"Class"
+"Coercion"
+"DelPath"
+"Eval"
+"Extraction"
+"Focus"
+"Immediate"
+"Hint"
+"Infix"
+"Opaque"
+"Print"
+"Proof"
+"Pwd"
+"Reset"
+"Search"
+"Show"
+"Transparent"
+))
+
+(defvar coq-tactics
+ '(
+"Absurd"
+"Apply"
+"Assumption"
+"Auto"
+"Case"
+"Change"
+"Clear"
+"Cofix"
+"Compute"
+"Constructor"
+"Contradiction"
+"Cut"
+"DHyp"
+"DInd"
+"Dependent"
+"Destruct"
+"Discriminate"
+"Double"
+"EApply"
+"EAuto"
+"Elim"
+"End"
+"Exact"
+"Exists"
+"Fix"
+"Generalize"
+"Grammar"
+"Hnf"
+"Induction"
+"Injection"
+"Intro"
+"Intros"
+"Intuition"
+"Inversion_clear"
+"Inversion"
+"LApply"
+"Left"
+"Linear"
+"Load"
+"Pattern"
+"Program_all"
+"Program"
+"Prolog"
+"Realizer"
+"Red"
+"Reflexivity"
+"Replace"
+"Rewrite"
+"Right"
+"Section"
+"Simplify_eq"
+"Simpl"
+"Specialize"
+"Split"
+"Symmetry"
+"Syntax"
+"Tauto"
+"Transitivity"
+"Trivial"
+"Unfold"
+))
+
+(defvar coq-keywords
+ (append coq-keywords-goal coq-keywords-save coq-keywords-decl
+ coq-keywords-defn coq-keywords-commands coq-tactics)
+ "All keywords in a Coq script")
+
+(defvar coq-tacticals '(
+"Do"
+"Idtac"
+"OrElse"
+"Repeat"
+"Try"
+))
+
+;; ----- regular expressions
+(defvar coq-error-regexp "^\\(Error\\|Discarding\\|Syntax error\\|System Error\\)"
+ "A regular expression indicating that the Coq process has identified
+ an error.")
+
+(defvar coq-id proof-id)
+
+(defvar coq-ids (proof-ids coq-id))
+
+(defun coq-abstr-regexp (paren char)
+ (concat paren "\\s-*\\(" coq-ids "\\)\\s-*" char))
+
+(defvar coq-font-lock-terms
+ (list
+
+ ;; lambda binders
+ (list (coq-abstr-regexp "\\[" ":") 1 'font-lock-declaration-name-face)
+
+ ;; Pi binders
+ (list (coq-abstr-regexp "(" ":") 1 'font-lock-declaration-name-face)
+
+ ;; Kinds
+ (cons (concat "\\<Prop\\>\\|\\<Set\\>\\|\\<Type\\s-*\\(("
+ coq-id ")\\)?") 'font-lock-type-face))
+ "*Font-lock table for Coq terms.")
+
+;; According to Coq, "Definition" is both a declaration and a goal.
+;; It is understood here as being a goal. This is important for
+;; recognizing global identifiers, see coq-global-p.
+(defconst coq-save-command-regexp
+ (concat "^" (ids-to-regexp coq-keywords-save)))
+(defconst coq-save-with-hole-regexp
+ (concat "\\(" (ids-to-regexp coq-keywords-save)
+ "\\)\\s-+\\(" coq-id "\\)\\s-*\."))
+(defconst coq-goal-command-regexp
+ (concat "^" (ids-to-regexp coq-keywords-goal)))
+(defconst coq-goal-with-hole-regexp
+ (concat "\\(" (ids-to-regexp coq-keywords-goal)
+ "\\)\\s-+\\(" coq-id "\\)\\s-*:"))
+(defconst coq-decl-with-hole-regexp
+ (concat "\\(" (ids-to-regexp coq-keywords-decl)
+ "\\)\\s-+\\(" coq-ids "\\)\\s-*:"))
+(defconst coq-defn-with-hole-regexp
+ (concat "\\(" (ids-to-regexp coq-keywords-defn)
+ "\\)\\s-+\\(" coq-id "\\)\\s-*[:[]"))
+
+(defvar coq-font-lock-keywords-1
+ (append
+ coq-font-lock-terms
+ (list
+ (cons (ids-to-regexp coq-keywords) 'font-lock-keyword-face)
+ (cons (ids-to-regexp coq-tacticals) 'font-lock-tacticals-name-face)
+
+ (list coq-goal-with-hole-regexp 2 'font-lock-function-name-face)
+ (list coq-decl-with-hole-regexp 2 'font-lock-declaration-name-face)
+ (list coq-defn-with-hole-regexp 2 'font-lock-function-name-face)
+ (list coq-save-with-hole-regexp 2 'font-lock-function-name-face))))
+
+(provide 'coq-syntax)
diff --git a/coq.el b/coq.el
new file mode 100644
index 00000000..b24d4d21
--- /dev/null
+++ b/coq.el
@@ -0,0 +1,535 @@
+;; coq.el Major mode for Coq proof assistant
+;; Copyright (C) 1994, 1995, 1996, 1997 LFCS Edinburgh.
+;; Author: Healfdene Goguen and Thomas Kleymann
+
+;; $Log$
+;; Revision 2.0 1998/08/11 11:39:20 da
+;; Renamed <file>-fontlock to <file>-syntax
+;;
+;; Revision 1.29 1998/06/10 11:42:06 hhg
+;; Added coq-init-syntax-table as function to initialize syntax entries
+;; particular to coq.
+;; Changed proof-ctxt-string to "Print All".
+;; Call coq-init-syntax-table from coq-shell-mode-config. This was
+;; necessary to get prompts with "'"s in them (coming from goals with
+;; same) recognized.
+;;
+;; Revision 1.28 1998/06/03 18:02:54 hhg
+;; Added '?'s before single characters in define-keys for emacs19, at
+;; Pascal Brisset's suggestion.
+;;
+;; Revision 1.27 1998/06/03 13:57:10 hhg
+;; Added definition of proof-commands-regexp for coq
+;;
+;; Revision 1.26 1998/06/02 15:34:43 hhg
+;; Generalized proof-retract-target, now parameterized by
+;; proof-count-undos and proof-find-and-forget.
+;; Generalized proof-shell-analyse-structure, introduced variable
+;; proof-analyse-using-stack.
+;; Generalized proof menu plus ancillary functions.
+;; Generalized proof-mode-version-string.
+;; Moved various comments into documentation string.
+;;
+;; Revision 1.25 1998/05/23 12:50:40 tms
+;; improved support for Info
+;; o employed `Info-default-directory-list' rather than
+;; `Info-directory-list' so that code also works for Emacs 19.34
+;; o setting of `Info-default-directory-list' now at proof level
+;;
+;; Revision 1.24 1998/05/22 11:31:33 hhg
+;; Correct path for coq-prog-name and coq-tags.
+;;
+;; Revision 1.23 1998/05/15 16:16:55 hhg
+;; Changed variable names [s]ext to span.
+;; Fixed coq-find-and-forget pattern for declarations and definitions
+;; following Pascal Brisset's suggestion.
+;;
+;; Revision 1.22 1998/05/14 11:52:32 hhg
+;; Changes to indentation code:
+;; Changed "case" to "Case".
+;; Added "CoInductive".
+;;
+;; Revision 1.21 1998/05/12 14:51:27 hhg
+;; Added hook `coq-shell-init-hook', for `proof-shell-insert-hook'.
+;; This initializes undo limit and changes directory to that associated
+;; with buffer.
+;; This is because Coq has a command line option to run with emacs mode.
+;;
+;; Revision 1.20 1998/05/08 17:08:31 hhg
+;; Made separated indentation more elegant.
+;; Fixed bug with Inductive.
+;; Added CoInductive.
+;;
+;; Revision 1.19 1998/05/08 15:42:42 hhg
+;; Merged indentation code for LEGO and Coq into proof.el.
+;;
+;; Revision 1.18 1998/05/06 16:39:10 hhg
+;; Removed default instantiation of undo limit to 100.
+;;
+;; Revision 1.17 1998/05/06 15:29:11 hhg
+;; Added coq-info-dir so that script-management.info can be hard-coded.
+;;
+;; Revision 1.16 1998/05/05 14:21:48 hhg
+;; Made updates to fix problem with Definition, which couldn't be
+;; used with proof scripts.
+;; Removed some useless declarations.
+;; Removed Abort from menu.
+;; Now Reset's if user undoes to beginning of proof.
+;; Added command to increase undo limit for Coq, and set default to 100.
+;;
+;; Revision 1.15 1998/03/25 17:30:35 tms
+;; added support for etags at generic proof level
+;;
+;; Revision 1.14 1998/01/15 13:30:18 hhg
+;; Added coq-shell-cd
+;; Some new fontlocks
+;;
+;; Revision 1.13 1997/11/26 17:23:51 hhg
+;; Added C-c C-s to run "Search" in Coq.
+;; Moved coq-goal-with-hole-regexp etc to coq-fontlock.
+;; Removed various superfluous definitions for COQPATH etc.
+;;
+;; Revision 1.12 1997/11/24 19:15:08 djs
+;; Added proof-execute-minibuffer-cmd and scripting minor mode.
+;;
+;; Revision 1.11 1997/11/20 13:03:08 hhg
+;; Added coq-global-p for global declarations and definitions. These now
+;; get lifted in the same way as lemmas.
+;; Changed [meta (control i)] to [meta tab] in key definition.
+;; Changed menu, and made help in menu refer to info mode.
+;;
+;; Revision 1.10 1997/11/17 17:11:15 djs
+;; Added some magic commands: proof-frob-locked-end, proof-try-command,
+;; proof-interrupt-process. Added moving nested lemmas above goal for coq.
+;; Changed the key mapping for assert-until-point to C-c RET.
+;;
+;; Revision 1.9 1997/11/12 15:56:15 hhg
+;; Changed pbp-change-goal so that it only "Show"s the goal pointed at.
+;;
+;; Revision 1.8 1997/11/06 16:55:49 hhg
+;; Assign new variable proof-goal-hyp-fn to coq-goal-hyp, which advances
+;; over coq-goal-regexp to pick up goal for pbp
+;;
+;; Revision 1.7 1997/10/30 15:58:31 hhg
+;; Updates for coq, including:
+;; * pbp-goal-command and pbp-hyp-command use proof-terminal-string
+;; * updates to keywords
+;; * fix for goal regexp
+;;
+;; Revision 1.6 1997/10/24 14:51:09 hhg
+;; Fixed coq-count-undos for comments
+;;
+;; Revision 1.5 1997/10/17 14:51:48 hhg
+;; Fixed coq-shell-prompt-pattern to reflect proof-id
+;; Changed ";" to "." in coq-save-with-hole-regexp
+;; New modifications to syntax table to reflect actual use of symbols in Coq
+;;
+;; Revision 1.4 1997/10/16 13:14:32 djs
+;; Merged Coq changes with main branch.
+;;
+;; Revision 1.2 1997/10/13 17:12:48 tms
+;; *** empty log message ***
+;;
+;; Revision 1.1.2.3 1997/10/10 19:19:58 djs
+;; Added multiple file support, changed the way comments work, fixed a
+;; few minor bugs, and merged in coq support by hhg.
+;;
+;; Revision 1.1.2.2 1997/10/08 08:22:30 hhg
+;; Updated undo, fixed bugs, more modularization
+;;
+;; Revision 1.1.2.1 1997/10/07 13:34:16 hhg
+;; New structure to share as much as possible between LEGO and Coq.
+;;
+
+(require 'coq-syntax)
+(require 'outline)
+(require 'proof)
+(require 'info)
+
+; Configuration
+
+(defvar coq-assistant "Coq"
+ "Name of proof assistant")
+
+(defvar coq-tags "/usr/local/lib/coq/theories/TAGS"
+ "the default TAGS table for the Coq library")
+
+(defconst coq-process-config nil
+ "Command to configure pretty printing of the Coq process for emacs.")
+
+(defconst coq-interrupt-regexp "Interrupted"
+ "Regexp corresponding to an interrupt")
+
+(defvar coq-save-query t
+ "*If non-nil, ask user for permission to save the current buffer before
+ processing a module.")
+
+(defvar coq-default-undo-limit 100
+ "Maximum number of Undo's possible when doing a proof.")
+
+;; ----- web documentation
+
+(defvar coq-www-home-page "http://pauillac.inria.fr/coq/")
+
+;; ----- coq-shell configuration options
+
+(defvar coq-prog-name "coqtop -emacs"
+ "*Name of program to run as Coq.")
+
+(defvar coq-shell-working-dir ""
+ "The working directory of the coq shell")
+
+(defvar coq-shell-prompt-pattern (concat "^" proof-id " < ")
+ "*The prompt pattern for the inferior shell running coq.")
+
+(defvar coq-shell-cd nil ; "Cd \"%s\"."
+ "*Command of the inferior process to change the directory.")
+
+(defvar coq-shell-abort-goal-regexp "Current goal aborted"
+ "*Regular expression indicating that the proof of the current goal
+ has been abandoned.")
+
+(defvar coq-shell-proof-completed-regexp "Subtree proved!"
+ "*Regular expression indicating that the proof has been completed.")
+
+(defvar coq-goal-regexp
+ "\\(============================\\)\\|\\(subgoal [0-9]+ is:\\)\n")
+
+;; ----- outline
+
+(defvar coq-outline-regexp
+ (ids-to-regexp
+ '("Section" "Chapter" "Goal" "Lemma" "Theorem" "Fact"
+ "Remark" "Record" "Inductive" "Definition")))
+
+(defvar coq-outline-heading-end-regexp "\.\\|\\*)")
+
+(defvar coq-shell-outline-regexp coq-goal-regexp)
+(defvar coq-shell-outline-heading-end-regexp coq-goal-regexp)
+
+(defconst coq-kill-goal-command "Abort.")
+(defconst coq-forget-id-command "Reset ")
+
+(defconst coq-undoable-commands-regexp (ids-to-regexp coq-tactics))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Derived modes - they're here 'cos they define keymaps 'n stuff ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-derived-mode coq-shell-mode proof-shell-mode
+ "coq-shell" "Inferior shell mode for coq shell"
+ (coq-shell-mode-config))
+
+(define-derived-mode coq-mode proof-mode
+ "coq" "Coq Mode"
+ (coq-mode-config))
+
+(define-derived-mode coq-pbp-mode pbp-mode
+ "pbp" "Proof-by-pointing support for Coq"
+ (coq-pbp-mode-config))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Code that's coq specific ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun coq-shell-init-hook ()
+ (insert (format "Set Undo %s." coq-default-undo-limit))
+ (insert (format "Cd \"%s\"." default-directory))
+ (remove-hook 'proof-shell-insert-hook 'coq-shell-init-hook))
+
+(defun coq-set-undo-limit (undos)
+ (proof-invisible-command (format "Set Undo %s." undos)))
+
+(defun coq-count-undos (span)
+ (let ((ct 0) str i)
+ (if (and span (prev-span span 'type)
+ (not (eq (span-property (prev-span span 'type) 'type) 'comment))
+ (coq-goal-command-p
+ (span-property (prev-span span 'type) 'cmd)))
+ (concat "Restart" proof-terminal-string)
+ (while span
+ (setq str (span-property span 'cmd))
+ (cond ((eq (span-property span 'type) 'vanilla)
+ (if (string-match coq-undoable-commands-regexp str)
+ (setq ct (+ 1 ct))))
+ ((eq (span-property span 'type) 'pbp)
+ (cond ((string-match coq-undoable-commands-regexp str)
+ (setq i 0)
+ (while (< i (length str))
+ (if (= (aref str i) proof-terminal-char)
+ (setq ct (+ 1 ct)))
+ (setq i (+ 1 i))))
+ (t nil))))
+ (setq span (next-span span 'type)))
+ (concat "Undo " (int-to-string ct) proof-terminal-string))))
+
+(defconst coq-keywords-decl-defn-regexp
+ (ids-to-regexp (append coq-keywords-decl coq-keywords-defn))
+ "Declaration and definition regexp.")
+
+(defun coq-goal-command-p (str)
+ "Decide whether argument is a goal or not"
+ (and (string-match coq-goal-command-regexp str)
+ (not (string-match "Definition.*:=" str))))
+
+(defun coq-find-and-forget (span)
+ (let (str ans)
+ (while (and span (not ans))
+ (setq str (span-property span 'cmd))
+ (cond
+
+ ((eq (span-property span 'type) 'comment))
+
+ ((eq (span-property span 'type) 'goalsave)
+ (setq ans (concat coq-forget-id-command
+ (span-property span 'name) proof-terminal-string)))
+
+ ((string-match (concat "\\`\\(" coq-keywords-decl-defn-regexp
+ "\\)\\s-*\\(" proof-id "\\)\\s-*[\\[,:]") str)
+ (setq ans (concat coq-forget-id-command
+ (match-string 2 str) proof-terminal-string)))
+
+ ;; If it's not a goal but it contains "Definition" then it's a
+ ;; declaration
+ ((and (not (coq-goal-command-p str))
+ (string-match
+ (concat "Definition\\s-+\\(" proof-id "\\)\\s-*:") str))
+ (setq ans (concat coq-forget-id-command
+ (match-string 2 str) proof-terminal-string))))
+
+ (setq span (next-span span 'type)))
+
+ (or ans "COMMENT")))
+
+(defvar coq-current-goal 1
+ "Last goal that emacs looked at.")
+
+(defun coq-goal-hyp ()
+ (cond
+ ((looking-at "============================\n")
+ (goto-char (match-end 0))
+ (cons 'goal (int-to-string coq-current-goal)))
+ ((looking-at "subgoal \\([0-9]+\\) is:\n")
+ (goto-char (match-end 0))
+ (cons 'goal (match-string 1))
+ (setq coq-current-goal (string-to-int (match-string 1))))
+ ((looking-at proof-shell-assumption-regexp)
+ (cons 'hyp (match-string 1)))
+ (t nil)))
+
+(defun coq-state-preserving-p (cmd)
+ (not (string-match coq-undoable-commands-regexp cmd)))
+
+(defun coq-global-p (cmd)
+ (or (string-match coq-keywords-decl-defn-regexp cmd)
+ (and (string-match
+ (concat "Definition\\s-+\\(" coq-id "\\)\\s-*:") cmd)
+ (string-match ":=" cmd))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Commands specific to coq ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun coq-Intros ()
+ "List proof state."
+ (interactive)
+ (insert "Intros "))
+
+(defun coq-Apply ()
+ "List proof state."
+ (interactive)
+ (insert "Apply "))
+
+(defun coq-Search ()
+ "Search for type in goals."
+ (interactive)
+ (let (cmd)
+ (proof-check-process-available)
+ (setq cmd (read-string "Search Type: " nil 'proof-minibuffer-history))
+ (proof-invisible-command (concat "Search " cmd proof-terminal-string))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Indentation ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; "Case" is represented by 'c' on the stack, and
+;; "CoInductive is represented by 'C'.
+(defun coq-stack-to-indent (stack)
+ (cond
+ ((null stack) 0)
+ ((null (car (car stack)))
+ (nth 1 (car stack)))
+ (t (let ((col (save-excursion
+ (goto-char (nth 1 (car stack)))
+ (current-column))))
+ (cond
+ ((eq (car (car stack)) ?c)
+ (save-excursion (move-to-column (current-indentation))
+ (cond
+ ((eq (char-after (point)) ?|) (+ col 3))
+ ((looking-at "end") col)
+ (t (+ col 5)))))
+ ((or (eq (car (car stack)) ?I) (eq (car (car stack)) ?C))
+ (+ col (if (eq ?| (save-excursion
+ (move-to-column (current-indentation))
+ (char-after (point)))) 2 4)))
+ (t (1+ col)))))))
+
+(defun coq-parse-indent (c stack)
+ (cond
+ ((eq c ?C)
+ (cond ((looking-at "Case")
+ (cons (list ?c (point)) stack))
+ ((looking-at "CoInductive")
+ (forward-char (length "CoInductive"))
+ (cons (list c (- (point) (length "CoInductive"))) stack))
+ (t stack)))
+ ((and (eq c ?e) (looking-at "end") (eq (car (car stack)) ?c))
+ (cdr stack))
+
+ ((and (eq c ?I) (looking-at "Inductive"))
+ (forward-char (length "Inductive"))
+ (cons (list c (- (point) (length "Inductive"))) stack))
+
+ ((and (eq c ?.) (or (eq (car (car stack)) ?I) (eq (car (car stack)) ?C)))
+ (cdr stack))
+
+ (t stack)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Coq shell startup and exit hooks ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun coq-pre-shell-start ()
+ (setq proof-prog-name coq-prog-name)
+ (setq proof-mode-for-shell 'coq-shell-mode)
+ (setq proof-mode-for-pbp 'coq-pbp-mode)
+)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuring proof and pbp mode and setting up various utilities ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun coq-init-syntax-table ()
+ "Set appropriate values for syntax table in current buffer."
+
+ (modify-syntax-entry ?\$ ".")
+ (modify-syntax-entry ?\/ ".")
+ (modify-syntax-entry ?\\ ".")
+ (modify-syntax-entry ?+ ".")
+ (modify-syntax-entry ?- ".")
+ (modify-syntax-entry ?= ".")
+ (modify-syntax-entry ?% ".")
+ (modify-syntax-entry ?< ".")
+ (modify-syntax-entry ?> ".")
+ (modify-syntax-entry ?\& ".")
+ (modify-syntax-entry ?_ "_")
+ (modify-syntax-entry ?\' "_")
+ (modify-syntax-entry ?\| ".")
+ (modify-syntax-entry ?\* ". 23")
+ (modify-syntax-entry ?\( "()1")
+ (modify-syntax-entry ?\) ")(4"))
+
+(defun coq-mode-config ()
+
+ (setq proof-terminal-char ?\.)
+ (setq proof-comment-start "(*")
+ (setq proof-comment-end "*)")
+
+ (setq proof-assistant coq-assistant
+ proof-www-home-page coq-www-home-page)
+
+ (setq proof-prf-string "Show"
+ proof-ctxt-string "Print All"
+ proof-help-string "Help")
+
+ (setq proof-goal-command-p 'coq-goal-command-p
+ proof-count-undos-fn 'coq-count-undos
+ proof-find-and-forget-fn 'coq-find-and-forget
+ proof-goal-hyp-fn 'coq-goal-hyp
+ proof-state-preserving-p 'coq-state-preserving-p
+ proof-global-p 'coq-global-p
+ proof-parse-indent 'coq-parse-indent
+ proof-stack-to-indent 'coq-stack-to-indent)
+
+ (setq proof-save-command-regexp coq-save-command-regexp
+ proof-save-with-hole-regexp coq-save-with-hole-regexp
+ proof-goal-with-hole-regexp coq-goal-with-hole-regexp
+ proof-kill-goal-command coq-kill-goal-command
+ proof-commands-regexp (ids-to-regexp coq-keywords))
+
+ (coq-init-syntax-table)
+
+;; font-lock
+
+ (setq font-lock-keywords coq-font-lock-keywords-1)
+
+ (proof-config-done)
+
+ (define-key (current-local-map) [(control c) ?I] 'coq-Intros)
+ (define-key (current-local-map) [(control c) ?a] 'coq-Apply)
+ (define-key (current-local-map) [(control c) (control s)] 'coq-Search)
+
+;; outline
+
+ (make-local-variable 'outline-regexp)
+ (setq outline-regexp coq-outline-regexp)
+
+ (make-local-variable 'outline-heading-end-regexp)
+ (setq outline-heading-end-regexp coq-outline-heading-end-regexp)
+
+;; tags
+ (and (boundp 'tag-table-alist)
+ (setq tag-table-alist
+ (append '(("\\.v$" . coq-tags)
+ ("coq" . coq-tags))
+ tag-table-alist)))
+
+ (setq blink-matching-paren-dont-ignore-comments t)
+
+;; hooks and callbacks
+
+ (add-hook 'proof-shell-exit-hook 'coq-zap-line-width nil t)
+ (add-hook 'proof-pre-shell-start-hook 'coq-pre-shell-start nil t))
+
+(defun coq-shell-mode-config ()
+ (setq proof-shell-prompt-pattern coq-shell-prompt-pattern
+ proof-shell-cd coq-shell-cd
+ proof-shell-abort-goal-regexp coq-shell-abort-goal-regexp
+ proof-shell-proof-completed-regexp coq-shell-proof-completed-regexp
+ proof-shell-error-regexp coq-error-regexp
+ proof-shell-interrupt-regexp coq-interrupt-regexp
+ proof-shell-noise-regexp ""
+ proof-shell-assumption-regexp coq-id
+ proof-shell-goal-regexp coq-goal-regexp
+ proof-shell-first-special-char ?\360
+ proof-shell-wakeup-char ?\371 ; done: prompt
+ ; The next three represent path annotation information
+ proof-shell-start-char ?\372 ; not done
+ proof-shell-end-char ?\373 ; not done
+ proof-shell-field-char ?\374 ; not done
+ proof-shell-goal-char ?\375 ; done
+ proof-shell-eager-annotation-start "\376" ; done
+ proof-shell-eager-annotation-end "\377" ; done
+ proof-shell-annotated-prompt-regexp
+ (concat proof-shell-prompt-pattern
+ (char-to-string proof-shell-wakeup-char)) ; done
+ proof-shell-result-start "\372 Pbp result \373"
+ proof-shell-result-end "\372 End Pbp result \373"
+ proof-shell-start-goals-regexp "[0-9]+ subgoals?"
+ proof-shell-end-goals-regexp proof-shell-annotated-prompt-regexp
+ proof-shell-init-cmd nil
+ proof-analyse-using-stack t)
+
+ ;; The following hook is removed once it's called.
+ (add-hook 'proof-shell-insert-hook 'coq-shell-init-hook nil t)
+
+ (coq-init-syntax-table)
+
+ (proof-shell-config-done))
+
+(defun coq-pbp-mode-config ()
+ (setq pbp-change-goal "Show %s.")
+ (setq pbp-error-regexp coq-error-regexp))
+
+(provide 'coq)
diff --git a/coqtags b/coqtags
new file mode 100644
index 00000000..b6c72c78
--- /dev/null
+++ b/coqtags
@@ -0,0 +1,56 @@
+#!/usr/local/bin/perl4
+$/=0777;
+
+if($#ARGV<$[) {die "No Files\n";}
+open(tagfile,">TAGS") || die "Couldn't open TAGS: $!\n";
+
+while(<>)
+{
+ print "Tagging $ARGV\n";
+ $a=$_;
+ $cp=1;
+ $lp=1;
+ $tagstring="";
+
+ while(1)
+ {
+
+# ---- Get the next statement starting on a newline ----
+
+ if($a=~/^[ \t\n]*\(\*/)
+ { while($a=~/^\s*\(\*/)
+ { $d=1; $a=$'; $cp+=length $&; $lp+=($&=~tr/\n/\n/);
+ while($d>0 && $a=~/\(\*|\*\)/)
+ { $a=$'; $cp+=2+length $`; $lp+=($`=~tr/\n/\n/);
+ if($& eq "(*") {$d++} else {$d--};
+ }
+ if($d!=0) {die "Unbalanced Comment?";}
+ }
+ }
+
+ if($cp>1 && $a=~/.*\n/) {$a=$'; $cp+=length $&; $lp++;}
+ while($a=~/^\n/) {$cp++;$lp++;$a=$'}
+
+ if($a=~/^[^\.]*\./)
+ { $stmt=$&; $newa=$'; $newcp=$cp+length $&; $newlp=$lp+($&=~tr/\n/\n/); }
+ else { last;}
+
+# ---- The above embarrasses itself if there are semicolons inside comments
+# ---- inside commands. Could do better.
+
+# print "----- (",$lp,",",$cp,")\n", $stmt, "\n";
+
+ if($stmt=~/^([ \t]*((Fact)|(Goal)|(Lemma)|(Remark)|(Theorem))\s+([\w\']+))\s*:/)
+ { $tagstring.=$1."\177".$8."\001".$lp.",".$cp."\n"; }
+
+ elsif($stmt=~/^([ \t]*((Axiom)|(Hypothesis)|(Parameter)|(Variable))\s+([\w\']+))\s*:/)
+ { $tagstring.=$1."\177".$7."\001".$lp.",".$cp."\n"; }
+
+ elsif($stmt=~/^([ \t]*((Definition)|(Fixpoint)|(Inductive))\s+([\w\']+))\s*[:[]/)
+ { $tagstring.=$1."\177".$6."\001".$lp.",".$cp."\n"; }
+
+ $cp=$newcp; $lp=$newlp; $a=$newa;
+ }
+ print tagfile "\f\n".$ARGV.",".(length $tagstring)."\n".$tagstring;
+}
+close tagfile;
diff --git a/isa-print-functions.ML b/isa-print-functions.ML
new file mode 100644
index 00000000..3af539a5
--- /dev/null
+++ b/isa-print-functions.ML
@@ -0,0 +1,172 @@
+(*
+ isa-print-functions.ML
+
+ Customized version of Isabelle printing for script management
+ mode.
+
+ $Id$
+
+*)
+
+
+
+val proof_state_special_prefix="\248";
+val proof_state_special_suffix="\249";
+val goal_start_special="\253";
+
+
+
+(* val orig_prs_fn = !prs_fn; *)
+(* val orig_warning_fn = !warning_fn; *)
+(* val orig_error_fn = !error_fn; *)
+
+(* copied from Pure/library.ML: *)
+local
+ fun out s =
+ (TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
+
+ fun prefix_lines prfx txt =
+ txt |> split_lines |> map (fn s => prfx ^ s ^ "\n") |> implode;
+in
+
+(*hooks for output channels: normal, warning, error*)
+
+(* da: NO CHANGES NEEDED YET *)
+val () =
+ (prs_fn := (fn s => out s);
+ warning_fn := (fn s => out (prefix_lines "### " s));
+ error_fn := (fn s => out (prefix_lines "*** " s)))
+
+end;
+
+
+
+local
+
+ (* utils *)
+
+ fun ins_entry (x, y) [] = [(x, [y])]
+ | ins_entry (x, y) ((pair as (x', ys')) :: pairs) =
+ if x = x' then (x', y ins ys') :: pairs
+ else pair :: ins_entry (x, y) pairs;
+
+ fun add_consts (Const (c, T), env) = ins_entry (T, (c, T)) env
+ | add_consts (t $ u, env) = add_consts (u, add_consts (t, env))
+ | add_consts (Abs (_, _, t), env) = add_consts (t, env)
+ | add_consts (_, env) = env;
+
+ fun add_vars (Free (x, T), env) = ins_entry (T, (x, ~1)) env
+ | add_vars (Var (xi, T), env) = ins_entry (T, xi) env
+ | add_vars (Abs (_, _, t), env) = add_vars (t, env)
+ | add_vars (t $ u, env) = add_vars (u, add_vars (t, env))
+ | add_vars (_, env) = env;
+
+ fun add_varsT (Type (_, Ts), env) = foldr add_varsT (Ts, env)
+ | add_varsT (TFree (x, S), env) = ins_entry (S, (x, ~1)) env
+ | add_varsT (TVar (xi, S), env) = ins_entry (S, xi) env;
+
+ fun sort_idxs vs = map (apsnd (sort (prod_ord string_ord int_ord))) vs;
+ fun sort_cnsts cs = map (apsnd (sort_wrt fst)) cs;
+
+
+ (* prepare atoms *)
+
+ fun consts_of t = sort_cnsts (add_consts (t, []));
+ fun vars_of t = sort_idxs (add_vars (t, []));
+ fun varsT_of t = rev (sort_idxs (it_term_types add_varsT (t, [])));
+
+in
+
+ fun script_print_goals maxgoals state =
+ let
+ val {sign, ...} = rep_thm state;
+
+ val prt_term = Sign.pretty_term sign;
+ val prt_typ = Sign.pretty_typ sign;
+ val prt_sort = Sign.pretty_sort sign;
+
+ fun prt_atoms prt prtT (X, xs) = Pretty.block
+ [Pretty.block (Pretty.commas (map prt xs)), Pretty.str " ::",
+ Pretty.brk 1, prtT X];
+
+ fun prt_var (x, ~1) = prt_term (Syntax.free x)
+ | prt_var xi = prt_term (Syntax.var xi);
+
+ fun prt_varT (x, ~1) = prt_typ (TFree (x, []))
+ | prt_varT xi = prt_typ (TVar (xi, []));
+
+ val prt_consts = prt_atoms (prt_term o Const) prt_typ;
+ val prt_vars = prt_atoms prt_var prt_typ;
+ val prt_varsT = prt_atoms prt_varT prt_sort;
+
+
+ fun print_list _ _ [] = ()
+ | print_list name prt lst = (writeln "";
+ Pretty.writeln (Pretty.big_list name (map prt lst)));
+
+ fun print_subgoals (_, []) = ()
+ | print_subgoals (n, A :: As) = (Pretty.writeln (Pretty.blk (0,
+ [Pretty.str (goal_start_special ^
+ " " ^ string_of_int n ^ ". "), prt_term A]));
+ print_subgoals (n + 1, As));
+
+ val print_ffpairs =
+ print_list "Flex-flex pairs:" (prt_term o Logic.mk_flexpair);
+
+ val print_consts = print_list "Constants:" prt_consts o consts_of;
+ val print_vars = print_list "Variables:" prt_vars o vars_of;
+ val print_varsT = print_list "Type variables:" prt_varsT o varsT_of;
+
+
+ val {prop, ...} = rep_thm state;
+ val (tpairs, As, B) = Logic.strip_horn prop;
+ val ngoals = length As;
+
+ fun print_gs (types, sorts) =
+ (Pretty.writeln (prt_term B);
+ if ngoals = 0 then writeln "No subgoals!"
+ else if ngoals > maxgoals then
+ (print_subgoals (1, take (maxgoals, As));
+ writeln ("A total of " ^ string_of_int ngoals ^ " subgoals..."))
+ else print_subgoals (1, As);
+
+ print_ffpairs tpairs;
+
+ if types andalso ! show_consts then print_consts prop else ();
+ if types then print_vars prop else ();
+ if sorts then print_varsT prop else ());
+ in
+ setmp show_no_free_types true
+ (setmp show_types (! show_types orelse ! show_sorts)
+ (setmp show_sorts false print_gs))
+ (! show_types orelse ! show_sorts, ! show_sorts)
+ end;
+
+end;
+
+
+
+
+(* Pure/goals.ML declares print_current_goals_fn. *)
+
+val orig_print_current_goals_fn = !print_current_goals_fn;
+
+fun script_mode_print_current_goals_fn n max th =
+ (writeln ("Level " ^ string_of_int n); script_print_goals max th);
+
+local
+ fun out s =
+ (TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
+ fun cgf i j t =
+ (out proof_state_special_prefix;
+ script_mode_print_current_goals_fn i j t;
+ out proof_state_special_suffix)
+in
+ val () = (print_current_goals_fn := cgf)
+end
+
+
+
+
+
+ \ No newline at end of file
diff --git a/isa-syntax.el b/isa-syntax.el
new file mode 100644
index 00000000..2cba6435
--- /dev/null
+++ b/isa-syntax.el
@@ -0,0 +1,112 @@
+;; isa-syntax.el Syntax expressions for Isabelle
+;;
+
+(require 'proof-syntax)
+
+;; ----- keywords for font-lock.
+
+(defvar isa-keywords-decl
+ '(
+))
+
+(defvar isa-keywords-defn
+ '(
+"bind_thm"
+))
+
+(defvar isa-keywords-goal
+ '(
+"goal"
+))
+
+(defvar isa-keywords-save
+ '(
+"qed"
+))
+
+(defvar isa-keywords-kill-goal '(
+))
+
+(defvar isa-keywords-commands
+ '(
+"by"
+"goal"
+))
+
+;; See isa-command-table in Isamode/isa-menus.el to get this list.
+(defvar isa-tactics
+ '(
+"resolve_tac" "assume_tac"
+))
+
+(defvar isa-keywords
+ (append isa-keywords-goal isa-keywords-save isa-keywords-decl
+ isa-keywords-defn isa-keywords-commands isa-tactics)
+ "All keywords in a Isa script")
+
+(defvar isa-tacticals '(
+"REPEAT" "THEN" "ORELSE" "TRY"
+))
+
+;; ----- regular expressions
+
+;; this should come from isa-ml-compiler stuff.
+(defvar isa-error-regexp
+ "^.*Error:"
+ "A regular expression indicating that the Isa process has identified
+ an error.")
+
+(defvar isa-id proof-id)
+
+(defvar isa-ids (proof-ids isa-id))
+
+(defun isa-abstr-regexp (paren char)
+ (concat paren "\\s-*\\(" isa-ids "\\)\\s-*" char))
+
+(defvar isa-font-lock-terms
+ (list
+
+ ;; lambda binders
+ (list (isa-abstr-regexp "\\[" ":") 1 'font-lock-declaration-name-face)
+
+ ;; Pi binders
+ (list (isa-abstr-regexp "(" ":") 1 'font-lock-declaration-name-face)
+
+ ;; Kinds
+ (cons (concat "\\<Prop\\>\\|\\<Set\\>\\|\\<Type\\s-*\\(("
+ isa-id ")\\)?") 'font-lock-type-face))
+ "*Font-lock table for Isa terms.")
+
+;; According to Isa, "Definition" is both a declaration and a goal.
+;; It is understood here as being a goal. This is important for
+;; recognizing global identifiers, see isa-global-p.
+(defconst isa-save-command-regexp
+ (concat "^" (ids-to-regexp isa-keywords-save)))
+(defconst isa-save-with-hole-regexp
+ (concat "\\(" (ids-to-regexp isa-keywords-save)
+ "\\)\\s-+\\(" isa-id "\\)\\s-*\."))
+(defconst isa-goal-command-regexp
+ (concat "^" (ids-to-regexp isa-keywords-goal)))
+(defconst isa-goal-with-hole-regexp
+ (concat "\\(" (ids-to-regexp isa-keywords-goal)
+ "\\)\\s-+\\(" isa-id "\\)\\s-*:"))
+(defconst isa-decl-with-hole-regexp
+ (concat "\\(" (ids-to-regexp isa-keywords-decl)
+ "\\)\\s-+\\(" isa-ids "\\)\\s-*:"))
+(defconst isa-defn-with-hole-regexp
+ (concat "\\(" (ids-to-regexp isa-keywords-defn)
+ "\\)\\s-+\\(" isa-id "\\)\\s-*[:[]"))
+
+(defvar isa-font-lock-keywords-1
+ (append
+ isa-font-lock-terms
+ (list
+ (cons (ids-to-regexp isa-keywords) 'font-lock-keyword-face)
+ (cons (ids-to-regexp isa-tacticals) 'font-lock-tacticals-name-face)
+
+ (list isa-goal-with-hole-regexp 2 'font-lock-function-name-face)
+ (list isa-decl-with-hole-regexp 2 'font-lock-declaration-name-face)
+ (list isa-defn-with-hole-regexp 2 'font-lock-function-name-face)
+ (list isa-save-with-hole-regexp 2 'font-lock-function-name-face))))
+
+(provide 'isa-syntax)
diff --git a/isa.el b/isa.el
new file mode 100644
index 00000000..c750d5b4
--- /dev/null
+++ b/isa.el
@@ -0,0 +1,434 @@
+;; isa.el Major mode for Isabelle proof assistant
+;; Copyright (C) 1994-1998 LFCS Edinburgh.
+;; Author: David Aspinall
+
+;; $Log$
+;; Revision 2.1 1998/08/21 14:37:18 da
+;; First attempt, proof state works.
+;;
+;; Revision 2.0 1998/08/11 14:59:57 da
+;; New branch
+;;
+;; Revision 1.1 1998/08/11 14:43:34 da
+;; Isabelle proof.el support.
+;;
+
+;; STATUS:
+;; - Basic proof state extraction works, using prompt regexp
+;; - Undo needs attention
+
+
+(require 'isa-syntax)
+(require 'outline)
+(require 'proof)
+
+; Configuration
+
+(defvar isa-assistant "Isabelle"
+ "Name of proof assistant")
+
+(defvar isa-tags nil ; "/usr/local/lib/isa/theories/TAGS"
+ "the default TAGS table for the Isa library")
+
+(defconst isa-process-config nil
+ "Command to configure pretty printing of the Isa process for emacs.")
+
+(defconst isa-interrupt-regexp "Interrupt"
+ "Regexp corresponding to an interrupt")
+
+(defvar isa-save-query t
+ "*If non-nil, ask user for permission to save the current buffer before
+ processing a module.")
+
+(defvar isa-default-undo-limit 100
+ "Maximum number of Undo's possible when doing a proof.")
+
+;; ----- web documentation
+
+(defvar isa-www-home-page "http://www.cl.cam.ac.uk/Research/HVG/isabelle.html")
+
+;; ----- isa-shell configuration options
+
+;; FIXME: needs to have special characters for proof.el, also path
+;; name shouldn't be here.
+(defvar isa-prog-name "/usr/lib/Isabelle98/bin/isabelle"
+ "*Name of program to run as Isabelle.")
+
+(defvar isa-shell-working-dir ""
+ "The working directory of the isabelle shell")
+
+(defvar isa-shell-prompt-pattern
+ ;; borrowed from somewhere?
+ ;; "^2?[---=#>]>? *\\|^\\*\\* .*"
+ "^> "
+ "*The prompt pattern for the inferior shell running isabelle.")
+
+(defvar isa-shell-cd "cd \"%s\";"
+ "*Command of the inferior process to change the directory.")
+
+;; FIXME: check this?
+; Don't define this, no correspondence.
+;(defvar isa-shell-abort-goal-regexp nil
+; "*Regular expression indicating that the proof of the current goal
+; has been abandoned.")
+
+(defvar isa-shell-proof-completed-regexp "No subgoals!"
+ "*Regular expression indicating that the proof has been completed.")
+
+(defvar isa-goal-regexp
+ "^[ \t]*[0-9]+\\. "
+ "Regexp to match subgoal heading.")
+
+;; ----- outline
+
+;;; FIXME: BROKEN
+(defvar isa-outline-regexp
+ (ids-to-regexp
+ '("Section" "Chapter" "Goal" "Lemma" "Theorem" "Fact"
+ "Remark" "Record" "Inductive" "Definition")))
+
+(defvar isa-outline-heading-end-regexp "\.\\|\\*)")
+
+(defvar isa-shell-outline-regexp isa-goal-regexp)
+(defvar isa-shell-outline-heading-end-regexp isa-goal-regexp)
+
+;;; ---- end-outline
+
+(defconst isa-kill-goal-command nil) ; "Abort."
+(defconst isa-forget-id-command nil) ; "Reset "
+
+;;; FIXME!!
+(defconst isa-undoable-commands-regexp (ids-to-regexp isa-tactics))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Derived modes - they're here 'cos they define keymaps 'n stuff ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-derived-mode isa-shell-mode proof-shell-mode
+ "isa-shell" "Inferior shell mode for isabelle shell"
+ (isa-shell-mode-config))
+
+(define-derived-mode isa-mode proof-mode
+ "isa" "Isabelle Mode"
+ (isa-mode-config))
+
+(define-derived-mode isa-pbp-mode pbp-mode
+ "pbp" "Proof-by-pointing support for Isabelle"
+ (isa-pbp-mode-config))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Code that's Isabelle specific ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;(defun isa-shell-init-hook ()
+; (remove-hook 'proof-shell-insert-hook 'isa-shell-init-hook))
+
+;(defun isa-set-undo-limit (undos)
+; (proof-invisible-command (format "Set Undo %s." undos)))
+
+(defun isa-count-undos (span)
+ (let ((ct 0) str i)
+ (if (and span (prev-span span 'type)
+ (not (eq (span-property (prev-span span 'type) 'type) 'comment))
+ (isa-goal-command-p
+ (span-property (prev-span span 'type) 'cmd)))
+ (concat "choplev 0" proof-terminal-string)
+ (while span
+ (setq str (span-property span 'cmd))
+ (cond ((eq (span-property span 'type) 'vanilla)
+ (if (string-match isa-undoable-commands-regexp str)
+ (setq ct (+ 1 ct))))
+ ((eq (span-property span 'type) 'pbp)
+ (cond ((string-match isa-undoable-commands-regexp str)
+ (setq i 0)
+ (while (< i (length str))
+ (if (= (aref str i) proof-terminal-char)
+ (setq ct (+ 1 ct)))
+ (setq i (+ 1 i))))
+ (t nil))))
+ (setq span (next-span span 'type)))
+ (concat "choplev " (int-to-string ct) proof-terminal-string))))
+
+(defconst isa-keywords-decl-defn-regexp
+ (ids-to-regexp (append isa-keywords-decl isa-keywords-defn))
+ "Declaration and definition regexp.")
+
+(defun isa-goal-command-p (str)
+ "Decide whether argument is a goal or not"
+ (and (string-match isa-goal-command-regexp str)
+ (not (string-match "Definition.*:=" str))))
+
+(defun isa-find-and-forget (span)
+ (let (str ans)
+ (while (and span (not ans))
+ (setq str (span-property span 'cmd))
+ (cond
+
+ ((eq (span-property span 'type) 'comment))
+
+ ((eq (span-property span 'type) 'goalsave)
+ (setq ans (concat isa-forget-id-command
+ (span-property span 'name) proof-terminal-string)))
+
+ ((string-match (concat "\\`\\(" isa-keywords-decl-defn-regexp
+ "\\)\\s-*\\(" proof-id "\\)\\s-*[\\[,:]") str)
+ (setq ans (concat isa-forget-id-command
+ (match-string 2 str) proof-terminal-string)))
+
+ ;; If it's not a goal but it contains "Definition" then it's a
+ ;; declaration
+ ((and (not (isa-goal-command-p str))
+ (string-match
+ (concat "Definition\\s-+\\(" proof-id "\\)\\s-*:") str))
+ (setq ans (concat isa-forget-id-command
+ (match-string 2 str) proof-terminal-string))))
+
+ (setq span (next-span span 'type)))
+
+ (or ans "COMMENT")))
+
+(defvar isa-current-goal 1
+ "Last goal that emacs looked at.")
+
+(defun isa-goal-hyp ()
+ (cond
+ ((looking-at "============================\n")
+ (goto-char (match-end 0))
+ (cons 'goal (int-to-string isa-current-goal)))
+ ((looking-at "subgoal \\([0-9]+\\) is:\n")
+ (goto-char (match-end 0))
+ (cons 'goal (match-string 1))
+ (setq isa-current-goal (string-to-int (match-string 1))))
+ ((looking-at proof-shell-assumption-regexp)
+ (cons 'hyp (match-string 1)))
+ (t nil)))
+
+(defun isa-state-preserving-p (cmd)
+ (not (string-match isa-undoable-commands-regexp cmd)))
+
+(defun isa-global-p (cmd)
+ (or (string-match isa-keywords-decl-defn-regexp cmd)
+ (and (string-match
+ (concat "Definition\\s-+\\(" isa-id "\\)\\s-*:") cmd)
+ (string-match ":=" cmd))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Commands specific to Isabelle ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun isa-Intros ()
+ "List proof state."
+ (interactive)
+ (insert "printlev"))
+
+(defun isa-Apply ()
+ "List proof state."
+ (interactive)
+ (insert "Apply "))
+
+(defun isa-Search ()
+ "Search for type in goals."
+ (interactive)
+ (let (cmd)
+ (proof-check-process-available)
+ (setq cmd (read-string "Search Type: " nil 'proof-minibuffer-history))
+ (proof-invisible-command (concat "Search " cmd proof-terminal-string))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Indentation ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; "Case" is represented by 'c' on the stack, and
+;; "CoInductive is represented by 'C'.
+(defun isa-stack-to-indent (stack)
+ (cond
+ ((null stack) 0)
+ ((null (car (car stack)))
+ (nth 1 (car stack)))
+ (t (let ((col (save-excursion
+ (goto-char (nth 1 (car stack)))
+ (current-column))))
+ (cond
+ ((eq (car (car stack)) ?c)
+ (save-excursion (move-to-column (current-indentation))
+ (cond
+ ((eq (char-after (point)) ?|) (+ col 3))
+ ((looking-at "end") col)
+ (t (+ col 5)))))
+ ((or (eq (car (car stack)) ?I) (eq (car (car stack)) ?C))
+ (+ col (if (eq ?| (save-excursion
+ (move-to-column (current-indentation))
+ (char-after (point)))) 2 4)))
+ (t (1+ col)))))))
+
+(defun isa-parse-indent (c stack)
+ (cond
+ ((eq c ?C)
+ (cond ((looking-at "Case")
+ (cons (list ?c (point)) stack))
+ ((looking-at "CoInductive")
+ (forward-char (length "CoInductive"))
+ (cons (list c (- (point) (length "CoInductive"))) stack))
+ (t stack)))
+ ((and (eq c ?e) (looking-at "end") (eq (car (car stack)) ?c))
+ (cdr stack))
+
+ ((and (eq c ?I) (looking-at "Inductive"))
+ (forward-char (length "Inductive"))
+ (cons (list c (- (point) (length "Inductive"))) stack))
+
+ ((and (eq c ?.) (or (eq (car (car stack)) ?I) (eq (car (car stack)) ?C)))
+ (cdr stack))
+
+ (t stack)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Isa shell startup and exit hooks ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun isa-pre-shell-start ()
+ (setq proof-prog-name isa-prog-name)
+ (setq proof-mode-for-shell 'isa-shell-mode)
+ (setq proof-mode-for-pbp 'isa-pbp-mode)
+)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuring proof and pbp mode and setting up various utilities ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun isa-init-syntax-table ()
+ "Set appropriate values for syntax table in current buffer."
+
+ (modify-syntax-entry ?\$ ".")
+ (modify-syntax-entry ?\/ ".")
+ (modify-syntax-entry ?\\ ".")
+ (modify-syntax-entry ?+ ".")
+ (modify-syntax-entry ?- ".")
+ (modify-syntax-entry ?= ".")
+ (modify-syntax-entry ?% ".")
+ (modify-syntax-entry ?< ".")
+ (modify-syntax-entry ?> ".")
+ (modify-syntax-entry ?\& ".")
+ (modify-syntax-entry ?_ "_")
+ (modify-syntax-entry ?\' "_")
+ (modify-syntax-entry ?\| ".")
+ (modify-syntax-entry ?\* ". 23")
+ (modify-syntax-entry ?\( "()1")
+ (modify-syntax-entry ?\) ")(4"))
+
+(defun isa-mode-config ()
+
+ (setq proof-terminal-char ?\;)
+ (setq proof-comment-start "(*")
+ (setq proof-comment-end "*)")
+
+ (setq proof-assistant isa-assistant
+ proof-www-home-page isa-www-home-page)
+
+ (setq proof-prf-string "pr()"
+ proof-ctxt-string "print \"No context for Isabelle.\""
+ proof-help-string "print \"No in-built help for Isabelle.\"")
+
+ (setq proof-goal-command-p 'isa-goal-command-p
+ proof-count-undos-fn 'isa-count-undos
+ ;; this one won't be relevant.
+ proof-find-and-forget-fn 'isa-find-and-forget
+ proof-goal-hyp-fn 'isa-goal-hyp
+ proof-state-preserving-p 'isa-state-preserving-p
+ proof-global-p 'isa-global-p
+ proof-parse-indent 'isa-parse-indent
+ proof-stack-to-indent 'isa-stack-to-indent)
+
+ (setq proof-save-command-regexp isa-save-command-regexp
+ proof-save-with-hole-regexp isa-save-with-hole-regexp
+ proof-goal-with-hole-regexp isa-goal-with-hole-regexp
+ proof-kill-goal-command isa-kill-goal-command
+ proof-commands-regexp (ids-to-regexp isa-keywords))
+
+ (isa-init-syntax-table)
+
+;; font-lock
+
+ (setq font-lock-keywords isa-font-lock-keywords-1)
+
+ (proof-config-done)
+
+ (define-key (current-local-map) [(control c) ?I] 'isa-Intros)
+ (define-key (current-local-map) [(control c) ?a] 'isa-Apply)
+ (define-key (current-local-map) [(control c) (control s)] 'isa-Search)
+
+;; outline
+
+ (make-local-variable 'outline-regexp)
+ (setq outline-regexp isa-outline-regexp)
+
+ (make-local-variable 'outline-heading-end-regexp)
+ (setq outline-heading-end-regexp isa-outline-heading-end-regexp)
+
+;; tags
+ (and (boundp 'tag-table-alist)
+ (setq tag-table-alist
+ (append '(("\\.v$" . isa-tags)
+ ("isa" . isa-tags))
+ tag-table-alist)))
+
+ (setq blink-matching-paren-dont-ignore-comments t)
+
+;; hooks and callbacks
+
+ (add-hook 'proof-shell-exit-hook 'isa-zap-line-width nil t)
+ (add-hook 'proof-pre-shell-start-hook 'isa-pre-shell-start nil t))
+
+
+
+(defun isa-shell-mode-config ()
+ (setq proof-shell-prompt-pattern isa-shell-prompt-pattern
+ proof-shell-cd isa-shell-cd
+; this one not set.
+; proof-shell-abort-goal-regexp isa-shell-abort-goal-regexp
+ proof-shell-proof-completed-regexp isa-shell-proof-completed-regexp
+ proof-shell-error-regexp isa-error-regexp
+ proof-shell-interrupt-regexp isa-interrupt-regexp
+ proof-shell-noise-regexp ""
+ proof-shell-assumption-regexp isa-id
+ proof-shell-goal-regexp isa-goal-regexp
+ proof-shell-first-special-char ?\360
+ ; The next three represent path annotation information
+
+ proof-shell-eager-annotation-start "\376"
+ proof-shell-eager-annotation-end "\377"
+ proof-shell-annotated-prompt-regexp proof-shell-prompt-pattern
+ ;(concat proof-shell-prompt-pattern
+ ; (char-to-string proof-shell-wakeup-char))
+ proof-shell-result-start "\372 Pbp result \373"
+ proof-shell-result-end "\372 End Pbp result \373"
+ proof-analyse-using-stack t
+ proof-shell-start-char ?\372 ; not done
+ proof-shell-end-char ?\373 ; not done
+ proof-shell-field-char ?\374 ; not done
+ ;; da: settings below here WORK
+ ;; ============================
+ proof-shell-goal-char ?\375
+ ;; We can't hack the SML prompt, so set wakeup-char to nil.
+ proof-shell-wakeup-char nil
+ proof-shell-start-goals-regexp "\370"
+ proof-shell-end-goals-regexp "\371"
+ ;; initial command configures Isabelle by hacking print functions.
+ ;; may need directory for this: /home/da/devel/lego/elisp/
+ proof-shell-init-cmd
+ "use \"isa-print-functions.ML\";")
+
+
+ ;; The following hook is removed once it's called.
+ ;; FIXME: maybe add this back later.
+ ;;(add-hook 'proof-shell-insert-hook 'isa-shell-init-hook nil t)
+
+ (isa-init-syntax-table)
+
+ (proof-shell-config-done))
+
+(defun isa-pbp-mode-config ()
+ (setq pbp-change-goal "Show %s.")
+ (setq pbp-error-regexp isa-error-regexp))
+
+(provide 'isa)
diff --git a/lego-syntax.el b/lego-syntax.el
new file mode 100644
index 00000000..60ede04f
--- /dev/null
+++ b/lego-syntax.el
@@ -0,0 +1,100 @@
+;; lego-fontlock.el Font lock expressions for LEGO
+;; Copyright (C) 1994, 1995, 1996, 1997 LFCS Edinburgh.
+;; Author: Healfdene Goguen, Thomas Kleymann and Dilip Sequeira
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+(require 'proof-syntax)
+
+;; ----- keywords for font-lock.
+
+(defconst lego-keywords-goal '("$?Goal"))
+
+(defconst lego-keywords-save '("$?Save" "SaveFrozen" "SaveUnfrozen"))
+
+(defconst lego-commands
+ (append lego-keywords-goal lego-keywords-save
+ '("allE" "allI" "andE" "andI" "Assumption" "Claim"
+ "Cut" "Discharge" "DischargeKeep"
+ "echo" "exE" "exI" "Expand" "ExpAll"
+ "ExportState" "Equiv" "For" "Freeze" "Hnf" "Immed"
+ "impE" "impI" "Induction" "Inductive"
+ "Invert" "Init" "intros" "Intros" "Module" "Next"
+ "Normal" "notE" "notI" "orE" "orIL" "orIR" "qnify" "Qnify"
+ "Qrepl" "Record" "Refine" "Repeat" "Try" "Unfreeze"))
+ "Subset of LEGO keywords and tacticals which are terminated by a \?;")
+
+(defconst lego-keywords
+ (append lego-commands
+ '("Constructors" "Double" "ElimOver" "Fields" "Import" "Inversion"
+ "NoReductions" "Parameters" "Relation" "Theorems")))
+
+(defconst lego-tacticals '("Then" "Else" "Try" "Repeat" "For"))
+
+;; ----- regular expressions for font-lock
+(defvar lego-error-regexp "^\\(Error\\|Lego parser\\)"
+ "A regular expression indicating that the LEGO process has
+ identified an error.")
+
+(defvar lego-id proof-id)
+
+(defvar lego-ids (concat lego-id "\\(\\s *,\\s *" lego-id "\\)*")
+ "*For font-lock, we treat \",\" separated identifiers as one identifier
+ and refontify commata using \\{lego-fixup-change}.")
+
+(defconst lego-arg-list-regexp "\\s *\\(\\[[^]]+\\]\\s *\\)*"
+ "Regular expression maching a list of arguments.")
+
+(defun lego-decl-defn-regexp (char)
+ (concat "\\[\\s *\\(" lego-ids "\\)" lego-arg-list-regexp char))
+; Examples
+; ^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
+; [ sort =
+; [ sort [n:nat] =
+; [ sort [abbrev=...][n:nat] =
+
+(defconst lego-definiendum-alternative-regexp
+ (concat "\\(" lego-id "\\)" lego-arg-list-regexp "\\s * ==")
+ "Regular expression where the first match identifies the definiendum.")
+
+(defvar lego-font-lock-terms
+ (list
+
+ ; lambda binders
+ (list (lego-decl-defn-regexp "[:|]") 1
+ 'font-lock-declaration-name-face)
+
+ ; let binders
+ (list lego-definiendum-alternative-regexp 1 'font-lock-function-name-face)
+ (list (lego-decl-defn-regexp "=") 1 'font-lock-function-name-face)
+
+ ; Pi and Sigma binders
+ (list (concat "[{<]\\s *\\(" lego-ids "\\)") 1
+ 'font-lock-declaration-name-face)
+
+ ;; Kinds
+ (cons (concat "\\<Prop\\>\\|\\<Type\\s *\\(("
+ lego-id ")\\)?") 'font-lock-type-face))
+ "*Font-lock table for LEGO terms.")
+
+;; Instead of "[^:]+", it may be better to use "lego-id". Furthermore,
+;; it might be safer to append "\\s-*:".
+(defconst lego-goal-with-hole-regexp
+ (concat "\\(" (ids-to-regexp lego-keywords-goal) "\\)\\s-+\\([^:]+\\)")
+ "Regular expression which matches an entry in `lego-keywords-goal'
+ and the name of the goal.")
+
+(defconst lego-save-with-hole-regexp
+ (concat "\\(" (ids-to-regexp lego-keywords-save) "\\)\\s-+\\([^;]+\\)")
+ "Regular expression which matches an entry in
+ `lego-keywords-save' and the name of the goal.")
+
+(defvar lego-font-lock-keywords-1
+ (append
+ lego-font-lock-terms
+ (list
+ (cons (ids-to-regexp lego-keywords) 'font-lock-keyword-face)
+ (cons (ids-to-regexp lego-tacticals) 'font-lock-tacticals-name-face)
+ (list lego-goal-with-hole-regexp 2 'font-lock-function-name-face)
+ (list lego-save-with-hole-regexp 2 'font-lock-function-name-face))))
+
+(provide 'lego-syntax)
diff --git a/lego.el b/lego.el
new file mode 100644
index 00000000..b8a398e1
--- /dev/null
+++ b/lego.el
@@ -0,0 +1,469 @@
+;; lego.el Major mode for LEGO proof assistants
+;; Copyright (C) 1994 - 1998 LFCS Edinburgh.
+;; Author: Thomas Kleymann and Dilip Sequeira
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+(require 'lego-syntax)
+(require 'outline)
+(require 'proof)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; User Configuration ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; I believe this is standard for Linux under RedHat -tms
+(defvar lego-tags "/usr/lib/lego/lib_Type/"
+ "*the default TAGS table for the LEGO library")
+
+(defvar lego-indent 2 "*Indentation")
+
+(defvar lego-test-all-name "test_all"
+ "*The name of the LEGO module which inherits all other modules of the
+ library.")
+
+(defvar lego-save-query t
+ "*If non-nil, ask user for permission to save the current buffer before
+ processing a module.")
+
+(defvar lego-help-menu-list
+ '(["The LEGO Reference Card" (w3-fetch lego-www-refcard) t]
+ ["The LEGO library (WWW)" (w3-fetch lego-library-www-page) t])
+ "List of menu items, as defined in `easy-menu-define' for LEGO
+ specific help.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Configuration of Generic Proof Package ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Users should not need to change this.
+
+(defvar lego-shell-process-output
+ '((lambda (cmd string) (string-match "^Module" cmd)) .
+ (lambda (cmd string)
+ (setq proof-shell-delayed-output
+ (cons 'insert "Imports done!"))))
+ "Acknowledge end of processing import declarations.")
+
+(defvar lego-assistant "LEGO"
+ "Name of proof assistant")
+
+(defconst lego-process-config "Configure PrettyOn; Configure AnnotateOn;"
+ "Command to enable pretty printing of the LEGO process.")
+
+(defconst lego-pretty-set-width "Configure PrettyWidth %s; "
+ "Command to adjust the linewidth for pretty printing of the LEGO
+ process.")
+
+(defconst lego-interrupt-regexp "Interrupt.."
+ "Regexp corresponding to an interrupt")
+
+(defvar lego-path-name "LEGOPATH"
+ "The name of the environmental variable to search for modules. This
+ is used by \\{legogrep} to find the files corresponding to a
+ search.")
+
+(defvar lego-path-separator ":"
+ "A character indicating how the items in the \\{lego-path-name} are
+ separated.")
+
+
+;; ----- web documentation
+
+(defvar lego-www-home-page "http://www.dcs.ed.ac.uk/home/lego/")
+
+(defvar lego-www-latest-release
+ (concat (w3-remove-file-name lego-www-home-page)
+ "html/release-1.3/")
+ "The WWW address for the latest LEGO release.")
+
+(defvar lego-www-refcard (concat lego-www-latest-release
+ "refcard.ps.gz"))
+
+(defvar lego-library-www-page
+ (concat lego-www-latest-release "library/library.html")
+ "The HTML documentation of the LEGO library.")
+
+;; ----- legostat and legogrep, courtesy of Mark Ruys
+
+(defvar legogrep-command (concat "legogrep -n \"\" " lego-test-all-name)
+ "Last legogrep command used in \\{legogrep}; default for next legogrep.")
+
+(defvar legostat-command "legostat -t")
+
+(defvar legogrep-regexp-alist
+ '(("^\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2 nil ("%s.l")))
+ "Regexp used to match legogrep hits. See `compilation-error-regexp-alist'.")
+
+;; ----- lego-shell configuration options
+
+(defvar lego-prog-name "lego"
+ "*Name of program to run as lego.")
+
+(defvar lego-shell-working-dir ""
+ "The working directory of the lego shell")
+
+(defvar lego-shell-prompt-pattern "^\\(Lego>[ \201]*\\)+"
+ "*The prompt pattern for the inferior shell running lego.")
+
+(defvar lego-shell-cd "Cd \"%s\";"
+ "*Command of the inferior process to change the directory.")
+
+(defvar lego-shell-abort-goal-regexp "KillRef: ok, not in proof state"
+ "*Regular expression indicating that the proof of the current goal
+ has been abandoned.")
+
+(defvar lego-shell-proof-completed-regexp "\\*\\*\\* QED \\*\\*\\*"
+ "*Regular expression indicating that the proof has been completed.")
+
+(defvar lego-save-command-regexp
+ (concat "^" (ids-to-regexp lego-keywords-save)))
+(defvar lego-goal-command-regexp
+ (concat "^" (ids-to-regexp lego-keywords-goal)))
+
+(defvar lego-kill-goal-command "KillRef;")
+(defvar lego-forget-id-command "Forget ")
+
+(defvar lego-undoable-commands-regexp
+ (ids-to-regexp '("Dnf" "Refine" "Intros" "intros" "Next" "Normal"
+ "Qrepl" "Claim" "For" "Repeat" "Succeed" "Fail" "Try" "Assumption"
+ "UTac" "Qnify" "qnify" "andE" "andI" "exE" "exI" "orIL" "orIR" "orE" "ImpI"
+ "impE" "notI" "notE" "allI" "allE" "Expand" "Induction" "Immed"
+ "Invert")) "Undoable list")
+
+;; ----- outline
+
+(defvar lego-goal-regexp "\\?\\([0-9]+\\)")
+
+(defvar lego-outline-regexp
+ (concat "[[*]\\|"
+ (ids-to-regexp
+ '("Discharge" "DischargeKeep" "Freeze" "$?Goal" "Module" "Record" "Inductive"
+ "Unfreeze"))))
+
+(defvar lego-outline-heading-end-regexp ";\\|\\*)")
+
+(defvar lego-shell-outline-regexp lego-goal-regexp)
+(defvar lego-shell-outline-heading-end-regexp lego-goal-regexp)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Derived modes - they're here 'cos they define keymaps 'n stuff ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-derived-mode lego-shell-mode proof-shell-mode
+ "lego-shell" "Inferior shell mode for lego shell"
+ (lego-shell-mode-config))
+
+(define-derived-mode lego-mode proof-mode
+ "lego" "Lego Mode"
+ (lego-mode-config)
+ (easy-menu-change (list proof-mode-name) (car proof-help-menu)
+ (append (cdr proof-help-menu) lego-help-menu-list)))
+
+(define-derived-mode lego-pbp-mode pbp-mode
+ "pbp" "Proof-by-pointing support for LEGO"
+ (lego-pbp-mode-config))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Code that's lego specific ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Martin Steffen <mnsteffe@informatik.uni-erlangen.de> has pointed
+;; out that calling lego-get-path has to deal with a user who hasn't
+;; set the environmental variable LEGOPATH. It is probably best if
+;; lego is installed as a shell script which sets a sensible default
+;; for LEGOPATH if the user hasn't done so before. See the
+;; documentation of the library for further details.
+
+(defun lego-get-path ()
+ (let ((path-name (getenv lego-path-name)))
+ (cond ((not path-name)
+ (message "Warning: LEGOPATH has not been set!")
+ (setq path-name ".")))
+ (proof-string-to-list path-name lego-path-separator)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; This is how to work out what the undo commands are, given the ;;
+;; first span which needs to be undone ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; needs to handle Normal as well
+;; it should ignore Normal TReg Normal VReg and (Normal ...)
+(defun lego-count-undos (span)
+ (let ((ct 0) str i)
+ (while span
+ (setq str (span-property span 'cmd))
+ (cond ((eq (span-property span 'type) 'vanilla)
+ (if (or (string-match lego-undoable-commands-regexp str)
+ (and (string-match "Equiv" str)
+ (not (string-match "Equiv\\s +[TV]Reg" str))))
+ (setq ct (+ 1 ct))))
+ ((eq (span-property span 'type) 'pbp)
+ (setq i 0)
+ (while (< i (length str))
+ (if (= (aref str i) proof-terminal-char) (setq ct (+ 1 ct)))
+ (setq i (+ 1 i)))))
+ (setq span (next-span span 'type)))
+ (concat "Undo " (int-to-string ct) proof-terminal-string)))
+
+(defun lego-goal-command-p (str)
+ "Decide whether argument is a goal or not"
+ (string-match lego-goal-command-regexp str))
+
+(defun lego-find-and-forget (span)
+ (let (str ans)
+ (while (and span (not ans))
+ (setq str (span-property span 'cmd))
+
+ (cond
+
+ ((eq (span-property span 'type) 'comment))
+
+ ((eq (span-property span 'type) 'goalsave)
+ (setq ans (concat lego-forget-id-command
+ (span-property span 'name) proof-terminal-string)))
+
+ ;; alternative definitions
+ ((string-match lego-definiendum-alternative-regexp str)
+ (setq ans (concat lego-forget-id-command (match-string 1 str)
+ proof-terminal-string)))
+ ;; declarations
+ ((string-match (concat "\\`\\$?" (lego-decl-defn-regexp "[:|=]")) str)
+ (let ((ids (match-string 1 str))) ; returns "a,b"
+ (string-match proof-id ids) ; matches "a"
+ (setq ans (concat lego-forget-id-command(match-string 1 ids)
+ proof-terminal-string))))
+
+ ((string-match "\\`\\(Inductive\\|\\Record\\)\\s-*\\[\\s-*\\w+\\s-*:[^;]+\\`Parameters\\s-*\\[\\s-*\\(\\w+\\)\\s-*:" str)
+ (setq ans (concat lego-forget-id-command
+ (match-string 2 str) proof-terminal-string)))
+
+ ((string-match
+ "\\`\\(Inductive\\|Record\\)\\s-*\\[\\s-*\\(\\w+\\)\\s-*:" str)
+ (setq ans
+ (concat lego-forget-id-command (match-string 2 str)
+ proof-terminal-string)))
+
+ ((string-match "\\`\\s-*Module\\s-+\\(\\S-+\\)\\W" str)
+ (setq ans (concat "ForgetMark " (match-string 1 str)
+ proof-terminal-string))))
+
+ (setq span (next-span span 'type)))
+ (or ans
+ "COMMENT")))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Other stuff which is required to customise script management ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun lego-goal-hyp ()
+ (cond
+ ((looking-at proof-shell-goal-regexp)
+ (cons 'goal (match-string 1)))
+ ((looking-at proof-shell-assumption-regexp)
+ (cons 'hyp (match-string 1)))
+ (t nil)))
+
+
+(defun lego-state-preserving-p (cmd)
+ (not (string-match lego-undoable-commands-regexp cmd)))
+
+(defun lego-global-p (cmd)
+ nil)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Commands specific to lego ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun lego-intros ()
+ "intros."
+ (interactive)
+ (insert "intros "))
+
+(defun lego-Intros ()
+ "List proof state."
+ (interactive)
+ (insert "Intros "))
+
+(defun lego-Refine ()
+ "List proof state."
+ (interactive)
+ (insert "Refine "))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lego Indentation ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun lego-stack-to-indent (stack)
+ (cond
+ ((null stack) 0)
+ ((null (car (car stack)))
+ (nth 1 (car stack)))
+ (t (save-excursion
+ (goto-char (nth 1 (car stack)))
+ (+ lego-indent (current-column))))))
+
+(defun lego-parse-indent (c stack)
+ (cond
+ ((eq c ?\{) (cons (list c (point)) stack))
+ ((eq c ?\}) (cdr stack))
+ (t stack)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lego shell startup and exit hooks ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar lego-shell-current-line-width nil
+ "Current line width of the LEGO process's pretty printing module.
+ Its value will be updated whenever the corresponding screen gets
+ selected.")
+
+;; The line width needs to be adjusted if the LEGO process is
+;; running and is out of sync with the screen width
+
+(defun lego-shell-adjust-line-width ()
+ "Uses LEGO's pretty printing facilities to adjust the line width of
+ the output."
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+ (and (proof-shell-live-buffer)
+ (let ((current-width
+ (window-width (get-buffer-window proof-shell-buffer))))
+ (if (equal current-width lego-shell-current-line-width) ()
+ ; else
+ (setq lego-shell-current-line-width current-width)
+ (insert (format lego-pretty-set-width (- current-width 1)))
+ )))))
+
+(defun lego-pre-shell-start ()
+ (setq proof-prog-name lego-prog-name)
+ (setq proof-mode-for-shell 'lego-shell-mode)
+ (setq proof-mode-for-pbp 'lego-pbp-mode))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuring proof and pbp mode and setting up various utilities ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun lego-init-syntax-table ()
+ "Set appropriate values for syntax table in current buffer."
+
+ (modify-syntax-entry ?_ "_")
+ (modify-syntax-entry ?\' "_")
+ (modify-syntax-entry ?\| ".")
+ (modify-syntax-entry ?\* ". 23")
+ (modify-syntax-entry ?\( "()1")
+ (modify-syntax-entry ?\) ")(4"))
+
+(defun lego-mode-config ()
+
+ (setq proof-terminal-char ?\;)
+ (setq proof-comment-start "(*")
+ (setq proof-comment-end "*)")
+
+ (setq proof-assistant lego-assistant
+ proof-www-home-page lego-www-home-page)
+
+ (setq proof-prf-string "Prf"
+ proof-ctxt-string "Ctxt"
+ proof-help-string "Help")
+
+ (setq proof-goal-command-p 'lego-goal-command-p
+ proof-count-undos-fn 'lego-count-undos
+ proof-find-and-forget-fn 'lego-find-and-forget
+ proof-goal-hyp-fn 'lego-goal-hyp
+ proof-state-preserving-p 'lego-state-preserving-p
+ proof-global-p 'lego-global-p
+ proof-parse-indent 'lego-parse-indent
+ proof-stack-to-indent 'lego-stack-to-indent)
+
+ (setq proof-save-command-regexp lego-save-command-regexp
+ proof-save-with-hole-regexp lego-save-with-hole-regexp
+ proof-goal-with-hole-regexp lego-goal-with-hole-regexp
+ proof-kill-goal-command lego-kill-goal-command
+ proof-commands-regexp (ids-to-regexp lego-commands))
+
+ (lego-init-syntax-table)
+
+ (proof-config-done)
+
+ (define-key (current-local-map) [(control c) ?i] 'lego-intros)
+ (define-key (current-local-map) [(control c) ?I] 'lego-Intros)
+ (define-key (current-local-map) [(control c) ?r] 'lego-Refine)
+
+;; outline
+
+ (make-local-variable 'outline-regexp)
+ (setq outline-regexp lego-outline-regexp)
+
+ (make-local-variable 'outline-heading-end-regexp)
+ (setq outline-heading-end-regexp lego-outline-heading-end-regexp)
+
+;; tags
+ (cond ((boundp 'tags-table-list)
+ (make-local-variable 'tags-table-list)
+ (setq tags-table-list (cons lego-tags tags-table-list))))
+
+ (and (boundp 'tag-table-alist)
+ (setq tag-table-alist
+ (append '(("\\.l$" . lego-tags)
+ ("lego" . lego-tags))
+ tag-table-alist)))
+
+ (setq font-lock-keywords lego-font-lock-keywords-1)
+
+;; where to find files
+
+ (setq compilation-search-path (cons nil (lego-get-path)))
+
+ (setq blink-matching-paren-dont-ignore-comments t)
+
+;; font-lock
+
+;; if we don't have the following in xemacs, zap-commas fails to work.
+
+ (and (boundp 'font-lock-always-fontify-immediately)
+ (setq font-lock-always-fontify-immediately t))
+
+;; hooks and callbacks
+
+ (add-hook 'proof-shell-exit-hook 'lego-zap-line-width nil t)
+ (add-hook 'proof-pre-shell-start-hook 'lego-pre-shell-start nil t)
+ (add-hook 'proof-shell-insert-hook 'lego-shell-adjust-line-width))
+
+;; insert standard header and footer in fresh buffers
+
+(defun lego-shell-mode-config ()
+ (setq proof-shell-prompt-pattern lego-shell-prompt-pattern
+ proof-shell-cd lego-shell-cd
+ proof-shell-abort-goal-regexp lego-shell-abort-goal-regexp
+ proof-shell-proof-completed-regexp lego-shell-proof-completed-regexp
+ proof-shell-error-regexp lego-error-regexp
+ proof-shell-interrupt-regexp lego-interrupt-regexp
+ proof-shell-noise-regexp "Discharge\\.\\. "
+ proof-shell-assumption-regexp lego-id
+ proof-shell-goal-regexp lego-goal-regexp
+ proof-shell-first-special-char ?\360
+ proof-shell-wakeup-char ?\371
+ proof-shell-start-char ?\372
+ proof-shell-end-char ?\373
+ proof-shell-field-char ?\374
+ proof-shell-goal-char ?\375
+ proof-shell-eager-annotation-start "\376"
+ proof-shell-eager-annotation-end "\377"
+ proof-shell-annotated-prompt-regexp "Lego> \371"
+ proof-shell-result-start "\372 Pbp result \373"
+ proof-shell-result-end "\372 End Pbp result \373"
+ proof-shell-start-goals-regexp "\372 Start of Goals \373"
+ proof-shell-end-goals-regexp "\372 End of Goals \373"
+ proof-shell-init-cmd lego-process-config
+ proof-analyse-using-stack nil
+ proof-shell-process-output-system-specific lego-shell-process-output
+ lego-shell-current-line-width nil)
+
+ (lego-init-syntax-table)
+
+ (proof-shell-config-done))
+
+(defun lego-pbp-mode-config ()
+ (setq pbp-change-goal "Next %s;")
+ (setq pbp-error-regexp lego-error-regexp))
+
+(provide 'lego)
diff --git a/legotags b/legotags
new file mode 100644
index 00000000..a3c13eab
--- /dev/null
+++ b/legotags
@@ -0,0 +1,87 @@
+#!/usr/local/bin/perl
+
+undef $/;
+
+if($#ARGV<$[) {die "No Files\n";}
+open(tagfile,">TAGS") || die "Couldn't open TAGS: $!\n";
+
+while(<>)
+{
+ print "Tagging $ARGV\n";
+ $a=$_;
+ $cp=1;
+ $lp=1;
+ $tagstring="";
+
+ while(1)
+ {
+
+# ---- Get the next statement starting on a newline ----
+
+ if($a=~/^[ \t\n]*\(\*/)
+ { while($a=~/^\s*\(\*/)
+ { $d=1; $a=$'; $cp+=length $&; $lp+=(($wombat=$&)=~tr/\n/\n/);
+ while($d>0 && $a=~/\(\*|\*\)/)
+ { $a=$'; $cp+=2+length $`; $lp+=(($wombat=$`)=~tr/\n/\n/);
+ if($& eq "(*") {$d++} else {$d--};
+ }
+ if($d!=0) {die "Unbalanced Comment?";}
+ }
+ }
+
+ if($cp>1 && $a=~/.*\n/) {$a=$'; $cp+=length $&; $lp++;}
+ while($a=~/^\n/) {$cp++;$lp++;$a=$'}
+
+ if($a=~/^[^;]*;/)
+ { $stmt=$&;
+ $newa=$';
+ $newcp=$cp+length $&;
+ $newlp=$lp+(($wombat=$&)=~tr/\n/\n/); }
+ else { last;}
+
+# ---- The above embarrasses itself if there are semicolons inside comments
+# ---- inside commands. Could do better.
+
+# print "----- (",$lp,",",$cp,")\n", $stmt, "\n";
+
+ if($stmt=~/^([ \t]*\$?Goal\s*([\w\']+))\s*:/)
+ { $tagstring.=$1."\177".$2."\001".$lp.",".$cp."\n"; }
+
+ elsif($stmt=~/^([ \t]*\$?\[\s*[\w\']+)/)
+ { do adddecs($stmt,$1) }
+
+ elsif($stmt=~/^([ \t]*Inductive\s*\[\s*[\w\']+)/)
+ { do adddecs($stmt,$1) }
+
+# ---- we don't need to tag saves: all goals should be named!
+
+# elsif($stmt=~/([ \t]*\$?Save\s+([\w\']+))/)
+# { $tagstring.=$1."\177".$2."\001".$lp.",".$cp."\n"; }
+#
+# elsif($stmt=~/^([ \t]*\$?SaveUnfrozen\s+([\w\']+))/)
+# { $tagstring.=$1."\177".$2."\001".$lp.",".$cp."\n"; }
+
+# ---- Maybe do something smart with discharge as well?
+
+ $cp=$newcp; $lp=$newlp; $a=$newa;
+ }
+ print tagfile "\f\n".$ARGV.",".(length $tagstring)."\n".$tagstring;
+}
+close tagfile;
+
+
+sub adddecs {
+ $wk=$_[0];
+ $tag=$_[1];
+ while($wk=~/\[\s*([\w\']+)/)
+ { $tagstring.=$tag."\177".$1."\001".$lp.",".$cp."\n"; $wk=$';
+ while($wk=~/^\s*,\s*([\w\']+)/)
+ { $tagstring.=$tag."\177".$1."\001".$lp.",".$cp."\n"; $wk=$'; }
+ $d=1;
+ while($d>0 && $wk=~/\[|\]/)
+ { $wk=$'; if($& eq "[") {$d++} else {$d--};
+ }
+ }
+ 0;
+}
+
diff --git a/pbp.el b/pbp.el
new file mode 100644
index 00000000..23ffdd68
--- /dev/null
+++ b/pbp.el
@@ -0,0 +1,2 @@
+
+(provide 'pbp)
diff --git a/proof-indent.el b/proof-indent.el
new file mode 100644
index 00000000..bb42f462
--- /dev/null
+++ b/proof-indent.el
@@ -0,0 +1,124 @@
+;; proof-indent.el Generic Indentation for Proof Assistants
+;; Copyright (C) 1997, 1998 LFCS Edinburgh
+;; Authors: Healfdene Goguen, Thomas Kleymann and Dilip Sequeira
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+(require 'cl)
+(require 'proof-syntax)
+
+(defvar proof-stack-to-indent nil
+ "Prover-specific code for indentation.")
+
+(defvar proof-parse-indent nil
+ "Proof-assistant specific function for parsing characters for
+ indentation which is invoked in `proof-parse-to-point.'. Must be a
+ function taking two arguments, a character (the current character)
+ and a stack reflecting indentation, and must return a stack. The
+ stack is a list of the form (c . p) where `c' is a character
+ representing the type of indentation and `p' records the column for
+ indentation. The generic `proof-parse-to-point.' function supports
+ parentheses and commands. It represents these with the characters
+ `?\(', `?\[' and `proof-terminal-char'. ")
+
+;; This is quite different from sml-mode, but borrows some bits of
+;; code. It's quite a lot less general, but works with nested
+;; comments.
+
+;; parse-to-point: If from is nil, parsing starts from either
+;; proof-locked-end if we're in the proof-script-buffer or the
+;; beginning of the buffer. Otherwise state must contain a valid
+;; triple.
+
+(defun proof-parse-to-point (&optional from state)
+ (let ((comment-level 0) (stack (list (list nil 0)))
+ (end (point)) instring c)
+ (save-excursion
+ (if (null from)
+ (if (eq proof-script-buffer (current-buffer))
+ (proof-goto-end-of-locked)
+ (goto-char 1))
+ (goto-char from)
+ (setq instring (car state)
+ comment-level (nth 1 state)
+ stack (nth 2 state)))
+ (while (< (point) end)
+ (setq c (char-after (point)))
+ (cond
+ (instring
+ (if (eq c ?\") (setq instring nil)))
+ (t (cond
+ ((eq c ?\()
+ (cond
+ ((looking-at "(\\*")
+ (progn
+ (incf comment-level)
+ (forward-char)))
+ ((eq comment-level 0)
+ (setq stack (cons (list ?\( (point)) stack)))))
+ ((and (eq c ?\*) (looking-at "\\*)"))
+ (decf comment-level)
+ (forward-char))
+ ((> comment-level 0))
+ ((eq c ?\") (setq instring t))
+ ((eq c ?\[)
+ (setq stack (cons (list ?\[ (point)) stack)))
+ ((or (eq c ?\)) (eq c ?\]))
+ (setq stack (cdr stack)))
+ ((looking-at proof-commands-regexp)
+ (setq stack (cons (list proof-terminal-char (point)) stack)))
+ ((and (eq c proof-terminal-char)
+ (eq (car (car stack)) proof-terminal-char)) (cdr stack))
+ (proof-parse-indent
+ (setq stack (funcall proof-parse-indent c stack))))))
+ (forward-char))
+ (list instring comment-level stack))))
+
+(defun proof-indent-line ()
+ (interactive)
+ (if (and (eq proof-script-buffer (current-buffer))
+ (< (point) (proof-locked-end)))
+ (if (< (current-column) (current-indentation))
+ (skip-chars-forward "\t "))
+ (save-excursion
+ (beginning-of-line)
+ (let* ((state (proof-parse-to-point))
+ (beg (point))
+ (indent (cond ((car state) 1)
+ ((> (nth 1 state) 0) 1)
+ (t (funcall proof-stack-to-indent (nth 2 state))))))
+ (skip-chars-forward "\t ")
+ (if (not (eq (current-indentation) indent))
+ (progn (delete-region beg (point))
+ (indent-to indent)))))
+ (skip-chars-forward "\t ")))
+
+(defun proof-indent-region (start end)
+ (interactive "r")
+ (if (and (eq proof-script-buffer (current-buffer))
+ (< (point) (proof-locked-end)))
+ (error "can't indent locked region!"))
+ (save-excursion
+ (goto-char start)
+ (beginning-of-line)
+ (let* ((beg (point))
+ (state (proof-parse-to-point))
+ indent)
+ ;; End of region changes with new indentation
+ (while (< (point) end)
+ (setq indent
+ (cond ((car state) 1)
+ ((> (nth 1 state) 0) 1)
+ (t (funcall proof-stack-to-indent (nth 2 state)))))
+ (skip-chars-forward "\t ")
+ (let ((diff (- (current-indentation) indent)))
+ (if (not (eq diff 0))
+ (progn
+ (delete-region beg (point))
+ (indent-to indent)
+ (setq end (- end diff)))))
+ (end-of-line)
+ (if (< (point) (point-max)) (forward-char))
+ (setq state (proof-parse-to-point beg state)
+ beg (point))))))
+
+(provide 'proof-indent) \ No newline at end of file
diff --git a/proof-syntax.el b/proof-syntax.el
new file mode 100644
index 00000000..45c9015d
--- /dev/null
+++ b/proof-syntax.el
@@ -0,0 +1,146 @@
+;; proof-syntax.el Generic font lock expressions
+;; Copyright (C) 1997 LFCS Edinburgh.
+;; Author: Healfdene Goguen, Thomas Kleymann and Dilip Sequiera
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+;; $Log$
+;; Revision 2.0 1998/08/11 15:00:04 da
+;; New branch
+;;
+;; Revision 1.2 1998/08/11 11:43:14 da
+;; Renamed <file>-fontlock to <file>-syntax
+;;
+;; Revision 1.8 1998/06/10 11:45:12 hhg
+;; Changed "\\s " to "\\s-" in proof-id as whitespace pattern.
+;;
+;; Revision 1.7 1998/05/29 09:49:53 tms
+;; o outsourced indentation to proof-indent
+;; o support indentation of commands
+;; o replaced test of Emacs version with availability test of specific
+;; features
+;; o C-c C-c, C-c C-v and M-tab is now available in all buffers
+;;
+;; Revision 1.6 1998/05/06 15:56:14 hhg
+;; Fixed problem introduced by working on emacs19 in
+;; proof-zap-commas-region.
+;;
+;; Revision 1.5 1998/05/05 14:25:45 hhg
+;; Simple white-space changes.
+;;
+;; Revision 1.4 1998/01/16 15:40:28 djs
+;; Commented the code of proof.el and lego.el a bit. Made a minor change
+;; to the way errors are handled, so that any delayed output is inserted
+;; in the buffer before the error message is printed.
+;;
+;; Revision 1.3 1997/11/17 17:11:19 djs
+;; Added some magic commands: proof-frob-locked-end, proof-try-command,
+;; proof-interrupt-process. Added moving nested lemmas above goal for coq.
+;; Changed the key mapping for assert-until-point to C-c RET.
+;;
+;; Revision 1.2 1997/10/13 17:13:50 tms
+;; *** empty log message ***
+;;
+;; Revision 1.1.2.1 1997/10/07 13:34:27 hhg
+;; New structure to share as much as possible between LEGO and Coq.
+;;
+;;
+
+(require 'font-lock)
+
+;;; FIXME: change this to proof-
+(defun ids-to-regexp (l)
+ "transforms a non-empty list of identifiers `l' into a regular
+ expression matching any of its elements"
+ (mapconcat (lambda (s) (concat "\\<" s "\\>")) l "\\|"))
+
+;; Generic font-lock
+
+;; proof-commands-regexp is used for indentation
+(defvar proof-commands-regexp ""
+ "Subset of keywords and tacticals which are terminated by the
+ `proof-terminal-char'")
+
+
+(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-unfontify-separator}.
+
+(defun proof-ids (proof-id)
+ "Function to generate a regular expression for separated lists of
+ identifiers."
+ (concat proof-id "\\(\\s-*,\\s-*" proof-id "\\)*"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; font lock faces: declarations, errors, tacticals ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun proof-have-color ()
+ ())
+
+(defvar font-lock-declaration-name-face
+(progn
+ (cond
+ ((proof-have-color)
+ (copy-face 'bold 'font-lock-declaration-name-face)
+
+ ;; Emacs 19.28 compiles this down to
+ ;; internal-set-face-1. This is not compatible with XEmacs
+ (set-face-foreground
+ 'font-lock-declaration-name-face "chocolate"))
+ (t (copy-face 'bold-italic 'font-lock-declaration-name-face)))))
+
+;; (if running-emacs19
+;; (setq font-lock-declaration-name-face
+;; (face-name 'font-lock-declaration-name-face))
+
+(defvar font-lock-tacticals-name-face
+(if (proof-have-color)
+ (let ((face (make-face 'font-lock-tacticals-name-face)))
+ (dont-compile
+ (set-face-foreground face "MediumOrchid3"))
+ face)
+ (copy-face 'bold 'font-lock-tacticals-name-face)))
+
+(defvar font-lock-error-face
+(if (proof-have-color)
+ (let ((face (make-face 'font-lock-error-face)))
+ (dont-compile
+ (set-face-foreground face "red"))
+ face)
+ (copy-face 'bold 'font-lock-error-face)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; A big hack to unfontify commas in declarations and definitions. ;;
+;; All that can be said for it is that the previous way of doing ;;
+;; this was even more bogus. ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Refontify the whole line, 'cos that's what font-lock-after-change
+;; does.
+
+(defun proof-zap-commas-region (start end length)
+ (save-excursion
+ (let
+ ((start (progn (goto-char start) (beginning-of-line) (point)))
+ (end (progn (goto-char end) (end-of-line) (point))))
+ (goto-char start)
+ (while (search-forward "," end t)
+ (if (memq (get-char-property (- (point) 1) 'face)
+ '(font-lock-declaration-name-face
+ font-lock-function-name-face))
+ (font-lock-remove-face (- (point) 1) (point))
+ )))))
+
+(defun proof-zap-commas-buffer ()
+ (proof-zap-commas-region (point-min) (point-max) 0))
+
+(defun proof-unfontify-separator ()
+ (make-local-variable 'after-change-functions)
+ (setq after-change-functions
+ (append (delq 'proof-zap-commas-region after-change-functions)
+ '(proof-zap-commas-region))))
+
+
+(provide 'proof-syntax)
diff --git a/proof.el b/proof.el
new file mode 100644
index 00000000..9e6866e8
--- /dev/null
+++ b/proof.el
@@ -0,0 +1,1818 @@
+;; proof.el Major mode for proof assistants
+;; Copyright (C) 1994 - 1998 LFCS Edinburgh.
+;; Authors: David Aspinall, Yves Bertot, Healfdene Goguen,
+;; Thomas Kleymann and Dilip Sequeira
+
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+;; Thanks to Robert Boyer, Rod Burstall,
+;; James McKinna, Mark Ruys, Martin Steffen, Perdita Stevens
+
+
+(require 'cl)
+(require 'compile)
+(require 'comint)
+(require 'etags)
+(cond ((fboundp 'make-extent) (require 'span-extent))
+ ((fboundp 'make-overlay) (require 'span-overlay))
+ (t nil))
+(require 'proof-syntax)
+(require 'proof-indent)
+(require 'easymenu)
+(require 'tl-list)
+
+(autoload 'w3-fetch "w3" nil t)
+
+(defmacro deflocal (var value docstring)
+ (list 'progn
+ (list 'defvar var 'nil docstring)
+ (list 'make-variable-buffer-local (list 'quote var))
+ (list 'setq var value)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst proof-mode-version-string
+ "PROOF-MODE. ALPHA Version 2 (August 1998) LEGO Team <lego@dcs.ed.ac.uk>")
+
+(defvar proof-assistant ""
+ "Name of the proof assistant")
+
+(defvar proof-www-home-page ""
+ "Web address for information on proof assistant")
+
+(defvar proof-shell-cd nil
+ "*Command of the inferior process to change the directory.")
+
+(defconst proof-info-dir "/usr/local/share/info"
+ "Directory to search for Info documents on Script Management.")
+
+(defvar proof-universal-keys
+ (list (cons '[(control c) (control c)] 'proof-interrupt-process)
+ (cons '[(control c) (control v)]
+ 'proof-execute-minibuffer-cmd)
+ (cons '[(meta tab)] 'tag-complete-symbol))
+ "List of keybindings which are valid in both in the script and the
+ response buffer. Elements of the list are tuples (k . f)
+ where `k' is a keybinding (vector) and `f' the designated function.")
+
+(defvar proof-prog-name-ask-p nil
+ "*If t, you will be asked which program to run when the inferior
+ process starts up.")
+
+(defvar proof-shell-process-output-system-specific nil
+ "*Errors, start of proofs, abortions of proofs and completions of
+ proofs are recognised in the function `proof-shell-process-output'.
+ All other output from the proof engine is simply reported to the
+ user in the RESPONSE buffer.
+
+ To catch further special cases, set this variable to a tuple of
+ functions '(condf . actf). Both are given (cmd string) as arguments.
+ `cmd' is a string containing the currently processed command.
+ `string' is the response from the proof system. To change the
+ behaviour of `proof-shell-process-output', (condf cmd string) must
+ return a non-nil value. Then (actf cmd string) is invoked. See the
+ documentation of `proof-shell-process-output' for the required
+ output format.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Other buffer-local variables used by proof mode ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; These should be set before proof-config-done is called
+
+(defvar proof-terminal-char nil "terminator character")
+
+(defvar proof-comment-start nil "Comment start")
+(defvar proof-comment-end nil "Comment end")
+
+(defvar proof-save-command-regexp nil "Matches a save command")
+(defvar proof-save-with-hole-regexp nil "Matches a named save command")
+(defvar proof-goal-with-hole-regexp nil "Matches a saved goal command")
+
+(defvar proof-goal-command-p nil "Is this a goal")
+(defvar proof-count-undos-fn nil "Compute number of undos in a target segment")
+(defvar proof-find-and-forget-fn nil "Compute command to forget up to point")
+(defvar proof-goal-hyp-fn nil "Is point at goal or hypothesis")
+(defvar proof-kill-goal-command nil "How to kill a goal.")
+(defvar proof-global-p nil "Is this a global declaration")
+
+(defvar proof-state-preserving-p nil
+ "whether a command preserves the proof state")
+
+(defvar pbp-change-goal nil
+ "*Command to change to the goal %s")
+
+;; these should be set in proof-pre-shell-start-hook
+
+(defvar proof-prog-name nil "program name for proof shell")
+(defvar proof-mode-for-shell nil "mode for proof shell")
+(defvar proof-mode-for-pbp nil "The actual mode for Proof-by-Pointing.")
+(defvar proof-shell-insert-hook nil
+ "Function to config proof-system to interface")
+
+(defvar proof-pre-shell-start-hook)
+(defvar proof-post-shell-exit-hook)
+
+(defvar proof-shell-prompt-pattern nil
+ "comint-prompt-pattern for proof shell")
+
+(defvar proof-shell-init-cmd nil
+ "The command for initially configuring the proof process")
+
+(defvar proof-shell-handle-delayed-output-hook
+ '(proof-pbp-focus-on-first-goal)
+ "*This hook is called after output from the PROOF process has been
+ displayed in the RESPONSE buffer.")
+
+(defvar proof-shell-handle-error-hook
+ '(proof-goto-end-of-locked-if-pos-not-visible-in-window)
+ "*This hook is called after an error has been reported in the
+ RESPONSE buffer.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Generic config for script management ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar proof-shell-wakeup-char nil
+ "A character terminating the prompt in annotation mode")
+
+(defvar proof-shell-annotated-prompt-regexp ""
+ "Annotated prompt pattern")
+
+(defvar proof-shell-abort-goal-regexp nil
+ "*Regular expression indicating that the proof of the current goal
+ has been abandoned.")
+
+(defvar proof-shell-error-regexp nil
+ "A regular expression indicating that the PROOF process has
+ identified an error.")
+
+(defvar proof-shell-interrupt-regexp nil
+ "A regular expression indicating that the PROOF process has
+ responded to an interrupt.")
+
+(defvar proof-shell-proof-completed-regexp nil
+ "*Regular expression indicating that the proof has been completed.")
+
+(defvar proof-shell-result-start ""
+ "String indicating the start of an output from the prover following
+ a `pbp-goal-command' or a `pbp-hyp-command'.")
+
+(defvar proof-shell-result-end ""
+ "String indicating the end of an output from the prover following a
+ `pbp-goal-command' or a `pbp-hyp-command'.")
+
+(defvar proof-shell-start-goals-regexp ""
+ "String indicating the start of the proof state.")
+
+(defvar proof-shell-end-goals-regexp ""
+ "String indicating the end of the proof state.")
+
+(defvar pbp-error-regexp nil
+ "A regular expression indicating that the PROOF process has
+ identified an error.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Internal variables used by scripting and pbp ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar proof-mode-name "Proof")
+
+(defvar proof-shell-echo-input t
+ "If nil, input to the proof shell will not be echoed")
+
+(defvar proof-terminal-string nil
+ "End-of-line string for proof process.")
+
+(defvar proof-re-end-of-cmd nil
+ "You are not authorised for this information.")
+
+(defvar proof-re-term-or-comment nil
+ "You are not authorised for this information.")
+
+(defvar proof-marker nil
+ "You are not authorised for this information.")
+
+(defvar proof-shell-buffer nil
+ "You are not authorised for this information.")
+
+(defvar proof-script-buffer nil
+ "You are not authorised for this information.")
+
+(defvar proof-pbp-buffer nil
+ "You are not authorised for this information.")
+
+(defvar proof-shell-busy nil
+ "You are not authorised for this information.")
+
+(deflocal proof-buffer-type nil
+ "You are not authorised for this information.")
+
+(defvar proof-action-list nil "action list")
+
+(defvar proof-included-files-list nil
+ "Files currently included in proof process")
+
+(deflocal proof-active-buffer-fake-minor-mode nil
+ "An indication in the modeline that this is the *active* buffer")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; A couple of small utilities ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun proof-define-keys (map kbl)
+ "Adds keybindings `kbl' in `map'. The argument `kbl' is a list of
+ tuples (k . f) where `k' is a keybinding (vector) and `f' the
+ designated function."
+ (mapcar
+ (lambda (kbl)
+ (let ((k (car kbl)) (f (cdr kbl)))
+ (define-key map k f)))
+ kbl))
+
+(defun proof-string-to-list (s separator)
+ "converts strings `s' separated by the character `separator' to a
+ list of words"
+ (let ((end-of-word-occurence (string-match (concat separator "+") s)))
+ (if (not end-of-word-occurence)
+ (if (string= s "")
+ nil
+ (list s))
+ (cons (substring s 0 end-of-word-occurence)
+ (proof-string-to-list
+ (substring s
+ (string-match (concat "[^" separator "]")
+ s end-of-word-occurence)) separator)))))
+
+(defun w3-remove-file-name (address)
+ "remove the file name in a World Wide Web address"
+ (string-match "://[^/]+/" address)
+ (concat (substring address 0 (match-end 0))
+ (file-name-directory (substring address (match-end 0)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Basic code for the locked region and the queue region ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar proof-locked-hwm nil
+ "Upper limit of the locked region")
+
+(defvar proof-queue-loose-end nil
+ "Limit of the queue region that is not equal to proof-locked-hwm.")
+
+(defvar proof-locked-span nil
+ "Upper limit of the locked region")
+
+(defvar proof-queue-span nil
+ "Upper limit of the locked region")
+
+(make-variable-buffer-local 'proof-locked-span)
+(make-variable-buffer-local 'proof-queue-span)
+
+(defun proof-init-segmentation ()
+ (setq proof-queue-loose-end nil)
+ (if (not proof-queue-span)
+ (setq proof-queue-span (make-span 1 1)))
+ (set-span-property proof-queue-span 'start-closed t)
+ (set-span-property proof-queue-span 'end-open t)
+ (span-read-only proof-queue-span)
+
+ (make-face 'proof-queue-face)
+ ;; Whether display has color or not
+ (cond ((and (fboundp 'device-class)
+ (eq (device-class (frame-device)) 'color))
+ (set-face-background 'proof-queue-face "mistyrose"))
+ ((and (fboundp 'x-display-color-p) (x-display-color-p))
+ (set-face-background 'proof-queue-face "mistyrose"))
+ (t (progn
+ (set-face-background 'proof-queue-face "Black")
+ (set-face-foreground 'proof-queue-face "White"))))
+ (set-span-property proof-queue-span 'face 'proof-queue-face)
+
+ (detach-span proof-queue-span)
+
+ (setq proof-locked-hwm nil)
+ (if (not proof-locked-span)
+ (setq proof-locked-span (make-span 1 1)))
+ (set-span-property proof-locked-span 'start-closed t)
+ (set-span-property proof-locked-span 'end-open t)
+ (span-read-only proof-locked-span)
+
+ (make-face 'proof-locked-face)
+ ;; Whether display has color or not
+ (cond ((and (fboundp 'device-class)
+ (eq (device-class (frame-device)) 'color))
+ (set-face-background 'proof-locked-face "lavender"))
+ ((and (fboundp 'x-display-color-p) (x-display-color-p))
+ (set-face-background 'proof-locked-face "lavender"))
+ (t (set-face-property 'proof-locked-face 'underline t)))
+ (set-span-property proof-locked-span 'face 'proof-locked-face)
+
+ (detach-span proof-locked-span))
+
+(defsubst proof-lock-unlocked ()
+ (span-read-only proof-locked-span))
+
+(defsubst proof-unlock-locked ()
+ (span-read-write proof-locked-span))
+
+(defsubst proof-set-queue-endpoints (start end)
+ (set-span-endpoints proof-queue-span start end))
+
+(defsubst proof-set-locked-endpoints (start end)
+ (set-span-endpoints proof-locked-span start end))
+
+(defsubst proof-detach-queue ()
+ (and proof-queue-span (detach-span proof-queue-span)))
+
+(defsubst proof-detach-locked ()
+ (and proof-locked-span (detach-span proof-locked-span)))
+
+(defsubst proof-set-queue-start (start)
+ (set-span-endpoints proof-queue-span start (span-end proof-queue-span)))
+
+(defsubst proof-set-queue-end (end)
+ (set-span-endpoints proof-queue-span (span-start proof-queue-span) end))
+
+(defun proof-detach-segments ()
+ (proof-detach-queue)
+ (proof-detach-locked))
+
+(defsubst proof-set-locked-end (end)
+ (if (>= (point-min) end)
+ (proof-detach-locked)
+ (set-span-endpoints proof-locked-span (point-min) end)))
+
+(defun proof-unprocessed-begin ()
+ "proof-unprocessed-begin returns end of locked region in script
+ buffer and point-min otherwise."
+ (or
+ (and (eq proof-script-buffer (current-buffer))
+ proof-locked-span (span-end proof-locked-span))
+ (point-min)))
+
+(defun proof-locked-end ()
+ "proof-locked-end returns the end of the locked region. It should
+ only be called if we're in the scripting buffer."
+ (if (eq proof-script-buffer (current-buffer))
+ (proof-unprocessed-begin)
+ (error "bug: proof-locked-end called from wrong buffer")))
+
+(defsubst proof-end-of-queue ()
+ (and proof-queue-span (span-end proof-queue-span)))
+
+(defun proof-dont-show-annotations ()
+ "This sets the display values of the annotations used to
+ communicate with the proof assistant so that they don't show up on
+ the screen."
+ (let ((disp (make-display-table))
+ (i 128))
+ (while (< i 256)
+ (aset disp i [])
+ (incf i))
+ (cond ((fboundp 'add-spec-to-specifier)
+ (add-spec-to-specifier current-display-table disp
+ (current-buffer)))
+ ((boundp 'buffer-display-table)
+ (setq buffer-display-table disp)))))
+
+;;; in case Emacs is not aware of read-shell-command-map
+
+(defvar read-shell-command-map
+ (let ((map (make-sparse-keymap)))
+ (if (not (fboundp 'set-keymap-parents))
+ (setq map (append minibuffer-local-map map))
+ (set-keymap-parents map minibuffer-local-map)
+ (set-keymap-name map 'read-shell-command-map))
+ (define-key map "\t" 'comint-dynamic-complete)
+ (define-key map "\M-\t" 'comint-dynamic-complete)
+ (define-key map "\M-?" 'comint-dynamic-list-completions)
+ map)
+ "Minibuffer keymap used by shell-command and related commands.")
+
+
+;;; in case Emacs is not aware of the function read-shell-command
+(or (fboundp 'read-shell-command)
+ ;; from minibuf.el distributed with XEmacs 19.11
+ (defun read-shell-command (prompt &optional initial-input history)
+ "Just like read-string, but uses read-shell-command-map:
+\\{read-shell-command-map}"
+ (let ((minibuffer-completion-table nil))
+ (read-from-minibuffer prompt initial-input read-shell-command-map
+ nil (or history
+ 'shell-command-history)))))
+
+;; The package fume-func provides a function with the same name and
+;; specification. However, fume-func's version is incorrect.
+(and (fboundp 'fume-match-find-next-function-name)
+(defun fume-match-find-next-function-name (buffer)
+ "General next function name in BUFFER finder using match.
+ The regexp is assumed to be a two item list the car of which is the regexp
+ to use, and the cdr of which is the match position of the function name"
+ (set-buffer buffer)
+ (let ((r (car fume-function-name-regexp))
+ (p (cdr fume-function-name-regexp)))
+ (and (re-search-forward r nil t)
+ (cons (buffer-substring (setq p (match-beginning p)) (point)) p)))))
+
+(defun proof-goto-end-of-locked-interactive ()
+ "Jump to the end of the locked region."
+ (interactive)
+ (switch-to-buffer proof-script-buffer)
+ (goto-char (proof-locked-end)))
+
+(defun proof-goto-end-of-locked ()
+ "Jump to the end of the locked region."
+ (goto-char (proof-locked-end)))
+
+(defun proof-goto-end-of-locked-if-pos-not-visible-in-window ()
+ "If the end of the locked region is not visible, jump to the end of
+ the locked region."
+ (interactive)
+ (let ((pos (save-excursion
+ (set-buffer proof-script-buffer)
+ (proof-locked-end))))
+ (or (pos-visible-in-window-p pos (get-buffer-window
+ proof-script-buffer t))
+ (proof-goto-end-of-locked-interactive))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Starting and stopping the proof-system shell ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun proof-shell-live-buffer ()
+ (and proof-shell-buffer
+ (comint-check-proc proof-shell-buffer)
+ proof-shell-buffer))
+
+(defun proof-start-shell ()
+ (if (proof-shell-live-buffer)
+ ()
+ (run-hooks 'proof-pre-shell-start-hook)
+ (setq proof-included-files-list nil)
+ (if proof-prog-name-ask-p
+ (save-excursion
+ (setq proof-prog-name (read-shell-command "Run process: "
+ proof-prog-name))))
+ (let ((proc
+ (concat "Inferior "
+ (substring proof-prog-name
+ (string-match "[^/]*$" proof-prog-name)))))
+ (while (get-buffer (concat "*" proc "*"))
+ (if (string= (substring proc -1) ">")
+ (aset proc (- (length proc) 2)
+ (+ 1 (aref proc (- (length proc) 2))))
+ (setq proc (concat proc "<2>"))))
+
+ (message (format "Starting %s process..." proc))
+
+ ;; Starting the inferior process (asynchronous)
+ (let ((prog-name-list (proof-string-to-list proof-prog-name " ")))
+ (apply 'make-comint (append (list proc (car prog-name-list) nil)
+ (cdr prog-name-list))))
+ ;; To send any initialisation commands to the inferior process,
+ ;; consult proof-shell-config-done...
+
+ (setq proof-shell-buffer (get-buffer (concat "*" proc "*")))
+ (setq proof-pbp-buffer (get-buffer-create (concat "*" proc "-goals*")))
+
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+ (funcall proof-mode-for-shell)
+ (set-buffer proof-pbp-buffer)
+ (funcall proof-mode-for-pbp))
+
+ (setq proof-script-buffer (current-buffer))
+ (proof-init-segmentation)
+ (setq proof-active-buffer-fake-minor-mode t)
+
+ (if (fboundp 'redraw-modeline)
+ (redraw-modeline)
+ (force-mode-line-update))
+
+ (or (assq 'proof-active-buffer-fake-minor-mode minor-mode-alist)
+ (setq minor-mode-alist
+ (append minor-mode-alist
+ (list '(proof-active-buffer-fake-minor-mode
+ " Scripting")))))
+
+ (message
+ (format "Starting %s process... done." proc)))))
+
+
+(defun proof-stop-shell ()
+ "Exit the PROOF process
+
+ Runs proof-shell-exit-hook if non nil"
+
+ (interactive)
+ (save-excursion
+ (let ((buffer (proof-shell-live-buffer)) (proc))
+ (if buffer
+ (progn
+ (save-excursion
+ (set-buffer buffer)
+ (setq proc (process-name (get-buffer-process)))
+ (comint-send-eof)
+ (save-excursion
+ (set-buffer proof-script-buffer)
+ (proof-detach-segments))
+ (kill-buffer))
+ (run-hooks 'proof-shell-exit-hook)
+
+ ;;it is important that the hooks are
+ ;;run after the buffer has been killed. In the reverse
+ ;;order e.g., intall-shell-fonts causes problems and it
+ ;;is impossible to restart the PROOF shell
+
+ (message (format "%s process terminated." proc)))))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Proof by pointing ;;
+;; All very lego-specific at present ;;
+;; To make sense of this code, you should read the ;;
+;; relevant LFCS tech report by tms, yb, and djs ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defvar pbp-goal-command nil
+ "Command informing the prover that `pbp-button-action' has been
+ requested on a goal.")
+
+(defvar pbp-hyp-command nil
+ "Command informing the prover that `pbp-button-action' has been
+ requested on an assumption.")
+
+(defun pbp-button-action (event)
+ (interactive "e")
+ (mouse-set-point event)
+ (pbp-construct-command))
+
+; Using the spans in a mouse behavior is quite simple: from the
+; mouse position, find the relevant span, then get its annotation
+; and produce a piece of text that will be inserted in the right
+; buffer.
+
+(defun proof-expand-path (string)
+ (let ((a 0) (l (length string)) ls)
+ (while (< a l)
+ (setq ls (cons (int-to-string (aref string a))
+ (cons " " ls)))
+ (incf a))
+ (apply 'concat (nreverse ls))))
+
+(defun proof-send-span (event)
+ (interactive "e")
+ (let* ((span (span-at (mouse-set-point event) 'type))
+ (str (span-property span 'cmd)))
+ (cond ((and (eq proof-script-buffer (current-buffer)) (not (null span)))
+ (proof-goto-end-of-locked)
+ (cond ((eq (span-property span 'type) 'vanilla)
+ (insert str)))))))
+
+(defun pbp-construct-command ()
+ (let* ((span (span-at (point) 'proof))
+ (top-span (span-at (point) 'proof-top-element))
+ top-info)
+ (if (null top-span) ()
+ (setq top-info (span-property top-span 'proof-top-element))
+ (pop-to-buffer proof-script-buffer)
+ (cond
+ (span
+ (proof-invisible-command
+ (format (if (eq 'hyp (car top-info)) pbp-hyp-command
+ pbp-goal-command)
+ (concat (cdr top-info) (proof-expand-path
+ (span-property span 'proof))))))
+ ((eq (car top-info) 'hyp)
+ (proof-invisible-command (format pbp-hyp-command (cdr top-info))))
+ (t
+ (proof-insert-pbp-command (format pbp-change-goal (cdr top-info))))))
+ ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Turning annotated output into pbp goal set ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar proof-shell-first-special-char nil "where the specials start")
+(defvar proof-shell-goal-char nil "goal mark")
+(defvar proof-shell-start-char nil "annotation start")
+(defvar proof-shell-end-char nil "annotation end")
+(defvar proof-shell-field-char nil "annotated field end")
+(defvar proof-shell-eager-annotation-start nil "eager ann. field start")
+(defvar proof-shell-eager-annotation-end nil "eager ann. field end")
+
+(defvar proof-shell-assumption-regexp nil
+ "A regular expression matching the name of assumptions.")
+
+;; FIXME: da: where is this variable used?
+;; dropped in favour of goal-char?
+(defvar proof-shell-goal-regexp nil
+ "A regular expressin matching the identifier of a goal.")
+
+(defvar proof-shell-noise-regexp nil
+ "Unwanted information output from the proof process within
+ `proof-start-goals-regexp' and `proof-end-goals-regexp'.")
+
+(defun pbp-make-top-span (start end)
+ (let (span name)
+ (goto-char start)
+ (setq name (funcall proof-goal-hyp-fn))
+ (beginning-of-line)
+ (setq start (point))
+ (goto-char end)
+ (beginning-of-line)
+ (backward-char)
+ (setq span (make-span start (point)))
+ (set-span-property span 'mouse-face 'highlight)
+ (set-span-property span 'proof-top-element name)))
+
+
+;; Need this for processing error strings and so forth
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; The filter. First some functions that handle those few ;;
+;; occasions when the glorious illusion that is script-management ;;
+;; is temporarily suspended ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Output from the proof process is handled lazily, so that only
+;; the output from the last of multiple commands is actually
+;; processed (assuming they're all successful)
+
+(defvar proof-shell-delayed-output nil
+ "The last interesting output the proof process output, and what to do
+ with it.")
+
+(defvar proof-analyse-using-stack nil
+ "Are annotations sent by proof assistant local or global")
+
+;; FIXME: da: what's magical value 128 below? should be in defconst?
+(defun proof-shell-analyse-structure (string)
+ (save-excursion
+ (let* ((ip 0) (op 0) ap (l (length string))
+ (ann (make-string (length string) ?x))
+ (stack ()) (topl ())
+ (out (make-string l ?x)) c span)
+ (while (< ip l)
+ (if (< (setq c (aref string ip)) 128)
+ (progn (aset out op c)
+ (incf op)))
+ (incf ip))
+ (display-buffer (set-buffer proof-pbp-buffer))
+ (erase-buffer)
+ (insert (substring out 0 op))
+
+ (setq ip 0
+ op 1)
+ (while (< ip l)
+ (setq c (aref string ip))
+ (cond
+ ((= c proof-shell-goal-char)
+ (setq topl (cons op topl))
+ (setq ap 0))
+ ((= c proof-shell-start-char)
+ (if proof-analyse-using-stack
+ (setq ap (- ap (- (aref string (incf ip)) 128)))
+ (setq ap (- (aref string (incf ip)) 128)))
+ (incf ip)
+ (while (not (= (setq c (aref string ip)) proof-shell-end-char))
+ (aset ann ap (- c 128))
+ (incf ap)
+ (incf ip))
+ (setq stack (cons op (cons (substring ann 0 ap) stack))))
+ ((= c proof-shell-field-char)
+ (setq span (make-span (car stack) op))
+ (set-span-property span 'mouse-face 'highlight)
+ (set-span-property span 'proof (car (cdr stack)))
+ ;; Pop annotation off stack
+ (and proof-analyse-using-stack
+ (progn
+ (setq ap 0)
+ (while (< ap (length (cadr stack)))
+ (aset ann ap (aref (cadr stack) ap))
+ (incf ap))))
+ ;; Finish popping annotations
+ (setq stack (cdr (cdr stack))))
+ (t (incf op)))
+ (incf ip))
+ (setq topl (reverse (cons (point-max) topl)))
+ ;; If we want Coq pbp: (setq coq-current-goal 1)
+ (while (setq ip (car topl)
+ topl (cdr topl))
+ (pbp-make-top-span ip (car topl))))))
+
+(defun proof-shell-strip-annotations (string)
+ (let* ((ip 0) (op 0) (l (length string)) (out (make-string l ?x )))
+ (while (< ip l)
+ (if (>= (aref string ip) proof-shell-first-special-char)
+ (if (char-equal (aref string ip) proof-shell-start-char)
+ (progn (incf ip)
+ (while (< (aref string ip) proof-shell-first-special-char)
+ (incf ip))))
+ (aset out op (aref string ip))
+ (incf op))
+ (incf ip))
+ (substring out 0 op)))
+
+(defun proof-shell-handle-delayed-output ()
+ (let ((ins (car proof-shell-delayed-output))
+ (str (cdr proof-shell-delayed-output)))
+ (display-buffer proof-pbp-buffer)
+ (save-excursion
+ (cond
+ ((eq ins 'insert)
+ (setq str (proof-shell-strip-annotations str))
+ (set-buffer proof-pbp-buffer)
+ (erase-buffer)
+ (insert str))
+ ((eq ins 'analyse)
+ (proof-shell-analyse-structure str))
+ (t (set-buffer proof-pbp-buffer)
+ (insert "\n\nbug???")))))
+ (run-hooks 'proof-shell-handle-delayed-output-hook)
+ (setq proof-shell-delayed-output (cons 'insert "done")))
+
+(defun proof-shell-handle-error (cmd string)
+ (save-excursion
+ (display-buffer (set-buffer proof-pbp-buffer))
+ (if (not (eq proof-shell-delayed-output (cons 'insert "done")))
+ (progn
+ (set-buffer proof-pbp-buffer)
+ (erase-buffer)
+ (insert (proof-shell-strip-annotations
+ (cdr proof-shell-delayed-output)))))
+ (goto-char (point-max))
+ (if (re-search-backward pbp-error-regexp nil t)
+ (delete-region (- (point) 2) (point-max)))
+ (newline 2)
+ (insert-string string)
+ (beep))
+ (set-buffer proof-script-buffer)
+ (proof-detach-queue)
+ (delete-spans (proof-locked-end) (point-max) 'type)
+ (proof-release-lock)
+ (run-hooks 'proof-shell-handle-error-hook))
+
+(defun proof-shell-handle-interrupt ()
+ (save-excursion
+ (display-buffer (set-buffer proof-pbp-buffer))
+ (goto-char (point-max))
+ (newline 2)
+ (insert-string
+ "Interrupt: Script Management may be in an inconsistent state\n")
+ (beep))
+ (set-buffer proof-script-buffer)
+ (if proof-shell-busy
+ (progn (proof-detach-queue)
+ (delete-spans (proof-locked-end) (point-max) 'type)
+ (proof-release-lock))))
+
+
+(defun proof-goals-pos (span maparg)
+ "Given a span, this function returns the start of it if corresponds
+ to a goal and nil otherwise."
+ (and (eq 'goal (car (span-property span 'proof-top-element)))
+ (span-start span)))
+
+(defun proof-pbp-focus-on-first-goal ()
+ "If the `proof-pbp-buffer' contains goals, the first one is brought
+ into view."
+ (and (fboundp 'map-extents)
+ (let
+ ((pos (map-extents 'proof-goals-pos proof-pbp-buffer
+ nil nil nil nil 'proof-top-element)))
+ (and pos (set-window-point
+ (get-buffer-window proof-pbp-buffer t) pos)))))
+
+
+
+(defun proof-shell-process-output (cmd string)
+ "Deals with errors, start of proofs, abortions of proofs and
+ completions of proofs. All other output from the proof engine is
+ simply reported to the user in the RESPONSE buffer. To extend this
+ function, set `proof-shell-process-output-system-specific'.
+
+ The basic output processing function - it can return one of 4
+ things: 'error, 'interrupt, 'loopback, or nil. 'loopback means this
+ was output from pbp, and should be inserted into the script buffer
+ and sent back to the proof assistant."
+ (cond
+ ((string-match proof-shell-error-regexp string)
+ (cons 'error (proof-shell-strip-annotations
+ (substring string (match-beginning 0)))))
+
+ ((string-match proof-shell-interrupt-regexp string)
+ 'interrupt)
+
+ ((and proof-shell-abort-goal-regexp
+ (string-match proof-shell-abort-goal-regexp string))
+ (setq proof-shell-delayed-output (cons 'insert "\n\nAborted"))
+ ())
+
+ ((string-match proof-shell-proof-completed-regexp string)
+ (setq proof-shell-delayed-output
+ (cons 'insert (concat "\n" (match-string 0 string)))))
+
+ ((string-match proof-shell-start-goals-regexp string)
+ (let (start end)
+ (while (progn (setq start (match-end 0))
+ (string-match proof-shell-start-goals-regexp
+ string start)))
+ (setq end (string-match proof-shell-end-goals-regexp string start))
+ (setq proof-shell-delayed-output
+ (cons 'analyse (substring string start end)))))
+
+ ((string-match proof-shell-result-start string)
+ (let (start end)
+ (setq start (+ 1 (match-end 0)))
+ (string-match proof-shell-result-end string)
+ (setq end (- (match-beginning 0) 1))
+ (cons 'loopback (substring string start end))))
+
+ ;; hook to tailor proof-shell-process-output to a specific proof
+ ;; system
+ ((and proof-shell-process-output-system-specific
+ (funcall (car proof-shell-process-output-system-specific)
+ cmd string))
+ (funcall (cdr proof-shell-process-output-system-specific)
+ cmd string))
+
+ (t (setq proof-shell-delayed-output (cons 'insert string)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Low-level commands for shell communication ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun proof-shell-insert (string)
+ (set-buffer proof-shell-buffer)
+ (goto-char (point-max))
+
+ (run-hooks 'proof-shell-insert-hook)
+ (insert string)
+
+ ;; xemacs and emacs19 have different semantics for what happens when
+ ;; shell input is sent next to a marker
+ ;; the following code accommodates both definitions
+ (if (marker-position proof-marker)
+ (let ((inserted (point)))
+ (comint-send-input)
+ (set-marker proof-marker inserted))
+ (comint-send-input)))
+
+(defun proof-send (string)
+ (let ((l (length string)) (i 0))
+ (while (< i l)
+ (if (= (aref string i) ?\n) (aset string i ?\ ))
+ (incf i)))
+ (save-excursion (proof-shell-insert string)))
+
+;; Note that this is not really intended for anything complicated -
+;; just to stop the user accidentally sending a command while the
+;; queue is running.
+(defun proof-check-process-available (&optional relaxed)
+ "Checks
+ (1) Is a proof process running?
+ (2) Is the proof process idle?
+ (3) Does the current buffer own the proof process?
+ (4) Is the current buffer a proof script?
+ and signals an error if at least one of the conditions is not
+ fulfilled. If relaxed is set, only (1) and (2) are tested."
+ (if (proof-shell-live-buffer)
+ (cond
+ (proof-shell-busy (error "Proof Process Busy!"))
+ (relaxed ()) ;exit cond
+ ((not (eq proof-script-buffer (current-buffer)))
+ (error "Don't own proof process"))))
+ (if (not (or relaxed (eq proof-buffer-type 'script)))
+ (error "Must be running in a script buffer")))
+
+(defun proof-grab-lock (&optional relaxed)
+ (proof-start-shell)
+ (proof-check-process-available relaxed)
+ (setq proof-shell-busy t))
+
+(defun proof-release-lock ()
+ (if (proof-shell-live-buffer)
+ (progn
+ (if (not proof-shell-busy)
+ (error "Bug: Proof process not busy"))
+ (if (not (eq proof-script-buffer (current-buffer)))
+ (error "Bug: Don't own process"))
+ (setq proof-shell-busy nil))))
+
+; Pass start and end as nil if the cmd isn't in the buffer.
+
+(defun proof-start-queue (start end alist &optional relaxed)
+ (if start
+ (proof-set-queue-endpoints start end))
+ (let (item)
+ (while (and alist (string=
+ (nth 1 (setq item (car alist)))
+ "COMMENT"))
+ (funcall (nth 2 item) (car item))
+ (setq alist (cdr alist)))
+ (if alist
+ (progn
+ (proof-grab-lock relaxed)
+ (setq proof-shell-delayed-output (cons 'insert "Done."))
+ (setq proof-action-list alist)
+ (proof-send (nth 1 item))))))
+
+; returns t if it's run out of input
+
+(defun proof-shell-exec-loop ()
+ (save-excursion
+ (set-buffer proof-script-buffer)
+ (if (null proof-action-list) (error "Non Sequitur"))
+ (let ((item (car proof-action-list)))
+ (funcall (nth 2 item) (car item))
+ (setq proof-action-list (cdr proof-action-list))
+ (while (and proof-action-list
+ (string=
+ (nth 1 (setq item (car proof-action-list)))
+ "COMMENT"))
+ (funcall (nth 2 item) (car item))
+ (setq proof-action-list (cdr proof-action-list)))
+ (if (null proof-action-list)
+ (progn (proof-release-lock)
+ (proof-detach-queue)
+ t)
+ (proof-send (nth 1 item))
+ nil))))
+
+(defun proof-shell-insert-loopback-cmd (cmd)
+ "Insert command sequence triggered by the proof process
+at the end of locked region (after inserting a newline and indenting)."
+ (save-excursion
+ (set-buffer proof-script-buffer)
+ (let (span)
+ (proof-goto-end-of-locked)
+ (newline-and-indent)
+ (insert cmd)
+ (setq span (make-span (proof-locked-end) (point)))
+ (set-span-property span 'type 'pbp)
+ (set-span-property span 'cmd cmd)
+ (proof-set-queue-endpoints (proof-locked-end) (point))
+ (setq proof-action-list
+ (cons (car proof-action-list)
+ (cons (list span cmd 'proof-done-advancing)
+ (cdr proof-action-list)))))))
+
+;; ******** NB **********
+;; While we're using pty communication, this code is OK, since all
+;; eager annotations are one line long, and we get input a line at a
+;; time. If we go over to piped communication, it will break.
+
+(defun proof-shell-popup-eager-annotation ()
+ "Eager annotations are annotations which the proof system produces
+while it's doing something (e.g. loading libraries) to say how much
+progress it's made. Obviously we need to display these as soon as they
+arrive."
+ (let (mrk str file module)
+ (save-excursion
+ (goto-char (point-max))
+ (search-backward proof-shell-eager-annotation-start)
+ (setq mrk (+ 1 (point)))
+ (search-forward proof-shell-eager-annotation-end)
+ (setq str (buffer-substring mrk (- (point) 1)))
+ (display-buffer (set-buffer proof-pbp-buffer))
+ (goto-char (point-max))
+ (insert str "\n"))
+ (if (string-match "Creating mark \"\\(.*\\)\" \\[\\(.*\\)\\]" str)
+ (progn
+ (setq file (match-string 2 str)
+ module (match-string 1 str))
+ (if (string= file "")
+ (setq file (buffer-file-name proof-script-buffer)))
+ (setq file (expand-file-name file))
+ (if (string-match "\\(.*\\)\\.." file)
+ (setq file (match-string 1 file)))
+ (setq proof-included-files-list (cons (cons module file)
+ proof-included-files-list))))))
+
+(defun proof-shell-filter (str)
+ "The filter for the shell-process. We sleep until we get a
+ wakeup-char in the input, then run proof-shell-process-output, and
+ set proof-marker to keep track of how far we've got."
+ (if (string-match proof-shell-eager-annotation-end str)
+ (proof-shell-popup-eager-annotation))
+ (if (or
+ ;; Some proof systems can be hacked to have annotated prompts;
+ ;; for these we set proof-shell-wakeup-char to the annotation special.
+ (and proof-shell-wakeup-char
+ (string-match (char-to-string proof-shell-wakeup-char) str))
+ ;; Others rely on a standard top-level (e.g. SML) whose prompt can't
+ ;; be hacked. For those we use the prompt regexp.
+ (string-match proof-shell-annotated-prompt-regexp str))
+ (if (null (marker-position proof-marker))
+ ;; Set marker to first prompt in output buffer, and sleep again.
+ (progn
+ (goto-char (point-min))
+ (re-search-forward proof-shell-annotated-prompt-regexp)
+ ;; FIXME: da: why is this next line here? to delete the
+ ;; possibly several character prompt? why?
+ ;; TMS: Its purpose is to remove the wakeup
+ ;; character associated with the prompt. This
+ ;; should not be necessary anymore, because the wakeup
+ ;; character isn't displayed anyway; see
+ ;; `proof-dont-show-annotations'. Watch this space!
+ (backward-delete-char 1)
+ (set-marker proof-marker (point)))
+ ;; We've matched against a second prompt in str now. Search
+ ;; the output buffer for the second prompt after the one previously
+ ;; marked.
+ (let (string res cmd)
+ (goto-char (marker-position proof-marker))
+ (re-search-forward proof-shell-annotated-prompt-regexp nil t)
+ (backward-char (- (match-end 0) (match-beginning 0)))
+ (setq string (buffer-substring (marker-position proof-marker)
+ (point)))
+ (goto-char (point-max)) ; da: assumed to be after a prompt?
+ (backward-delete-char 1) ; da: WHY? nasty assumption.
+ (setq cmd (nth 1 (car proof-action-list)))
+ (save-excursion
+ (setq res (proof-shell-process-output cmd string))
+ (cond
+ ((and (consp res) (eq (car res) 'error))
+ (proof-shell-handle-error cmd (cdr res)))
+ ((eq res 'interrupt)
+ (proof-shell-handle-interrupt))
+ ((and (consp res) (eq (car res) 'loopback))
+ (proof-shell-insert-loopback-cmd (cdr res))
+ (proof-shell-exec-loop))
+ (t (if (proof-shell-exec-loop)
+ (proof-shell-handle-delayed-output)))))))))
+
+(defun proof-last-goal-or-goalsave ()
+ (save-excursion
+ (let ((span (span-at-before (proof-locked-end) 'type)))
+ (while (and span
+ (not (eq (span-property span 'type) 'goalsave))
+ (or (eq (span-property span 'type) 'comment)
+ (not (funcall proof-goal-command-p
+ (span-property span 'cmd)))))
+ (setq span (prev-span span 'type)))
+ span)))
+
+;; This needs some work to make it generic, since most of the code
+;; doesn't apply to Coq at all.
+(defun proof-steal-process ()
+ "This allows us to steal the process if we want to change the buffer
+ in which script management is running."
+ (proof-start-shell)
+ (if proof-shell-busy (error "Proof Process Busy!"))
+ (if (not (eq proof-buffer-type 'script))
+ (error "Must be running in a script buffer"))
+ (cond
+ ((eq proof-script-buffer (current-buffer))
+ nil)
+ (t
+ (let ((flist proof-included-files-list)
+ (file (expand-file-name (buffer-file-name))) span (cmd ""))
+ (if (string-match "\\(.*\\)\\.." file) (setq file (match-string 1 file)))
+ (while (and flist (not (string= file (cdr (car flist)))))
+ (setq flist (cdr flist)))
+ (if (null flist)
+ (if (not (y-or-n-p "Steal script management? " )) (error "Aborted"))
+ (if (not (y-or-n-p "Reprocess this file? " )) (error "Aborted")))
+ (if (not (buffer-name proof-script-buffer))
+ (message "Warning: Proof script buffer deleted: proof state may be inconsistent")
+ (save-excursion
+ (set-buffer proof-script-buffer)
+ (setq proof-active-buffer-fake-minor-mode nil)
+ (setq span (proof-last-goal-or-goalsave))
+ ;; This won't work for Coq if we have recursive goals in progress
+ (if (and span (not (eq (span-property span 'type) 'goalsave)))
+ (setq cmd proof-kill-goal-command))
+ (proof-detach-segments)
+ (delete-spans (point-min) (point-max) 'type)))
+
+ (setq proof-script-buffer (current-buffer))
+ (proof-init-segmentation)
+ (setq proof-active-buffer-fake-minor-mode t)
+
+ (cond
+ (flist
+ (list nil (concat cmd "ForgetMark " (car (car flist)) ";")
+ `(lambda (span) (setq proof-included-files-list
+ (quote ,(cdr flist))))))
+ ((not (string= cmd ""))
+ (list nil cmd 'proof-done-invisible))
+ (t nil))))))
+
+(defun proof-done-invisible (span) ())
+
+(defun proof-invisible-command (cmd &optional relaxed)
+ "Send cmd to the proof process without responding to the user."
+ (proof-check-process-available relaxed)
+ (if (not (string-match proof-re-end-of-cmd cmd))
+ (setq cmd (concat cmd proof-terminal-string)))
+ (proof-start-queue nil nil (list (list nil cmd
+ 'proof-done-invisible)) relaxed))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; User Commands ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Script management uses two major segments: Locked, which marks text
+; which has been sent to the proof assistant and cannot be altered
+; without being retracted, and Queue, which contains stuff being
+; queued for processing. proof-action-list contains a list of
+; (span,command,action) triples. The loop looks like: Execute the
+; command, and if it's successful, do action on span. If the
+; command's not successful, we bounce the rest of the queue and do
+; some error processing.
+;
+; when a span has been processed, we classify it as follows:
+; 'goalsave - denoting a 'goalsave pair in the locked region
+; a 'goalsave region has a 'name property which is the name of the goal
+; 'comment - denoting a comment
+; 'pbp - denoting a span created by pbp
+; 'vanilla - denoting any other span.
+; 'pbp & 'vanilla spans have a property 'cmd, which says what
+; command they contain.
+
+; We don't allow commands while the queue has anything in it. So we
+; do configuration by concatenating the config command on the front in
+; proof-send
+
+;; proof-assert-until-point, and various gunk for its ;;
+;; setup and callback ;;
+
+;; This code is for nested goals in Coq, and shouldn't affect things
+;; in LEGO. It lifts "local" lemmas from inside goals out to top
+;; level.
+
+(defun proof-lift-global (glob-span)
+ (let (start (next (span-at 1 'type)) str (goal-p nil))
+ (while (and next (and (not (eq next glob-span)) (not goal-p)))
+ (if (and (eq (span-property next 'type) 'vanilla)
+ (funcall proof-goal-command-p (span-property next 'cmd)))
+ (setq goal-p t)
+ (setq next (next-span next 'type))))
+
+ (if (and next (not (eq next glob-span)))
+ (progn
+ (proof-unlock-locked)
+ (setq str (buffer-substring (span-start glob-span)
+ (span-end glob-span)))
+ (delete-region (span-start glob-span) (span-end glob-span))
+ (goto-char (span-start next))
+ (setq start (point))
+ (insert str "\n")
+ (set-span-endpoints glob-span start (point))
+ (set-span-start next (point))
+ (proof-lock-unlocked)))))
+
+;; This is the actual callback for assert-until-point.
+
+(defun proof-done-advancing (span)
+ (let ((end (span-end span)) nam gspan next cmd)
+ (proof-set-locked-end end)
+ (proof-set-queue-start end)
+ (setq cmd (span-property span 'cmd))
+ (cond
+ ((eq (span-property span 'type) 'comment)
+ (set-span-property span 'mouse-face 'highlight))
+ ((string-match proof-save-command-regexp cmd)
+ ;; In coq, we have the invariant that if we've done a save and
+ ;; there's a top-level declaration then it must be the
+ ;; associated goal. (Notice that because it's a callback it
+ ;; must have been approved by the theorem prover.)
+ (if (string-match proof-save-with-hole-regexp cmd)
+ (setq nam (match-string 2 cmd)))
+ (setq gspan span)
+ (while (or (eq (span-property gspan 'type) 'comment)
+ (not (funcall proof-goal-command-p
+ (setq cmd (span-property gspan 'cmd)))))
+ (setq next (prev-span gspan 'type))
+ (delete-span gspan)
+ (setq gspan next))
+
+ (if (null nam)
+ (if (string-match proof-goal-with-hole-regexp
+ (span-property gspan 'cmd))
+ (setq nam (match-string 2 (span-property gspan 'cmd)))
+ ;; This only works for Coq, but LEGO raises an error if
+ ;; there's no name.
+ (setq nam "Unnamed_thm")))
+
+ (set-span-end gspan end)
+ (set-span-property gspan 'mouse-face 'highlight)
+ (set-span-property gspan 'type 'goalsave)
+ (set-span-property gspan 'name nam)
+
+ (proof-lift-global gspan))
+ (t
+ (set-span-property span 'mouse-face 'highlight)
+ (if (funcall proof-global-p cmd)
+ (proof-lift-global span))))))
+
+; depth marks number of nested comments. quote-parity is false if
+; we're inside ""'s. Only one of (depth > 0) and (not quote-parity)
+; should be true at once. -- hhg
+
+(defun proof-segment-up-to (pos)
+ "Create a list of (type,int,string) pairs from the end of the locked
+region to pos, denoting the command and the position of its
+terminator. type is one of comment, or cmd. 'unclosed-comment may be
+consed onto the start if the segment finishes with an unclosed
+comment."
+ (save-excursion
+ (let ((str (make-string (- (buffer-size) (proof-locked-end) -10) ?x))
+ (i 0) (depth 0) (quote-parity t) done alist c)
+ (proof-goto-end-of-locked)
+ (while (not done)
+ (cond
+ ((and (= (point) pos) (> depth 0))
+ (setq done t alist (cons 'unclosed-comment alist)))
+ ((= (point) (point-max))
+ (if (not quote-parity)
+ (message "Warning: unclosed quote"))
+ (setq done t))
+ ((and (looking-at "\\*)") quote-parity)
+ (if (= depth 0)
+ (progn (message "Warning: extraneous comment end") (setq done t))
+ (setq depth (- depth 1)) (forward-char 2)
+ (if (eq i 0)
+ (setq alist (cons (list 'comment "" (point)) alist))
+ (aset str i ?\ ) (incf i))))
+ ((and (looking-at "(\\*") quote-parity)
+ (setq depth (+ depth 1)) (forward-char 2))
+ ((> depth 0) (forward-char))
+ (t
+ (setq c (char-after (point)))
+ (if (or (> i 0) (not (= (char-syntax c) ?\ )))
+ (progn (aset str i c) (incf i)))
+ (if (looking-at "\"")
+ (setq quote-parity (not quote-parity)))
+ (forward-char)
+ (if (and (= c proof-terminal-char) quote-parity)
+ (progn
+ (setq alist
+ (cons (list 'cmd (substring str 0 i) (point)) alist))
+ (if (>= (point) pos) (setq done t) (setq i 0)))))))
+ alist)))
+
+(defun proof-semis-to-vanillas (semis &optional callback-fn)
+ "Convert a sequence of semicolon positions (returned by the above
+function) to a set of vanilla extents."
+ (let ((ct (proof-locked-end)) span alist semi)
+ (while (not (null semis))
+ (setq semi (car semis)
+ span (make-span ct (nth 2 semi))
+ ct (nth 2 semi))
+ (if (eq (car (car semis)) 'cmd)
+ (progn
+ (set-span-property span 'type 'vanilla)
+ (set-span-property span 'cmd (nth 1 semi))
+ (setq alist (cons (list span (nth 1 semi)
+ (or callback-fn 'proof-done-advancing))
+ alist)))
+ (set-span-property span 'type 'comment)
+ (setq alist (cons (list span "COMMENT" 'proof-done-advancing) alist)))
+ (setq semis (cdr semis)))
+ (nreverse alist)))
+
+; Assert until point - We actually use this to implement the
+; assert-until-point, active terminator keypress, and find-next-terminator.
+; In different cases we want different things, but usually the information
+; (i.e. are we inside a comment) isn't available until we've actually run
+; proof-segment-up-to (point), hence all the different options when we've
+; done so.
+
+(defun proof-assert-until-point
+ (&optional unclosed-comment-fun ignore-proof-process-p)
+ "Process the region from the end of the locked-region until point.
+ Default action if inside a comment is just to go until the start of
+ the comment. If you want something different, put it inside
+ unclosed-comment-fun. If ignore-proof-process-p is set, no commands
+ will be added to the queue."
+ (interactive)
+ (let ((pt (point))
+ (crowbar (or ignore-proof-process-p (proof-steal-process)))
+ semis)
+ (save-excursion
+ (if (not (re-search-backward "\\S-" (proof-locked-end) t))
+ (progn (goto-char pt)
+ (error "Nothing to do!")))
+ (setq semis (proof-segment-up-to (point))))
+ (if (and unclosed-comment-fun (eq 'unclosed-comment (car semis)))
+ (funcall unclosed-comment-fun)
+ (if (eq 'unclosed-comment (car semis)) (setq semis (cdr semis)))
+ (if (and (not ignore-proof-process-p) (not crowbar) (null semis))
+ (error "Nothing to do!"))
+ (goto-char (nth 2 (car semis)))
+ (and (not ignore-proof-process-p)
+ (let ((vanillas (proof-semis-to-vanillas (nreverse semis))))
+ (if crowbar (setq vanillas (cons crowbar vanillas)))
+ (proof-start-queue (proof-locked-end) (point) vanillas))))))
+
+;; insert-pbp-command - an advancing command, for use when ;;
+;; PbpHyp or Pbp has executed in LEGO, and returned a ;;
+;; command for us to run ;;
+
+(defun proof-insert-pbp-command (cmd)
+ (proof-check-process-available)
+ (let (span)
+ (proof-goto-end-of-locked)
+ (insert cmd)
+ (setq span (make-span (proof-locked-end) (point)))
+ (set-span-property span 'type 'pbp)
+ (set-span-property span 'cmd cmd)
+ (proof-start-queue (proof-locked-end) (point)
+ (list (list span cmd 'proof-done-advancing)))))
+
+
+;; proof-retract-until-point and associated gunk ;;
+;; most of the hard work (i.e computing the commands to do ;;
+;; the retraction) is implemented in the customisation ;;
+;; module (lego.el or coq.el) which is why this looks so ;;
+;; straightforward ;;
+
+
+(defun proof-done-retracting (span)
+ "Updates display after proof process has reset its state. See also
+the documentation for `proof-retract-until-point'. It optionally
+deletes the region corresponding to the proof sequence."
+ (let ((start (span-start span))
+ (end (span-end span))
+ (kill (span-property span 'delete-me)))
+ (proof-set-locked-end start)
+ (proof-set-queue-end start)
+ (delete-spans start end 'type)
+ (delete-span span)
+ (if kill (delete-region start end))))
+
+(defun proof-setup-retract-action (start end proof-command delete-region)
+ (let ((span (make-span start end)))
+ (set-span-property span 'delete-me delete-region)
+ (list (list span proof-command 'proof-done-retracting))))
+
+(defun proof-retract-target (target delete-region)
+ (let ((end (proof-locked-end))
+ (start (span-start target))
+ (span (proof-last-goal-or-goalsave))
+ actions)
+
+ (if (and span (not (eq (span-property span 'type) 'goalsave)))
+ (if (< (span-end span) (span-end target))
+ (progn
+ (setq span target)
+ (while (and span (eq (span-property span 'type) 'comment))
+ (setq span (next-span span 'type)))
+ (setq actions (proof-setup-retract-action
+ start end
+ (if (null span) "COMMENT"
+ (funcall proof-count-undos-fn span))
+ delete-region)
+ end start))
+
+ (setq actions (proof-setup-retract-action (span-start span) end
+ proof-kill-goal-command
+ delete-region)
+ end (span-start span))))
+
+ (if (> end start)
+ (setq actions
+ (nconc actions (proof-setup-retract-action
+ start end
+ (funcall proof-find-and-forget-fn target)
+ delete-region))))
+
+ (proof-start-queue (min start end) (proof-locked-end) actions)))
+
+(defun proof-retract-until-point (&optional delete-region)
+ "Sets up the proof process for retracting until point. In
+ particular, it sets a flag for the filter process to call
+ `proof-done-retracting' after the proof process has actually
+ successfully reset its state. It optionally deletes the region in
+ the proof script corresponding to the proof command sequence. If
+ this function is invoked outside a locked region, the last
+ successfully processed command is undone."
+ (interactive)
+ (proof-check-process-available)
+ (let ((span (span-at (point) 'type)))
+ (if (null (proof-locked-end)) (error "No locked region"))
+ (and (null span)
+ (progn (proof-goto-end-of-locked) (backward-char)
+ (setq span (span-at (point) 'type))))
+ (proof-retract-target span delete-region)))
+
+;; proof-try-command ;;
+;; this isn't really in the spirit of script management, ;;
+;; but sometimes the user wants to just try an expression ;;
+;; without having to undo it in order to try something ;;
+;; different. Of course you can easily lose sync by doing ;;
+;; something here which changes the proof state ;;
+
+(defun proof-done-trying (span)
+ (delete-span span)
+ (proof-detach-queue))
+
+(defun proof-try-command
+ (&optional unclosed-comment-fun)
+
+ "Process the command at point,
+ but don't add it to the locked region. This will only happen if
+ the command satisfies proof-state-preserving-p.
+
+ Default action if inside a comment is just to go until the start of
+ the comment. If you want something different, put it inside
+ unclosed-comment-fun."
+ (interactive)
+ (let ((pt (point)) semis crowbar test)
+ (setq crowbar (proof-steal-process))
+ (save-excursion
+ (if (not (re-search-backward "\\S-" (proof-locked-end) t))
+ (progn (goto-char pt)
+ (error "Nothing to do!")))
+ (setq semis (proof-segment-up-to (point))))
+ (if (and unclosed-comment-fun (eq 'unclosed-comment (car semis)))
+ (funcall unclosed-comment-fun)
+ (if (eq 'unclosed-comment (car semis)) (setq semis (cdr semis)))
+ (if (and (not crowbar) (null semis)) (error "Nothing to do!"))
+ (setq test (car semis))
+ (if (not (funcall proof-state-preserving-p (nth 1 test)))
+ (error "Command is not state preserving"))
+ (goto-char (nth 2 test))
+ (let ((vanillas (proof-semis-to-vanillas (list test)
+ 'proof-done-trying)))
+ (if crowbar (setq vanillas (cons crowbar vanillas)))
+ (proof-start-queue (proof-locked-end) (point) vanillas)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; misc other user functions ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defun proof-undo-last-successful-command ()
+ "Undo last successful command, both in the buffer recording the
+ proof script and in the proof process. In particular, it deletes
+ the corresponding part of the proof script."
+ (interactive)
+ (goto-char (span-start (span-at-before (proof-locked-end) 'type)))
+ (proof-retract-until-point t))
+
+(defun proof-interrupt-process ()
+ (interactive)
+ (if (not (proof-shell-live-buffer))
+ (error "Proof Process Not Started!"))
+ (if (not (eq proof-script-buffer (current-buffer)))
+ (error "Don't own process!"))
+ (if (not proof-shell-busy)
+ (error "Proof Process Not Active!"))
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+ (comint-interrupt-subjob)))
+
+
+(defun proof-find-next-terminator ()
+ "Set point after next `proof-terminal-char'."
+ (interactive)
+ (let ((cmd (span-at (point) 'type)))
+ (if cmd (goto-char (span-end cmd))
+ (and (re-search-forward "\\S-" nil t)
+ (proof-assert-until-point nil 'ignore-proof-process)))))
+
+(defun proof-process-buffer ()
+ "Process the current buffer and set point at the end of the buffer."
+ (interactive)
+ (end-of-buffer)
+ (proof-assert-until-point))
+
+;; For when things go horribly wrong
+
+(defun proof-restart-script ()
+ (interactive)
+ (save-excursion
+ (if (buffer-live-p proof-script-buffer)
+ (progn
+ (set-buffer proof-script-buffer)
+ (setq proof-active-buffer-fake-minor-mode nil)
+ (delete-spans (point-min) (point-max) 'type)
+ (proof-detach-segments)))
+ (setq proof-shell-busy nil
+ proof-script-buffer nil)
+ (if (buffer-live-p proof-shell-buffer)
+ (kill-buffer proof-shell-buffer))
+ (if (buffer-live-p proof-pbp-buffer)
+ (kill-buffer proof-pbp-buffer))))
+
+;; A command for making things go horribly wrong - it moves the
+;; end-of-locked-region marker backwards, so user had better move it
+;; correctly to sync with the proof state, or things will go all
+;; pear-shaped.
+
+(defun proof-frob-locked-end ()
+ (interactive)
+ "Move the end of the locked region backwards.
+ Only for use by consenting adults."
+ (cond
+ ((not (eq proof-script-buffer (current-buffer)))
+ (error "Not in proof buffer"))
+ ((> (point) (proof-locked-end))
+ (error "Can only move backwards"))
+ (t (proof-set-locked-end (point))
+ (delete-spans (proof-locked-end) (point-max) 'type))))
+
+(defvar proof-minibuffer-history nil
+ "The last command read from the minibuffer")
+
+(defun proof-execute-minibuffer-cmd ()
+ (interactive)
+ (let (cmd)
+ (proof-check-process-available 'relaxed)
+ (setq cmd (read-string "Command: " nil 'proof-minibuffer-history))
+ (proof-invisible-command cmd 'relaxed)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Popup and Pulldown Menu ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Menu commands for the underlying proof assistant
+(defvar proof-ctxt-string ""
+ "Command to display context in proof assistant")
+
+(defvar proof-help-string ""
+ "Command to ask for help in proof assistant")
+
+(defvar proof-prf-string ""
+ "Command to display proof state in proof assistant")
+
+(defun proof-ctxt ()
+ "List context."
+ (interactive)
+ (proof-invisible-command (concat proof-ctxt-string proof-terminal-string)))
+
+(defun proof-help ()
+ "Print help message giving syntax."
+ (interactive)
+ (proof-invisible-command (concat proof-help-string proof-terminal-string)))
+
+(defun proof-prf ()
+ "List proof state."
+ (interactive)
+ (proof-invisible-command (concat proof-prf-string proof-terminal-string)))
+
+;;; To be called from menu
+(defun proof-info-mode ()
+ "Info mode on proof mode."
+ (interactive)
+ (info "script-management"))
+
+(defun proof-exit ()
+ "Exit Proof-assistant."
+ (interactive)
+ (proof-restart-script))
+
+(defvar proof-help-menu
+ '("Help"
+ ["Proof assistant web page"
+ (w3-fetch proof-www-home-page) t]
+ ["Help on Emacs proof-mode" proof-info-mode t]
+ )
+ "The Help Menu in Script Management.")
+
+(defvar proof-shared-menu
+ (append-element '(
+ ["Display context" proof-ctxt
+ :active (proof-shell-live-buffer)]
+ ["Display proof state" proof-prf
+ :active (proof-shell-live-buffer)]
+ ["Exit proof assistant" proof-exit
+ :active (proof-shell-live-buffer)]
+ "----"
+ ["Find definition/declaration" find-tag-other-window t]
+ )
+ proof-help-menu))
+
+(defvar proof-menu
+ (append '("Commands"
+ ["Toggle active terminator" proof-active-terminator-minor-mode
+ :active t
+ :style toggle
+ :selected proof-active-terminator-minor-mode]
+ "----")
+ (list (if (string-match "XEmacs 19.1[2-9]" emacs-version)
+ "--:doubleLine" "----"))
+ proof-shared-menu
+ )
+ "*The menu for the proof assistant.")
+
+(defvar proof-shell-menu proof-shared-menu
+ "The menu for the Proof-assistant shell")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Active terminator minor mode ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(deflocal proof-active-terminator-minor-mode nil
+ "active terminator minor mode flag")
+
+(defun proof-active-terminator-minor-mode (&optional arg)
+ "Toggle PROOF's Active Terminator minor mode.
+With arg, turn on the Active Terminator minor mode if and only if arg
+is positive.
+
+If Active terminator mode is enabled, a terminator will process the
+current command."
+
+ (interactive "P")
+
+;; has this minor mode been registered as such?
+ (or (assq 'proof-active-terminator-minor-mode minor-mode-alist)
+ (setq minor-mode-alist
+ (append minor-mode-alist
+ (list '(proof-active-terminator-minor-mode
+ (concat " " proof-terminal-string))))))
+
+ (setq proof-active-terminator-minor-mode
+ (if (null arg) (not proof-active-terminator-minor-mode)
+ (> (prefix-numeric-value arg) 0)))
+ (if (fboundp 'redraw-modeline)
+ (redraw-modeline)
+ (force-mode-line-update)))
+
+(defun proof-process-active-terminator ()
+ "Insert the terminator in an intelligent way and assert until the
+ new terminator. Fire up proof process if necessary."
+ (let ((mrk (point)) ins)
+ (if (looking-at "\\s-\\|\\'\\|\\w")
+ (if (not (re-search-backward "\\S-" (proof-unprocessed-begin) t))
+ (error "Nothing to do!")))
+ (if (not (= (char-after (point)) proof-terminal-char))
+ (progn (forward-char) (insert proof-terminal-string) (setq ins t)))
+ (proof-assert-until-point
+ (function (lambda ()
+ (if ins (backward-delete-char 1))
+ (goto-char mrk) (insert proof-terminal-string))))))
+
+(defun proof-active-terminator ()
+ (interactive)
+ (if proof-active-terminator-minor-mode
+ (proof-process-active-terminator)
+ (self-insert-command 1)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Proof mode configuration ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(define-derived-mode proof-mode fundamental-mode
+ proof-mode-name "Proof mode - not standalone"
+ ;; define-derived-mode proof-mode initialises proof-mode-map
+ (setq proof-buffer-type 'script))
+
+;; This has to come after proof-mode is defined
+
+(define-derived-mode proof-shell-mode comint-mode
+ "proof-shell" "Proof shell mode - not standalone"
+ (setq proof-buffer-type 'shell)
+ (setq proof-shell-busy nil)
+ (setq proof-shell-delayed-output (cons 'insert "done"))
+ (setq comint-prompt-regexp proof-shell-prompt-pattern)
+ (add-hook 'comint-output-filter-functions 'proof-shell-filter nil t)
+ (setq comint-get-old-input (function (lambda () "")))
+ (proof-dont-show-annotations)
+ (setq proof-marker (make-marker)))
+
+(easy-menu-define proof-shell-menu
+ proof-shell-mode-map
+ "Menu used in the proof assistant shell."
+ (cons proof-mode-name (cdr proof-shell-menu)))
+
+(easy-menu-define proof-mode-menu
+ proof-mode-map
+ "Menu used in proof mode."
+ (cons proof-mode-name (cdr proof-menu)))
+
+;; the following callback is an irritating hack - there should be some
+;; elegant mechanism for computing constants after the child has
+;; configured.
+
+(defun proof-config-done ()
+
+;; calculate some strings and regexps for searching
+
+ (setq proof-terminal-string (char-to-string proof-terminal-char))
+
+ (setq pbp-goal-command (concat "Pbp %s" proof-terminal-string))
+ (setq pbp-hyp-command (concat "PbpHyp %s" proof-terminal-string))
+
+ (make-local-variable 'comment-start)
+ (setq comment-start (concat proof-comment-start " "))
+ (make-local-variable 'comment-end)
+ (setq comment-end (concat " " proof-comment-end))
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip
+ (concat (regexp-quote proof-comment-start) "+\\s_?"))
+
+ (setq proof-re-end-of-cmd (concat "\\s_*" proof-terminal-string "\\s_*\\\'"))
+ (setq proof-re-term-or-comment
+ (concat proof-terminal-string "\\|" (regexp-quote proof-comment-start)
+ "\\|" (regexp-quote proof-comment-end)))
+
+;; func-menu --- Jump to a goal within a buffer
+ (and (boundp 'fume-function-name-regexp-alist)
+ (defvar fume-function-name-regexp-proof
+ (cons proof-goal-with-hole-regexp 2))
+ (push (cons major-mode 'fume-function-name-regexp-proof)
+ fume-function-name-regexp-alist))
+ (and (boundp 'fume-find-function-name-method-alist)
+ (push (cons major-mode 'fume-match-find-next-function-name)
+ fume-find-function-name-method-alist))
+
+;; Info
+ (or (memq proof-info-dir Info-default-directory-list)
+ (setq Info-default-directory-list
+ (cons proof-info-dir Info-default-directory-list)))
+
+;; keymaps and menus
+ (easy-menu-add proof-mode-menu proof-mode-map)
+
+ (proof-define-keys proof-mode-map proof-universal-keys)
+
+ (define-key proof-mode-map
+ (vconcat [(control c)] (vector proof-terminal-char))
+ 'proof-active-terminator-minor-mode)
+
+ (define-key proof-mode-map [(control c) (control e)]
+ 'proof-find-next-terminator)
+
+ (define-key proof-mode-map (vector proof-terminal-char)
+ 'proof-active-terminator)
+ (define-key proof-mode-map [(control c) (return)] 'proof-assert-until-point)
+ (define-key proof-mode-map [(control c) (control t)] 'proof-try-command)
+ (define-key proof-mode-map [(control c) ?u] 'proof-retract-until-point)
+ (define-key proof-mode-map [(control c) (control u)]
+ 'proof-undo-last-successful-command)
+
+ (define-key proof-mode-map [(control c) ?\']
+ 'proof-goto-end-of-locked-interactive)
+ (define-key proof-mode-map [(control button1)] 'proof-send-span)
+ (define-key proof-mode-map [(control c) (control b)] 'proof-process-buffer)
+ (define-key proof-mode-map [(control c) (control z)] 'proof-frob-locked-end)
+
+ (define-key proof-mode-map [tab] 'proof-indent-line)
+ (setq indent-line-function 'proof-indent-line)
+
+ (define-key (current-local-map) [(control c) (control p)] 'proof-prf)
+ (define-key (current-local-map) [(control c) ?c] 'proof-ctxt)
+ (define-key (current-local-map) [(control c) ?h] 'proof-help)
+
+;; For fontlock
+ (remove-hook 'font-lock-after-fontify-buffer-hook 'proof-zap-commas-buffer t)
+ (add-hook 'font-lock-after-fontify-buffer-hook 'proof-zap-commas-buffer nil t)
+ (remove-hook 'font-lock-mode-hook 'proof-unfontify-separator t)
+ (add-hook 'font-lock-mode-hook 'proof-unfontify-separator nil t)
+
+;; if we don't have the following, zap-commas fails to work.
+
+ (and (boundp 'font-lock-always-fontify-immediately)
+ (setq font-lock-always-fontify-immediately t))
+
+ (run-hooks 'proof-mode-hook))
+
+(defun proof-shell-config-done ()
+ (accept-process-output (get-buffer-process (current-buffer)))
+
+ ;; If the proof process in invoked on a different machine e.g.,
+ ;; for proof-prog-name="rsh fastmachine proofprocess", one needs
+ ;; to adjust the directory:
+ (and proof-shell-cd
+ (proof-shell-insert (format proof-shell-cd
+ ;; under Emacs 19.34 default-directory contains "~" which causes
+ ;; problems with LEGO's internal Cd command
+ (expand-file-name default-directory))))
+
+ (if proof-shell-init-cmd
+ (proof-shell-insert proof-shell-init-cmd))
+
+;; Note that proof-marker actually gets set in proof-shell-filter.
+;; This is manifestly a hack, but finding somewhere more convenient
+;; to do the setup is tricky.
+
+ (while (null (marker-position proof-marker))
+ (if (accept-process-output (get-buffer-process (current-buffer)) 15)
+ ()
+ (error "Failed to initialise proof process"))))
+
+(define-derived-mode pbp-mode fundamental-mode
+ proof-mode-name "Proof by Pointing"
+ ;; defined-derived-mode pbp-mode initialises pbp-mode-map
+ (setq proof-buffer-type 'pbp)
+ (suppress-keymap pbp-mode-map 'all)
+; (define-key pbp-mode-map [(button2)] 'pbp-button-action)
+ (proof-define-keys pbp-mode-map proof-universal-keys)
+ (erase-buffer))
+
+
+(provide 'proof)
diff --git a/script-management.texinfo b/script-management.texinfo
new file mode 100644
index 00000000..a7232b3c
--- /dev/null
+++ b/script-management.texinfo
@@ -0,0 +1,440 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename script-management.info
+@settitle Script Management
+@paragraphindent 0
+@c %**end of header
+
+@setchapternewpage odd
+
+@titlepage
+@sp 10
+@comment The title is printed in a large font.
+@center @titlefont{Script Management Mode}
+
+@c The following two commands start the copyright page.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1997, 1998 LEGO Team, LFCS Edinburgh
+@end titlepage
+
+@node Top, Credits, (dir), (dir)
+@comment node-name, next, previous, up
+
+A @emph{proof script} is a sequence of commands to a proof assistant.
+Proof mode is a mode designed to be customised for a particular proof
+assistant, to manage communication with a proof process and thereby
+support building and secure editing of proof scripts. Currently custom
+modes exist for LEGO and Coq.
+
+@menu
+* Credits:: The people Involved
+* Introduction:: Introduction to Script Management
+* Commands:: Proof mode Commands
+* Multiple Files:: Proof developments spanning several files
+* Proof by Pointing:: Proof using the Mouse
+* An Active Terminator:: Active Terminator minor mode
+* Walkthrough:: An example of using proof mode
+* LEGO mode:: Extra Bindings for LEGO
+* Coq mode:: Extra Bindings for Coq
+* Internals:: The Seedy Underside of Proof mode
+* Known Problems:: Caveat Emptor
+@end menu
+
+@node Credits, Introduction, Top, Top
+@comment node-name, next, previous, up
+@unnumberedsec Credits
+
+Inspired by Yves Bertot's Centaur-based proof environment CtCoq, Healf
+Goguen, Thomas Kleymann and Dilip Sequeira have implented a generic
+proof mode for Emacs. The original proof-by-pointing algorithm has been
+implemented by Yves Bertot. This manual was originally written by Dilip
+Sequeira.
+
+@node Introduction, Commands, Credits, Top
+@comment node-name, next, previous, up
+@unnumberedsec Introduction
+
+Each script resides in an Emacs buffer, called a @emph{script buffer},
+which is divided into three regions:
+
+@itemize @bullet
+@item The @emph{Locked} region appears in blue (underlined on monochrome
+displays) and contains commands which have been sent to the proof process
+and verified. The commands in the locked region cannot be edited.
+
+@item The @emph{Queue} region appears in pink (inverse video) and contains
+commands waiting to be sent to the proof process. Like those in the
+locked region, these commands can't be edited.
+
+@item The @emph{Editing} region contains the commands the user is working
+on, and can be edited as normal Emacs text.
+@end itemize
+
+These three regions appear in the buffer in the order above; that is,
+the locked region is always at the start of the buffer, and the editing
+region always at the end. The queue region only exists if there is input
+waiting to be sent to the proof process.
+
+Proof mode has two operations which transfer commands between these
+regions: assertion and retraction. These cause commands to be sent to
+the proof process, and Emacs will summarise the results in the
+@emph{Response Buffer}.
+
+@strong{Assertion} causes commands from the editing region to be
+transferred to the queue region and sent one by one to the proof
+process. If the command is accepted, it is transferred to the locked
+region, but if an error occurs it is signalled to the user, and the
+offending command is transferred back to the editing region together
+with any remaining commands in the queue. @strong{Retraction} causes
+commands to be transferred from the locked region to the editing region
+(again via the queue region) and the appropriate 'undo' commands to be
+sent to the proof process.
+
+As commands are transferred to the locked region, they are aggregated
+into segments which constitute the smallest units which can be
+undone. Typically a segment consists of a declaration or definition, or
+all the text from a `goal' command to the corresponding `save' command,
+or the individual commands in the proof of an unfinished goal. As the
+mouse moves over the the region, the segment containing the pointer will
+be highlighted.
+
+Commands in the editing region can be freely edited while
+commands in the queue are transferred to the proof process. However,
+assertion and retraction commands can only be issued when the queue is
+empty.
+
+@node Commands, Multiple Files, Introduction, Top
+@unnumberedsec Proof Mode Commands
+
+@table @kbd
+
+@item C-c C-b
+assert the commands in the buffer.
+
+@item C-c return
+assert the commands in the editing region up to and
+including the one containing the point.
+
+@item C-c u
+retract the segments in the locked region back to and
+including the one containing the point. If point is outside the *Locked*
+region, the last segment is undone.
+
+@item C-c C-u
+retract the last segment in the locked region, and kill the text in it.
+@footnote{Be careful with this, as it may delete more than you anticipate.
+However, you can always recover the killed text using Emacs Undo.}
+
+@item C-c '
+move the point to the end of the locked region. If you are in a script
+buffer other than the active scripting buffer, this will also transfer
+you to the active one.
+
+@item C-c C-e
+move the point to the next terminator
+
+@item C-c C-p
+display the proof state in the response buffer
+
+@item C-c c
+display the context in the response buffer
+
+@item C-c h
+print proof-system specific help text in the response buffer
+
+@item C-c C-c
+interrupt the process process. This may leave script management or the
+proof process (or both) in an inconsistent state.
+
+@item C-c C-z
+move the end of the locked region backwards to the end of the segment
+containing the point. @footnote{Don't try this one at home, kids.}
+
+@item C-c C-t
+Send the command at the point to the subprocess, not
+recording it in the locked region. @footnote{This is supplied in order
+to enable the user to test the types and values of expressions. There's
+some checking that the command won't change the proof state, but it
+isn't foolproof.}
+
+@item C-c C-v
+Request a command from the minibuffer and send it to
+the subprocess. Currently no checking whatsoever is done on the command.
+@end table
+
+The command @code{proof-restart-script} can be used to completely
+restart script management.
+
+
+@node Multiple Files, An Active Terminator, Commands, Top
+@unnumberedsec Multiple Files
+
+Proof mode has a rudimentary facility for operating with multiple files
+in a proof development. This is currently only supported for LEGO. If
+the user invokes script management in a different buffer from the one in
+which it is running, one of two prompts will appear:
+
+@itemize @bullet
+@item ``Steal script management?''
+if Emacs doesn't think the file is already part of the proof development
+@item ``Reprocess this file?''
+if Emacs thinks the file is already included in the proof process. If
+the user confirms, Emacs will cause the proof process to forget the
+contents of the file, so that it is processed afresh.
+@end itemize
+
+Currently this facility requires each script buffer to have a
+corresponding file.
+
+When working with script management in multiple buffers, it is easy
+to lose track of which buffer is the current script buffer. As a mnemonic
+aid, the word @samp{Scripting} appears in the minor mode list of the
+active scripting buffer.
+
+Caveats:
+@itemize @minus
+@item Note that if processing a buffer causes other files to be loaded
+into the LEGO process, those files will be imported from disk rather
+than from any Emacs buffer in which it is being edited, i.e.@: if your
+file is going to be included indirectly, save it.
+
+@item However much you move around the file system in Emacs, the
+LEGOPATH will be the LEGOPATH you started with. No concept of
+"current directory" is currently supported.
+@end itemize
+
+@node An Active Terminator, Proof by Pointing, Multiple Files, Top
+@unnumberedsec An Active Terminator
+
+Proof mode has a minor mode which causes the terminator to become
+active. When this mode is active, pressing the terminator key (@kbd{;}
+for LEGO, @kbd{.} for Coq) outside a comment or quote will cause the
+character to be entered into the buffer, and all the commands in the
+editing region up to the point to be asserted.
+
+This mode can be toggled with the command
+`proof-active-terminator-minor-mode' (@kbd{C-c ;} or @kbd{C-c .})
+
+@node Proof by Pointing, Walkthrough, An Active Terminator, Top
+@unnumberedsec Proof by Pointing
+
+@emph{This mode is currently very unreliable, and we do not guarantee
+that it will work as discussed in this document.}
+
+Proof by pointing is a facility whereby proof commands can be generated
+by using the mouse to select terms. When proving a goal, a summary of
+the current proof state will appear in the response buffer. By moving
+the mouse over the buffer, the structure of the goal and hypothesis
+terms will be shown by highlighting.
+
+If a selection is made using the second (usually the middle) mouse
+button, Emacs will generate the appropriate commands, insert them in the
+script buffer, and send them to the proof process. These commands are
+aggregated in the locked region as a single segment, so that a
+mouse-generated command sequence can be retracted with a single
+retraction command.
+
+Further Information about proof by pointing may be found in the paper
+@cite{User Interfaces for Theorem Provers} by Yves Bertot and Laurent
+Thery, to appear in @cite{Information and Computation}, from which
+the following example is taken.
+
+@menu
+* Proof by Pointing Example:: An example using proof by pointing
+@end menu
+
+@node Proof by Pointing Example, ,Proof by Pointing,Proof by Pointing
+
+Suppose we wish to prove the lego term:
+
+@example
+(((p a) \/ (q b)) /\ @{x:Prop@}(p x) -> (q x)) -> (Ex ([x:Prop] q(x)));
+@end example
+
+Asserting this goal will result in the proof state
+
+@example
+?0 : ((p a \/ q b) /\ @{x:Prop@}(p x)->q x)->Ex ([x:Prop]q x)
+@end example
+
+appearing in the response buffer. Suppose our strategy is to use a
+case analysis on the disjunction, starting with the @samp{p(a)} subterm.
+Clicking on this term will cause script management to insert the following
+command sequence in the script buffer, and execute it.
+
+@example
+Intros H; Refine H; Intros H0 H1;
+Refine or_elim H0 Then Intros H2; Try Refine H2;
+@end example
+
+
+The response buffer will then read
+
+@example
+ H : (p a \/ q b) /\ @{x:Prop@}(p x)->q x
+ H0 : p a \/ q b
+ H1 : @{x:Prop@}(p x)->q x
+ H2 : p a
+ ?10 : Ex ([x:Prop]q x)
+@end example
+
+Clicking on the subterm @samp{(p x)} in the hypothesis H1 will instruct
+script management to prove an instance of @samp{(p x)} and deduce the
+corresponding @samp{(q x)}. The commands
+
+@example
+allE H1; intros +1 H3; Refine impl_elim H3; Try Assumption;
+@end example
+
+are inserted and executed, leaving the proof state as
+
+@example
+ H : (p a \/ q b) /\ @{x:Prop@}(p x)->q x
+ H0 : p a \/ q b
+ H1 : @{x:Prop@}(p x)->q x
+ H2 : p a
+ H3 : (p a)->q a
+ ?20 : (q a)->Ex ([x:Prop]q x)
+@end example
+
+Now clicking on the @samp{q x)} subterm in ?20 will prove the subgoal. We are
+left with the other half of the original case analysis:
+
+@example
+ H : (p a \/ q b) /\ @{x:Prop@}(p x)->q x
+ H0 : p a \/ q b
+ H1 : @{x:Prop@}(p x)->q x
+ H2 : q b
+ ?26 : Ex ([x:Prop]q x)
+@end example
+
+Clicking on @samp{q x} proves the goal.
+
+
+
+
+@node Walkthrough, LEGO mode, Proof by Pointing, Top
+@unnumberedsec A Walkthrough
+
+Here's a LEGO example of how script management is used.
+
+First, we turn on active terminator minor mode by typing @kbd{C-c ;}
+Then we enter
+
+`Module Walkthrough Import lib_logic;'
+
+The command should be lit in pink (or inverse video if you don't have a
+colour display). As LEGO imports each module, a line will appear in the
+response buffer showing the creation of context marks. Eventually the
+command should turn blue, indicating that LEGO has successfully
+processed it. Then type (on a separate line if you like)
+
+@samp{Goal bland_commutes: @{A,B:Prop@} (and A B) -> (and B A);}
+
+The goal should be echoed in the response buffer.
+
+@samp{Intros;}
+
+Whoops! @kbd{C-c C-u} to pretend that didn't happen.
+
+@samp{intros; andI;}
+
+A proof summary will appear in the response buffer. We could solve the
+goal by pointing now, but we'll stay with the keyboard.
+
+@samp{Refine H; intros; Immed; Refine H; intros; Immed;}
+
+finishes the Goal.
+
+@samp{Save bland_commutes;}
+
+Moving the mouse pointer over the locked region now reveals that the
+entire proof has been aggregated into a single segment. Suppose we
+decide to call the goal something more sensible. Moving the cursor up
+into the locked region, somewhere between `Goal' and `Save', we enter
+@kbd{C-c u}. The segment is transferred back into the editing
+region. Now we correct the goal name, move the cursor to the end of the
+buffer, and type @kbd{C-c return}. Proof mode queues the commands for
+processing and executes them.
+
+@node LEGO mode, Coq mode, Walkthrough, Top
+@unnumberedsec LEGO mode
+
+LEGO mode is a mode derived from proof mode for editing LEGO scripts.
+There are some abbreviations for common commands, which
+add text to the buffer:
+
+@table @kbd
+@item C-c i
+intros
+@item C-c I
+Intros
+@item C-c R
+Refine
+@end table
+
+
+@node Coq mode, Known Problems, LEGO mode, Top
+@unnumberedsec Coq mode
+
+Coq mode is a mode derived from proof mode for editing Coq scripts.
+As well as custom popup menus, it has the following commands:
+
+@table @kbd
+
+@item C-c C-s
+search for items in the library of a given type. This runs the
+@kbd{Search} command of Coq.
+
+@end table
+
+In addition, there are some abbreviations for common commands, which
+add text to the buffer:
+
+@table @kbd
+@item C-c I
+Intros
+@item C-c a
+Apply
+@end table
+
+@node Known Problems, Internals, Coq mode, Top
+@unnumberedsec Known Problems
+
+Since Emacs is pretty flexible, there are a whole bunch of things you
+can do to confuse script management. When it gets confused, it may
+become distressed, and may eventually sulk. In such instances
+@code{proof-restart-script-management} may be of use.
+
+A few things to avoid:
+
+@itemize @minus
+@item If you're using script management with multiple files, don't start
+changing the file names.
+
+@item Script Management doesn't understand how to undo @code{Discharge}
+commands in LEGO, and any attempts it makes to do so may leave it in an
+inconsistent state. If you're undoing the effects of a @code{Discharge}
+command, retract back to the declaration of whatever gets discharged.
+
+@item Proof by Pointing doesn't work very well, and is inefficiently
+implemented.
+
+@item The locked and queue regions are not quite read-only: in particular
+Emacs Undo can insert text into them.
+
+@item When a LEGO import command fails, the created "Mark" is not
+forgotten, and the proof process thinks the file has been included. So
+if you assert the command again, it will probably be accepted by LEGO,
+because the relevant mark is in the namespace.
+@end itemize
+
+Fixes for some of these may be provided in a future release.
+
+@node Internals, , Known Problems, Top
+@unnumberedsec Internals
+
+I may one day document the script management internals here. Until then,
+UtSL.
+@bye
diff --git a/span-extent.el b/span-extent.el
new file mode 100644
index 00000000..b49670b7
--- /dev/null
+++ b/span-extent.el
@@ -0,0 +1,79 @@
+;;; This file implements spans in terms of extents, for xemacs.
+;;; Copyright (C) 1998 LFCS Edinburgh
+;;; Author: Healfdene Goguen
+
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+;; $Log$
+;; Revision 2.0 1998/08/11 15:00:13 da
+;; New branch
+;;
+;; Revision 1.4 1998/06/10 14:01:48 hhg
+;; Wrote generic span functions for making spans read-only or read-write.
+;;
+;; Revision 1.3 1998/06/02 15:36:44 hhg
+;; Corrected comment about this being for xemacs.
+;;
+;; Revision 1.2 1998/05/19 15:30:27 hhg
+;; Added header and log message.
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Bridging the emacs19/xemacs gulf ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Now define "spans" in terms of extents.
+
+(defsubst make-span (start end)
+ (make-extent start end))
+
+(defsubst detach-span (span)
+ (detach-extent span))
+
+(defsubst set-span-endpoints (span start end)
+ (set-extent-endpoints span start end))
+
+(defsubst set-span-start (span value)
+ (set-extent-endpoints span value (extent-end-position span)))
+
+(defsubst set-span-end (span value)
+ (set-extent-endpoints span (extent-start-position span) value))
+
+(defsubst span-read-only (span)
+ (set-span-property span 'read-only t))
+
+(defsubst span-read-write (span)
+ (set-span-property span 'read-only nil))
+
+(defsubst span-property (span name)
+ (extent-property span name))
+
+(defsubst set-span-property (span name value)
+ (set-extent-property span name value))
+
+(defsubst delete-span (span)
+ (delete-extent span))
+
+(defsubst delete-spans (start end prop)
+ (mapcar-extents 'delete-extent nil (current-buffer) start end nil prop))
+
+(defsubst span-at (pt prop)
+ (extent-at pt nil prop))
+
+(defsubst span-at-before (pt prop)
+ (extent-at pt nil prop nil 'before))
+
+(defsubst span-start (span)
+ (extent-start-position span))
+
+(defsubst span-end (span)
+ (extent-end-position span))
+
+(defsubst prev-span (span prop)
+ (extent-at (extent-start-position span) nil prop nil 'before))
+
+(defsubst next-span (span prop)
+ (extent-at (extent-end-position span) nil prop nil 'after))
+
+
+(provide 'span-extent)
diff --git a/span-overlay.el b/span-overlay.el
new file mode 100644
index 00000000..f74350ed
--- /dev/null
+++ b/span-overlay.el
@@ -0,0 +1,288 @@
+;;; This file implements spans in terms of overlays, for emacs19.
+;;; Copyright (C) 1998 LFCS Edinburgh
+;;; Author: Healfdene Goguen
+
+;; Maintainer: LEGO Team <lego@dcs.ed.ac.uk>
+
+;; $Log$
+;; Revision 2.0 1998/08/11 15:00:13 da
+;; New branch
+;;
+;; Revision 1.9 1998/06/10 14:02:39 hhg
+;; Wrote generic span functions for making spans read-only or read-write.
+;; Fixed bug in add-span and remove-span concerning return value of
+;; span-traverse.
+;;
+;; Revision 1.8 1998/06/10 12:41:47 hhg
+;; Compare span-end first rather than span-start in span-lt, because
+;; proof-lock-span is often changed and has starting point 1.
+;; Factored out common code of add-span and remove-span into
+;; span-traverse.
+;;
+;; Revision 1.7 1998/06/03 17:40:07 hhg
+;; Changed last-span to before-list.
+;; Added definitions of foldr and foldl if they aren't already loaded.
+;; Changed definitions of add-span, remove-span and find-span-aux to be
+;; non-recursive.
+;; Removed detach-extent since this file isn't used by xemacs.
+;; Added function append-unique to avoid repetitions in list generated by
+;; spans-at-region.
+;; Changed next-span so it uses member-if.
+;;
+;; Revision 1.6 1998/06/02 15:36:51 hhg
+;; Corrected comment about this being for emacs19.
+;;
+;; Revision 1.5 1998/05/29 09:50:10 tms
+;; o outsourced indentation to proof-indent
+;; o support indentation of commands
+;; o replaced test of Emacs version with availability test of specific
+;; features
+;; o C-c C-c, C-c C-v and M-tab is now available in all buffers
+;;
+;; Revision 1.4 1998/05/21 17:27:41 hhg
+;; Removed uninitialized os variable in spans-at-region.
+;;
+;; Revision 1.3 1998/05/21 08:28:52 hhg
+;; Initialize 'before pointer in add-span-aux when last-span is nil.
+;; Removed span-at-type.
+;; Fixed bug in span-at-before, where (span-start span) may be nil.
+;; Added spans-at-(point|region)[-prop], which fixes bug of C-c u at end
+;; of buffer.
+;;
+;; Revision 1.2 1998/05/19 15:31:37 hhg
+;; Added header and log message.
+;; Fixed set-span-endpoints so it preserves invariant.
+;; Changed add-span and remove-span so that they update last-span
+;; correctly themselves, and don't take last-span as an argument.
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Bridging the emacs19/xemacs gulf ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; before-list represents a linked list of spans for each buffer.
+;; It has the invariants of:
+;; * being ordered wrt the starting point of the spans in the list,
+;; with detached spans at the end.
+;; * not having overlapping overlays of the same type.
+
+(defvar before-list nil
+ "Start of backwards-linked list of spans")
+
+(make-variable-buffer-local 'before-list)
+
+
+(or (fboundp 'foldr)
+(defun foldr (func a seq)
+ "Return (func (func (func (... (func a Sn) ...) S2) S1) S0)
+when func's argument is 2 and seq is a sequence whose
+elements = S0 S1 S2 ... Sn. [tl-seq.el]"
+ (let ((i (length seq)))
+ (while (> i 0)
+ (setq i (1- i))
+ (setq a (funcall func a (elt seq i)))
+ )
+ a)))
+
+(or (fboundp 'foldl)
+(defun foldl (func a seq)
+ "Return (... (func (func (func a S0) S1) S2) ...)
+when func's argument is 2 and seq is a sequence whose
+elements = S0 S1 S2 .... [tl-seq.el]"
+ (let ((len (length seq))
+ (i 0))
+ (while (< i len)
+ (setq a (funcall func a (elt seq i)))
+ (setq i (1+ i))
+ )
+ a)))
+
+(defsubst span-start (span)
+ (overlay-start span))
+
+(defsubst span-end (span)
+ (overlay-end span))
+
+(defun set-span-property (span name value)
+ (overlay-put span name value))
+
+(defsubst span-property (span name)
+ (overlay-get span name))
+
+(defun span-read-only-hook (overlay after start end &optional len)
+ (error "Region is read-only"))
+
+(defun span-read-only (span)
+ (set-span-property span 'modification-hooks '(span-read-only-hook))
+ (set-span-property span 'insert-in-front-hooks '(span-read-only-hook)))
+
+(defun span-read-write (span)
+ (set-span-property span 'modification-hooks nil)
+ (set-span-property span 'insert-in-front-hooks nil))
+
+(defun int-nil-lt (m n)
+ (cond
+ ((eq m n) nil)
+ ((not n) t)
+ ((not m) nil)
+ (t (< m n))))
+
+;; We use end first because proof-locked-queue is often changed, and
+;; its starting point is always 1
+(defun span-lt (s u)
+ (or (int-nil-lt (span-end s) (span-end u))
+ (and (eq (span-end s) (span-end u))
+ (int-nil-lt (span-start s) (span-start u)))))
+
+(defun span-traverse (span prop)
+ (cond
+ ((not before-list)
+ ;; before-list empty
+ 'empty)
+ ((funcall prop before-list span)
+ ;; property holds for before-list and span
+ 'hd)
+ (t
+ ;; traverse before-list for property
+ (let ((l before-list) (before (span-property before-list 'before)))
+ (while (and before (not (funcall prop before span)))
+ (setq l before)
+ (setq before (span-property before 'before)))
+ l))))
+
+(defun add-span (span)
+ (let ((ans (span-traverse span 'span-lt)))
+ (cond
+ ((eq ans 'empty)
+ (set-span-property span 'before nil)
+ (setq before-list span))
+ ((eq ans 'hd)
+ (set-span-property span 'before before-list)
+ (setq before-list span))
+ (t
+ (set-span-property span 'before
+ (span-property ans 'before))
+ (set-span-property ans 'before span)))))
+
+(defun make-span (start end)
+ (add-span (make-overlay start end)))
+
+(defun remove-span (span)
+ (let ((ans (span-traverse span 'eq)))
+ (cond
+ ((eq ans 'empty)
+ (error "Bug: empty span list"))
+ ((eq ans 'hd)
+ (setq before-list (span-property before-list 'before)))
+ (ans
+ (set-span-property ans 'before (span-property span 'before)))
+ (t (error "Bug: span does not occur in span list")))))
+
+;; extent-at gives "smallest" extent at pos
+;; we're assuming right now that spans don't overlap
+(defun spans-at-point (pt)
+ (let ((overlays nil) (os nil))
+ (setq os (overlays-at pt))
+ (while os
+ (if (not (memq (car os) overlays))
+ (setq overlays (cons (car os) overlays)))
+ (setq os (cdr os)))
+ overlays))
+
+;; assumes that there are no repetitions in l or m
+(defun append-unique (l m)
+ (foldl (lambda (n a) (if (memq a m) n (cons a n))) m l))
+
+(defun spans-at-region (start end)
+ (let ((overlays nil) (pos start))
+ (while (< pos end)
+ (setq overlays (append-unique (spans-at-point pos) overlays))
+ (setq pos (next-overlay-change pos)))
+ overlays))
+
+(defun spans-at-point-prop (pt prop)
+ (let ((f (cond
+ (prop (lambda (spans span)
+ (if (span-property span prop) (cons span spans)
+ spans)))
+ (t (lambda (spans span) (cons span spans))))))
+ (foldl f nil (spans-at-point pt))))
+
+(defun spans-at-region-prop (start end prop)
+ (let ((f (cond
+ (prop (lambda (spans span)
+ (if (span-property span prop) (cons span spans)
+ spans)))
+ (t (lambda (spans span) (cons span spans))))))
+ (foldl f nil (spans-at-region start end))))
+
+(defun span-at (pt prop)
+ (car (spans-at-point-prop pt prop)))
+
+(defsubst detach-span (span)
+ (remove-span span)
+ (delete-overlay span)
+ (add-span span))
+
+(defsubst delete-span (span)
+ (remove-span span)
+ (delete-overlay span))
+
+;; The next two change ordering of list of spans:
+(defsubst set-span-endpoints (span start end)
+ (remove-span span)
+ (move-overlay span start end)
+ (add-span span))
+
+(defsubst set-span-start (span value)
+ (set-span-endpoints span value (span-end span)))
+
+;; This doesn't affect invariant:
+(defsubst set-span-end (span value)
+ (set-span-endpoints span (span-start span) value))
+
+(defsubst delete-spans (start end prop)
+ (mapcar 'delete-span (spans-at-region-prop start end prop)))
+
+(defun map-spans-aux (f l)
+ (cond (l (cons (funcall f l) (map-spans-aux f (span-property l 'before))))
+ (t ())))
+
+(defsubst map-spans (f)
+ (map-spans-aux f before-list))
+
+(defun find-span-aux (prop-p l)
+ (while (and l (not (funcall prop-p l)))
+ (setq l (span-property l 'before)))
+ l)
+
+(defun find-span (prop-p)
+ (find-span-aux prop-p before-list))
+
+(defun span-at-before (pt prop)
+ (let ((prop-pt-p
+ (cond (prop (lambda (span)
+ (let ((start (span-start span)))
+ (and start (> pt start)
+ (span-property span prop)))))
+ (t (lambda (span)
+ (let ((start (span-start span)))
+ (and start (> pt start))))))))
+ (find-span prop-pt-p)))
+
+(defun prev-span (span prop)
+ (let ((prev-prop-p
+ (cond (prop (lambda (span) (span-property span prop)))
+ (t (lambda (span) t)))))
+ (find-span-aux prev-prop-p (span-property span 'before))))
+
+;; overlays are [start, end)
+;; If there are two spans overlapping then this won't work.
+(defun next-span (span prop)
+ (let ((l (member-if (lambda (span) (span-property span prop))
+ (overlays-at
+ (next-overlay-change (overlay-start span))))))
+ (if l (car l) nil)))
+
+
+(provide 'span-overlay)
diff --git a/todo b/todo
new file mode 100644
index 00000000..7d9dfdb7
--- /dev/null
+++ b/todo
@@ -0,0 +1,175 @@
+-*- mode:outline -*-
+
+* Priorities
+============
+A (High) to be fixed before release (Version 2.0)
+B (Medium) desirable to fix at some point
+C (Low) probably not worth wasting time on
+
+* This is a list of things which need doing in the generic interface
+====================================================================
+
+B Outsource script management features from proof.el to
+ proof-script.el (1h)
+
+A Write function proof-retract-file. (30min)
+ Currently, the command ForgetMark (for LEGO) is hardwired in
+ proof-steal-process.
+
+B Improve documentation in proof.el to help porting/understanding
+ Also add notes into script-management.texinfo
+ (ongoing, da).
+
+A Update source documentation and manual, in particular document bugs
+ and workarounds
+ (4h hhg & tms)
+
+A Implement more generic mechanism for large undos (2h)
+
+ COQ: C-c u inside a Section should reset the whole section, then
+ redo defns
+
+ LEGO: consider Discharge; perhaps unrol to the beginning of the
+ module?
+
+A Multiple files are sometimes handled incorrectly, because the
+ function `proof-steal-process' cannot figure out that some files have
+ already been processed. This is most likely caused by the ad-hoc
+ equality test on file names. Instead, one could employ
+ the built-in `file-truename' to trigger *canonical* file names.
+ (1h tms)
+
+B Implement proof-find-previous-terminator and bind it to C-c C-a
+ (45min tms)
+
+B Technical documentation to record expertise and allow users of other
+ proof systems to adopt generic package (40h hhg & tms)
+
+B Support for x-symbols package
+
+C XEmacs sessions seem to grow excessively in terms of memory
+ allocation. Perhaps some of the spans aren't removed properly?
+ Setting a limit on the size of the process buffer doesn't seem to
+ help.
+
+A file handling could be more robust; perhaps one should always cd to
+ the directory corresponding to the script buffer (currently only
+ done for the buffer which starts up the proof system) (30min tms)
+
+A replace (current-buffer) by proof-shell-buffer/proof-script-buffer
+ where ever possible (30 min tms)
+
+A Replace "You are not authorised for this information." by a proper
+ documentation (2h)
+
+A Reengineer *-count-undos and *-find-and-forget at generic level
+ (3h)
+
+B Allow bib-cite style clicking on Load/Import commands to go to file.
+
+C LEGO and Coq modes overwrite each other.
+
+C We need to go over to piped communication rather than ptys to fix
+ the (Solaris) ^G bug. In this circumstance there's a bug in the
+ eager annotation code
+
+C Outline-mode does not work due to read-only restrictions of
+ protected region
+
+B Remove LEGO-specific code in proof.el: for example,
+ proof-shell-eager-annotation-end, proof-included-files-list.
+ (added by hhg)
+
+B support font-lock in response buffer
+
+B Response buffer: after an error message has been displayed; ensure
+ that the error message is visible
+
+B Introduce keybinding to save the proof e.g., in LEGO, this should
+ insert "Save id" or "$Save id" depending on the name of the theorem.
+
+B use proof buffer instead of response buffer and leave non-proof
+ state output in the process buffer (1h)
+
+B Remove duplication of variables e.g., proof-prog-name and
+ lego-prog-name . (1h)
+
+
+* Proof-by-Pointing
+===================
+
+A Fixing up errors caused by pbp-generated commands; currently, script
+ management unwisely assumes that pbp commands cannot fail (2h tms)
+
+A Rename pbp-mode to response-mode (which doesn't support any actual
+ proof-by-pointing) (30min)
+
+A Outsource actual pbp functionality (30min)
+ (separate pbp annotations from other annotations)
+
+C pbp code doesn't quite accord with the tech report; in particular it
+ decodes annotations eagerly. Lazily would be faster, and it's what
+ the tech report claims
+ --- djs: probably not much faster, actually.
+
+* Here are things to be done to Lego mode
+=========================================
+
+A fix Pbp implementation (10h; tms)
+
+A Sometimes e.g., ~tms/lego/imperative/recursion/Prepare_vc.l,
+ annotations are recorded in the object file. This needs to be
+ changed in the SML code. (initially 2h tms)
+
+C Mechanism to save object file
+
+B Equiv, Next,... aren't handled properly, because LEGO does not
+ refresh the proof state. Perhaps it would be easiest to get LEGO to
+ output more information in proof script mode (2h tms)
+
+A Error messages need to be revised e.g., if an import fails, LEGO
+ outputs
+
+ Error in file: search: undefined or out of context: should
+ (* closing file ./blah.l; time= 0.010000 gc= 0.0 sys= 0.0 *)
+ Error: Unwinding to top-level
+
+ but script management only prints the last line. (5h tms)
+
+* Here are things to be done to Coq mode
+========================================
+
+B set proof-commands-regexp to support indentation for commands
+ (10min hhg)
+
+B Add Patrick Loiseleur's commands to search for vernac or ml files.
+
+C Sections and files are handled incorrectly.
+
+A Lifted nested lemmas respond incorrectly to C-c u: Coq gets sent the
+ correct command if I undo up to the lower lemma, but the buffer
+ undoes to the upper lemma. I.e., if I start Lemma x, then prove
+ Lemma y, then finish x, and undo lemma x, then lemma y gets undone
+ in the buffer as well. (45min hhg)
+ [ This seems to have corrected itself... hhg ]
+
+B Proof-by-Pointing (10h hhg)
+
+A Add coq-add-tactic with a tactic name, which adds that tactic to the
+ undoable tactics and to the font-lock. (2h hhg)
+
+* Emacs19
+=========
+
+B The proof-locked-span isn't set to read-only, because overlays don't
+ have that capability. This needs to be done with text-regions.
+ (2hr hhg)
+
+* Release
+=========
+
+A remove CVS history in all files
+
+A extend Copyright to 1998
+
+A Release Number 2.0 \ No newline at end of file