move everything out of trunk
[lttv.git] / verif / md / promela-mode.el
diff --git a/verif/md/promela-mode.el b/verif/md/promela-mode.el
new file mode 100755 (executable)
index 0000000..10cac3f
--- /dev/null
@@ -0,0 +1,985 @@
+;; promela-mode.el --- major mode for editing PROMELA program files
+;; $Revision: 1.11 $ $Date: 2001/07/09 18:36:45 $ $Author: engstrom $
+
+;; Author: Eric Engstrom <eric.engstrom@honeywell.com>
+;; Maintainer: Eric Engstrom
+;; Keywords: spin, promela, tools
+
+;; Copyright (C) 1998-2003  Eric Engstrom / Honeywell Laboratories
+
+;; ... Possibly insert GPL here someday ...
+
+;;; Commentary:
+
+;;     This file contains code for a GNU Emacs major mode for editing
+;;     PROMELA (SPIN) program files.
+
+;;     Type "C-h m" in Emacs (while in a buffer in promela-mode) for
+;;     information on how to configure indentation and fontification,
+;;     or look at the configuration variables below.
+
+;;     To use, place promela-mode.el in a directory in your load-path.
+;;     Then, put the following lines into your .emacs and promela-mode
+;;     will be automatically loaded when editing a PROMELA program.
+
+;;     (autoload 'promela-mode "promela-mode" "PROMELA mode" nil t)
+;;     (setq auto-mode-alist
+;;           (append
+;;            (list (cons "\\.promela$"  'promela-mode)
+;;                  (cons "\\.spin$"     'promela-mode)
+;;                  (cons "\\.pml$"      'promela-mode)
+;;                  ;; (cons "\\.other-extensions$"     'promela-mode)
+;;                  )
+;;            auto-mode-alist))
+
+;;     If you wish for promela-mode to be used for files with other
+;;     extensions you add your own patterned after the code above.
+
+;;      Note that promela-mode adhears to the font-lock "standards" and
+;;      defines several "levels" of fontification or colorization.  The
+;;      default is fairly gaudy, so I can imagine that some folks would
+;;      like a bit less.  FMI: see `font-lock-maximum-decoration'
+
+;; This mode is known to work under the following versions of emacs:
+;;   - XEmacs:        19.16, 20.x, 21.x
+;;   - FSF/GNU Emacs: 19.34
+;;   - NTEmacs (FSF): 20.[67]
+;; That is not to say there are no bugs specific to one of those versions :-)
+
+;; Please send any comments, bugs, patches or other requests to
+;; Eric Engstrom at engstrom@htc.honeywell.com
+
+;; To-Do:
+;;  - compile/syntax-check/verify? (suggested by R.Goldman)
+;;  - indentation - splitting lines at logical operators (M. Rangarajan)
+;;    [ This might "devolve" to indentation after "->" or ";" 
+;;      being as is, but anything else indent even more? ]
+;;       :: SomeReallyLongArrayRef[this].typedefField != SomeReallyLongConstant -> /* some-comment */
+;;    [ Suggestion would be to break the first line after the !=, therefore: ]
+;;       :: SomeReallyLongArrayRef[this].typedefField 
+;;           != SomeReallyLongConstant -> /* some-comment */
+;;    [ at this point I'm not so sure about this change... EE: 2001/05/19 ] 
+\f
+;;; -------------------------------------------------------------------------
+;;; Code:
+
+;; NOTE: same as CVS revision:
+(defconst promela-mode-version "$Revision: 1.11 $"
+  "Promela-mode version number.")
+
+;; -------------------------------------------------------------------------
+;; The following constant values can be modified by the user in a .emacs file
+
+(defconst promela-block-indent 2
+  "*Controls indentation of lines within a block (`{') construct")
+
+(defconst promela-selection-indent 2
+  "*Controls indentation of options within a selection (`if')
+or iteration (`do') construct")
+
+(defconst promela-selection-option-indent 3
+  "*Controls indentation of lines after options within selection or
+iteration construct (`::')")
+
+(defconst promela-comment-col 32
+  "*Defines the desired comment column for comments to the right of text.")
+
+(defconst promela-tab-always-indent t
+  "*Non-nil means TAB in Promela mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used.")
+
+(defconst promela-auto-match-delimiter t
+  "*Non-nil means typing an open-delimiter (i.e. parentheses, brace, quote, etc)
+should also insert the matching closing delmiter character.")
+
+;; That should be about it for most users...
+;; unless you wanna hack elisp, the rest of this is probably uninteresting
+
+\f
+;; -------------------------------------------------------------------------
+;; help determine what emacs we have here...
+
+(defconst promela-xemacsp (string-match "XEmacs" (emacs-version))
+  "Non-nil if we are running in the XEmacs environment.")
+
+;;;(defconst promela-xemacs20p (and promela-xemacsp (>= emacs-major-version 20))
+;;  "Non-nil if we are running in an XEmacs environment version 20 or greater.")
+
+;; -------------------------------------------------------------------------
+;; promela-mode font faces/definitions
+
+;; make use of font-lock stuff, so say that explicitly
+(require 'font-lock)
+
+;; BLECH!  YUCK!   I just wish these guys could agree to something....
+;; Faces available in:         ntemacs emacs  xemacs xemacs xemacs    
+;;     font-lock- xxx -face     20.6   19.34  19.16   20.x   21.x
+;;       -builtin-                X                             
+;;       -constant-               X                             
+;;       -comment-                X      X      X      X      X
+;;       -doc-string-                           X      X      X
+;;       -function-name-          X      X      X      X      X
+;;       -keyword-                X      X      X      X      X
+;;       -preprocessor-                         X      X      X
+;;       -reference-                     X      X      X      X
+;;       -signal-name-                          X      X!20.0 
+;;       -string-                 X      X      X      X      X
+;;       -type-                   X      X      X      X      X
+;;       -variable-name-          X      X      X      X      X
+;;       -warning-                X                           X
+
+;;; Compatibility on faces between versions of emacs-en
+(unless promela-xemacsp
+
+  (defvar font-lock-preprocessor-face 'font-lock-preprocessor-face
+    "Face name to use for preprocessor statements.")
+  ;; For consistency try to define the preprocessor face == builtin face
+  (condition-case nil
+      (copy-face 'font-lock-builtin-face 'font-lock-preprocessor-face)
+    (error
+     (defface font-lock-preprocessor-face
+       '((t (:foreground "blue" :italic nil :underline t)))
+       "Face Lock mode face used to highlight preprocessor statements."
+       :group 'font-lock-highlighting-faces)))
+  
+  (defvar font-lock-reference-face 'font-lock-reference-face
+    "Face name to use for constants and reference and label names.")
+  ;; For consistency try to define the reference face == constant face
+  (condition-case nil
+      (copy-face 'font-lock-constant-face 'font-lock-reference-face)
+    (error
+     (defface font-lock-reference-face
+       '((((class grayscale) (background light))
+          (:foreground "LightGray" :bold t :underline t))
+         (((class grayscale) (background dark))
+          (:foreground "Gray50" :bold t :underline t))
+         (((class color) (background light)) (:foreground "CadetBlue"))
+         (((class color) (background dark)) (:foreground "Aquamarine"))
+         (t (:bold t :underline t)))
+       "Font Lock mode face used to highlight constancs, references and labels."
+       :group 'font-lock-highlighting-faces)))
+
+  )
+
+;; send-poll "symbol" face is custom to promela-mode 
+;; but check for existence to allow someone to override it
+(defvar promela-fl-send-poll-face 'promela-fl-send-poll-face
+  "Face name to use for Promela Send or Poll symbols: `!' or `?'")
+(copy-face (if promela-xemacsp 'modeline 'region)
+           'promela-fl-send-poll-face)
+
+;; some emacs-en don't define or have regexp-opt available.  
+(unless (functionp 'regexp-opt)
+  (defmacro regexp-opt (strings)
+    "Cheap imitation of `regexp-opt' since it's not availble in this emacs"
+    `(mapconcat 'identity ,strings "\\|")))
+  
+\f
+;; -------------------------------------------------------------------------
+;; promela-mode font lock specifications/regular-expressions
+;;   - for help, look at definition of variable 'font-lock-keywords
+;;   - some fontification ideas from -- [engstrom:20010309.1435CST]
+;;      Pat Tullman (tullmann@cs.utah.edu) and
+;;      Ny Aina Razermera Mamy (ainarazr@cs.uoregon.edu)
+;;     both had promela-mode's that I discovered after starting this one...
+;;     (but neither did any sort of indentation ;-)
+
+(defconst promela-font-lock-keywords-1 nil
+  "Subdued level highlighting for Promela mode.")
+
+(defconst promela-font-lock-keywords-2 nil
+  "Medium level highlighting for Promela mode.")
+
+(defconst promela-font-lock-keywords-3 nil
+  "Gaudy level highlighting for Promela mode.")
+
+;; set each of those three variables now..
+(let ((promela-keywords
+       (eval-when-compile 
+         (regexp-opt 
+          '("active" "assert" "atomic" "break" "d_step"
+            "do" "dproctype" "else" "empty" "enabled"
+            "eval" "fi" "full" "goto" "hidden" "if" "init"
+            "inline" "len" "local" "mtype" "nempty" "never"
+            "nfull" "od" "of" "pcvalue" "printf" "priority"
+            "proctype" "provided" "run" "show" "skip" 
+            "timeout" "trace" "typedef" "unless" "xr" "xs"))))
+      (promela-types
+       (eval-when-compile
+         (regexp-opt '("bit" "bool" "byte" "short"
+                       "int" "unsigned" "chan")))))
+
+  ;; really simple fontification (strings and comments come for "free")
+  (setq promela-font-lock-keywords-1
+    (list
+     ;; Keywords:
+     (cons (concat "\\<\\(" promela-keywords "\\)\\>")
+           'font-lock-keyword-face)
+     ;; Types:
+     (cons (concat "\\<\\(" promela-types "\\)\\>")
+           'font-lock-type-face)
+     ;; Special constants:
+     '("\\<_\\(np\\|pid\\|last\\)\\>" . font-lock-reference-face)))
+
+  ;; more complex fontification
+  ;; add function (proctype) names, lables and goto statements
+  ;; also add send/receive/poll fontification
+  (setq promela-font-lock-keywords-2
+   (append promela-font-lock-keywords-1
+    (list
+     ;; ANY Pre-Processor directive (lazy method: any line beginning with "#[a-z]+")
+     '("^\\(#[ \t]*[a-z]+\\)"          1 'font-lock-preprocessor-face t)
+
+     ;; "Functions" (proctype-s and inline-s)
+     (list (concat "\\<\\("
+                   (eval-when-compile
+                     (regexp-opt '("run" "dproctype" "proctype" "inline")))
+                   "\\)\\>[ \t]*\\(\\sw+\\)?")
+           ;;'(1 'font-lock-keyword-face nil)
+           '(2 'font-lock-function-name-face nil t))
+
+    ;; Labels and GOTO labels
+    '("^\\(\\sw+\\):" 1 'font-lock-reference-face)
+    '("\\<\\(goto\\)\\>[ \t]+\\(\\sw+\\)"
+      ;;(1 'font-lock-keyword-face nil)
+      (2 'font-lock-reference-face nil t))
+
+    ;; Send, Receive and Poll
+    '("\\(\\sw+\\)\\(\\[[^\\?!]+\\]\\)?\\(\\??\\?\\|!?!\\)\\(\\sw+\\)"
+      (1 'font-lock-variable-name-face nil t)
+      (3 'promela-fl-send-poll-face nil t)
+      (4 'font-lock-reference-face nil t)
+      )
+    )))
+
+  ;; most complex fontification
+  ;; add pre-processor directives, typed variables and hidden/typedef decls.
+  (setq promela-font-lock-keywords-3
+   (append promela-font-lock-keywords-2
+    (list
+     ;; ANY Pre-Processor directive (lazy method: any line beginning with "#[a-z]+")
+     ;;'("^\\(#[ \t]*[a-z]+\\)"                1 'font-lock-preprocessor-face t)
+     ;; "defined" in an #if or #elif and associated macro names
+     '("^#[ \t]*\\(el\\)?if\\>"
+       ("\\<\\(defined\\)\\>[ \t]*(?\\(\\sw+\\)" nil nil
+        (1 'font-lock-preprocessor-face nil t)
+        (2 'font-lock-reference-face nil t)))
+     '("^#[ \t]*ifn?def\\>"
+       ("[ \t]*\\(\\sw+\\)" nil nil
+        (1 'font-lock-reference-face nil t)))
+     ;; Filenames in #include <...> directives
+     '("^#[ \t]*include[ \t]+<\\([^>\"\n]+\\)>"        1 'font-lock-string-face nil t)
+     ;; Defined functions and constants/types (non-functions)
+     '("^#[ \t]*define[ \t]+"
+       ("\\(\\sw+\\)("                         nil nil (1 'font-lock-function-name-face nil t))
+       ("\\(\\sw+\\)[ \t]+\\(\\sw+\\)" nil nil (1 'font-lock-variable-name-face)
+                                                       (2 'font-lock-reference-face nil t))
+       ("\\(\\sw+\\)[^(]?"             nil nil (1 'font-lock-reference-face nil t)))
+
+     ;; Types AND variables
+     ;;   - room for improvement: (i.e. don't currently):
+     ;;     highlight user-defined types and asociated variable declarations
+     (list (concat "\\<\\(" promela-types "\\)\\>")
+          ;;'(1 'font-lock-type-face)
+          ;; now match the variables after the type definition, if any
+          '(promela-match-variable-or-declaration
+            nil nil
+            (1 'font-lock-variable-name-face) ;; nil t)
+            (2 font-lock-reference-face nil t)))
+    
+    ;; Typedef/hidden types and declarations
+    '("\\<\\(typedef\\|hidden\\)\\>[ \t]*\\(\\sw+\\)?"
+      ;;(1 'font-lock-keyword-face nil)
+      (2 'font-lock-type-face nil t)
+      ;; now match the variables after the type definition, if any
+      (promela-match-variable-or-declaration
+       nil nil
+       (1 'font-lock-variable-name-face nil t)
+       (2 'font-lock-reference-face nil t)))
+    )))
+  )
+
+(defvar promela-font-lock-keywords promela-font-lock-keywords-1
+  "Default expressions to highlight in Promela mode.")
+
+;; Font-lock matcher functions:
+(defun promela-match-variable-or-declaration (limit)
+  "Match, and move over, any declaration/definition item after point.
+Matches after point, but ignores leading whitespace characters.
+Does not move further than LIMIT.
+
+The expected syntax of a declaration/definition item is `word' (preceded
+by optional whitespace) optionally followed by a `= value' (preceded and
+followed by more optional whitespace)
+
+Thus the regexp matches after point:   word [ = value ]
+                                       ^^^^     ^^^^^
+Where the match subexpressions are:      1        2
+
+The item is delimited by (match-beginning 1) and (match-end 1).
+If (match-beginning 2) is non-nil, the item is followed by a `value'."
+  (when (looking-at "[ \t]*\\(\\sw+\\)[ \t]*=?[ \t]*\\(\\sw+\\)?[ \t]*,?")
+    (goto-char (min limit (match-end 0)))))
+
+\f
+;; -------------------------------------------------------------------------
+;; "install" promela-mode font lock specifications
+
+;; FMI: look up 'font-lock-defaults
+(defconst promela-font-lock-defaults
+  '(
+    (promela-font-lock-keywords 
+     promela-font-lock-keywords-1
+     promela-font-lock-keywords-2
+     promela-font-lock-keywords-3)               ;; font-lock stuff (keywords)
+    nil                                                  ;; keywords-only flag
+    nil                                                  ;; case-fold keyword searching
+    ;;((?_ . "w") (?$ . "."))                    ;; mods to syntax table
+    nil                                                  ;; mods to syntax table (see below)
+    nil                                                  ;; syntax-begin
+    (font-lock-mark-block-function . mark-defun))
+)
+
+;; "install" the font-lock-defaults based upon version of emacs we have
+(cond (promela-xemacsp
+       (put 'promela-mode 'font-lock-defaults promela-font-lock-defaults))
+      ((not (assq 'promela-mode font-lock-defaults-alist))
+       (setq font-lock-defaults-alist
+             (cons
+              (cons 'promela-mode promela-font-lock-defaults)
+              font-lock-defaults-alist))))
+
+\f
+;; -------------------------------------------------------------------------
+;; other promela-mode specific definitions
+
+(defconst promela-defun-prompt-regexp
+  "^[ \t]*\\(d?proctype\\|init\\|inline\\|never\\|trace\\|typedef\\|mtype\\s-+=\\)[^{]*"
+  "Regexp describing the beginning of a Promela top-level definition.")
+
+(defvar promela-mode-syntax-table nil
+  "Syntax table in use in PROMELA-mode buffers.")
+(if promela-mode-syntax-table
+    ()
+  (setq promela-mode-syntax-table (make-syntax-table))
+  (modify-syntax-entry ?\\ "\\"   promela-mode-syntax-table)
+  (modify-syntax-entry ?/  ". 14" promela-mode-syntax-table)
+  (modify-syntax-entry ?*  ". 23" promela-mode-syntax-table)
+  (modify-syntax-entry ?+  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?-  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?=  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?%  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?<  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?>  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?&  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?|  "."    promela-mode-syntax-table)
+  (modify-syntax-entry ?.  "_"    promela-mode-syntax-table)
+  (modify-syntax-entry ?_  "w"    promela-mode-syntax-table)
+  (modify-syntax-entry ?\' "\""   promela-mode-syntax-table)
+  )
+
+(defvar promela-mode-abbrev-table nil
+  "*Abbrev table in use in promela-mode buffers.")
+(if promela-mode-abbrev-table
+    nil
+  (define-abbrev-table 'promela-mode-abbrev-table
+    '(
+;; Commented out for now - need to think about what abbrevs make sense
+;;     ("assert"       "ASSERT"        promela-check-expansion 0)
+;;     ("d_step"       "D_STEP"        promela-check-expansion 0)
+;;     ("break"        "BREAK"         promela-check-expansion 0)
+;;     ("do"           "DO"            promela-check-expansion 0)
+;;     ("proctype"     "PROCTYPE"      promela-check-expansion 0)
+      )))
+
+(defvar promela-mode-map nil
+  "Keymap for promela-mode.")
+(if promela-mode-map
+    nil
+  (setq promela-mode-map (make-sparse-keymap))
+  (define-key promela-mode-map "\t"            'promela-indent-command)
+  (define-key promela-mode-map "\C-m"          'promela-newline-and-indent)
+  ;(define-key promela-mode-map 'backspace     'backward-delete-char-untabify)
+  (define-key promela-mode-map "\C-c\C-p"      'promela-beginning-of-block)
+  ;(define-key promela-mode-map "\C-c\C-n"     'promela-end-of-block)
+  (define-key promela-mode-map "\M-\C-a"       'promela-beginning-of-defun)
+  ;(define-key promela-mode-map "\M-\C-e"      'promela-end-of-defun)
+  (define-key promela-mode-map "\C-c("         'promela-toggle-auto-match-delimiter)
+  (define-key promela-mode-map "{"             'promela-open-delimiter)
+  (define-key promela-mode-map "}"             'promela-close-delimiter)
+  (define-key promela-mode-map "("             'promela-open-delimiter)
+  (define-key promela-mode-map ")"             'promela-close-delimiter)
+  (define-key promela-mode-map "["             'promela-open-delimiter)
+  (define-key promela-mode-map "]"             'promela-close-delimiter)
+  (define-key promela-mode-map ";"             'promela-insert-and-indent)
+  (define-key promela-mode-map ":"             'promela-insert-and-indent)
+  ;; 
+  ;; this is preliminary at best - use at your own risk:
+  (define-key promela-mode-map "\C-c\C-s"      'promela-syntax-check)
+  ;;
+  ;;(define-key promela-mode-map "\C-c\C-d"    'promela-mode-toggle-debug)
+  ;;(define-key promela-mode-map "\C-c\C-r"    'promela-mode-revert-buffer)
+  )
+
+(defvar promela-matching-delimiter-alist
+  '( (?(  . ?))
+     (?[  . ?])
+     (?{  . "\n}")
+     ;(?<  . ?>)
+     (?\' . ?\')
+     (?\` . ?\`)
+     (?\" . ?\") )
+  "List of pairs of matching open/close delimiters - for auto-insert")
+
+\f
+;; -------------------------------------------------------------------------
+;; Promela-mode itself
+
+(defun promela-mode ()
+  "Major mode for editing PROMELA code.
+\\{promela-mode-map}
+
+Variables controlling indentation style:
+  promela-block-indent
+       Relative offset of lines within a block (`{') construct.
+
+  promela-selection-indent
+       Relative offset of option lines within a selection (`if')
+       or iteration (`do') construct.
+
+  promela-selection-option-indent
+       Relative offset of lines after/within options (`::') within
+       selection or iteration constructs.
+
+  promela-comment-col
+       Defines the desired comment column for comments to the right of text.
+
+  promela-tab-always-indent
+       Non-nil means TAB in PROMELA mode should always reindent the current
+       line, regardless of where in the line the point is when the TAB
+       command is used.
+
+  promela-auto-match-delimiter
+       Non-nil means typing an open-delimiter (i.e. parentheses, brace,
+        quote, etc) should also insert the matching closing delmiter
+        character.
+
+Turning on PROMELA mode calls the value of the variable promela-mode-hook with
+no args, if that value is non-nil.
+
+For example: '
+       (setq promela-mode-hook '(lambda ()
+                       (setq promela-block-indent 2)
+                       (setq promela-selection-indent 0)
+                       (setq promela-selection-option-indent 2)
+                       (local-set-key \"\\C-m\" 'promela-indent-newline-indent)
+                       ))'
+
+will indent block two steps, will make selection options aligned with DO/IF
+and sub-option lines indent to a column after the `::'.  Also, lines will
+be reindented when you hit RETURN.
+
+Note that promela-mode adhears to the font-lock \"standards\" and
+defines several \"levels\" of fontification or colorization.  The
+default is fairly gaudy, so if you would prefer a bit less, please see
+the documentation for the variable: `font-lock-maximum-decoration'.
+"
+  (interactive)
+  (kill-all-local-variables)
+  (setq mode-name              "Promela")
+  (setq major-mode             'promela-mode)
+  (use-local-map               promela-mode-map)
+  (set-syntax-table            promela-mode-syntax-table)
+  (setq local-abbrev-table     promela-mode-abbrev-table)
+
+  ;; Make local variables
+  (make-local-variable 'case-fold-search)
+  (make-local-variable 'paragraph-start)
+  (make-local-variable 'paragraph-separate)
+  (make-local-variable 'paragraph-ignore-fill-prefix)
+  (make-local-variable 'indent-line-function)
+  (make-local-variable 'indent-region-function)
+  (make-local-variable 'parse-sexp-ignore-comments)
+  (make-local-variable 'comment-start)
+  (make-local-variable 'comment-end)
+  (make-local-variable 'comment-column)
+  (make-local-variable 'comment-start-skip)
+  (make-local-variable 'comment-indent-hook)
+  (make-local-variable 'defun-prompt-regexp)
+  (make-local-variable 'compile-command)
+  ;; Now set their values
+  (setq case-fold-search               t
+        paragraph-start                (concat "^$\\|" page-delimiter)
+        paragraph-separate             paragraph-start
+        paragraph-ignore-fill-prefix   t
+        indent-line-function           'promela-indent-command
+       ;;indent-region-function        'promela-indent-region
+        parse-sexp-ignore-comments     t
+        comment-start                  "/* "
+        comment-end                    " */"
+        comment-column                         32
+        comment-start-skip             "/\\*+ *"
+       ;;comment-start-skip            "/\\*+ *\\|// *"
+        ;;comment-indent-hook          'promela-comment-indent
+        defun-prompt-regexp            promela-defun-prompt-regexp
+        )
+
+  ;; Turn on font-lock mode
+  ;; (and promela-font-lock-mode (font-lock-mode))
+  (font-lock-mode)
+
+  ;; Finally, run the hooks and be done.
+  (run-hooks 'promela-mode-hook))
+
+\f
+;; -------------------------------------------------------------------------
+;; Interactive functions
+;;
+
+(defun promela-mode-version ()
+  "Print the current version of promela-mode in the minibuffer"
+  (interactive)
+  (message (concat "Promela-Mode: " promela-mode-version)))
+
+(defun promela-beginning-of-block ()
+  "Move backward to start of containing block.
+Containing block may be `{', `do' or `if' construct, or comment."
+  (interactive)
+  (goto-char (promela-find-start-of-containing-block-or-comment)))
+
+(defun promela-beginning-of-defun (&optional arg)
+  "Move backward to the beginning of a defun.
+With argument, do it that many times.
+Negative arg -N means move forward to Nth following beginning of defun.
+Returns t unless search stops due to beginning or end of buffer.
+
+See also 'beginning-of-defun.
+
+This is a Promela-mode specific version since default (in xemacs 19.16 and
+NT-Emacs 20) don't seem to skip comments - they will stop inside them.
+
+Also, this makes sure that the beginning of the defun is actually the
+line which starts the proctype/init/etc., not just the open-brace."
+  (interactive "p")
+  (beginning-of-defun arg)
+  (if (not (looking-at promela-defun-prompt-regexp))
+      (re-search-backward promela-defun-prompt-regexp nil t))
+  (if (promela-inside-comment-p)
+      (goto-char (promela-find-start-of-containing-comment))))
+
+(defun promela-indent-command ()
+  "Indent the current line as PROMELA code."
+  (interactive)
+  (if (and (not promela-tab-always-indent)
+           (save-excursion
+             (skip-chars-backward " \t")
+             (not (bolp))))
+      (tab-to-tab-stop)
+    (promela-indent-line)))
+
+(defun promela-newline-and-indent ()
+  "Promela-mode specific newline-and-indent which expands abbrevs before
+running a regular newline-and-indent."
+  (interactive)
+  (if abbrev-mode
+      (expand-abbrev))
+  (newline-and-indent))
+
+(defun promela-indent-newline-indent ()
+  "Promela-mode specific newline-and-indent which expands abbrevs and
+indents the current line before running a regular newline-and-indent."
+  (interactive)
+  (save-excursion (promela-indent-command))
+  (if abbrev-mode
+      (expand-abbrev))
+  (newline-and-indent))
+
+(defun promela-insert-and-indent ()
+  "Insert the last character typed and re-indent the current line"
+  (interactive)
+  (insert last-command-char)
+  (save-excursion (promela-indent-command)))
+
+(defun promela-open-delimiter ()
+  "Inserts the open and matching close delimiters, indenting as appropriate."
+  (interactive)
+  (insert last-command-char)
+  (if (and promela-auto-match-delimiter (not (promela-inside-comment-p)))
+      (save-excursion
+        (insert (cdr (assq last-command-char promela-matching-delimiter-alist)))
+        (promela-indent-command))))
+
+(defun promela-close-delimiter ()
+  "Inserts and indents a close delimiter."
+  (interactive)
+  (insert last-command-char)
+  (if (not (promela-inside-comment-p))
+      (save-excursion (promela-indent-command))))
+
+(defun promela-toggle-auto-match-delimiter ()
+  "Toggle auto-insertion of parens and other delimiters.
+See variable `promela-auto-insert-matching-delimiter'"
+  (interactive)
+  (setq promela-auto-match-delimiter
+        (not promela-auto-match-delimiter))
+  (message (concat "Promela auto-insert matching delimiters "
+                   (if promela-auto-match-delimiter
+                       "enabled" "disabled"))))
+
+\f
+;; -------------------------------------------------------------------------
+;; Compilation/Verification functions
+
+;; all of this is in serious "beta" mode - don't trust it ;-)
+(setq 
+        promela-compile-command                "spin "
+        promela-syntax-check-args      "-a -v "
+)
+
+;;(setq compilation-error-regexp-alist
+;;      (append compilation-error-regexp-alist
+;;              '(("spin: +line +\\([0-9]+\\) +\"\\([^\"]+\\)\"" 2 1))))
+
+(defun promela-syntax-check ()
+  (interactive)
+  (compile (concat promela-compile-command
+                   promela-syntax-check-args
+                   (buffer-name))))
+
+\f
+;; -------------------------------------------------------------------------
+;; Indentation support functions
+
+(defun promela-indent-around-label ()
+  "Indent the current line as PROMELA code,
+but make sure to consider the label at the beginning of the line."
+  (beginning-of-line)
+  (delete-horizontal-space)    ; delete any leading whitespace
+  (if (not (looking-at "\\sw+:\\([ \t]*\\)"))
+      (error "promela-indent-around-label: no label on this line")
+    (goto-char (match-beginning 1))
+    (let* ((space  (length (match-string 1)))
+           (indent (promela-calc-indent))
+           (wanted (max 0 (- indent (current-column)))))
+      (if (>= space wanted)
+          (delete-region (point) (+ (point) (- space wanted)))
+        (goto-char (+ (point) space))
+        (indent-to-column indent)))))
+
+;; Note that indentation is based ENTIRELY upon the indentation of the
+;; previous line(s), esp. the previous non-blank line and the line
+;; starting the current containgng block...
+(defun promela-indent-line ()
+  "Indent the current line as PROMELA code.
+Return the amount the by which the indentation changed."
+  (beginning-of-line)
+  (if (looking-at "[ \t]*\\sw+:")
+      (promela-indent-around-label)
+    (let ((indent (promela-calc-indent))
+          beg
+          shift-amt
+          (pos (- (point-max) (point))))
+      (setq beg (point))
+      (skip-chars-forward " \t")
+      (setq shift-amt (- indent (current-column)))
+      (if (zerop shift-amt)
+          (if (> (- (point-max) pos) (point))
+              (goto-char (- (point-max) pos)))
+        (delete-region beg (point))
+        (indent-to indent)
+        (if (> (- (point-max) pos) (point))
+            (goto-char (- (point-max) pos))))
+      shift-amt)))
+
+(defun promela-calc-indent ()
+  "Return the appropriate indentation for this line as an int."
+  (save-excursion
+    (beginning-of-line)
+    (let* ((orig-point  (point))
+           (state       (promela-parse-partial-sexp))
+           (paren-depth (nth 0 state))
+           (paren-point (or (nth 1 state) 1))
+           (paren-char  (char-after paren-point)))
+      ;;(what-cursor-position)
+      (cond
+       ;; Indent not-at-all - inside a string
+       ((nth 3 state)
+        (current-indentation))
+       ;; Indent inside a comment
+       ((nth 4 state)
+        (promela-calc-indent-within-comment))
+       ;; looking at a pre-processor directive - indent=0
+       ((looking-at "[ \t]*#\\(define\\|if\\(n?def\\)?\\|else\\|endif\\)")
+        0)
+       ;; If we're not inside a "true" block (i.e. "{}"), then indent=0
+       ;; I think this is fair, since no (indentable) code in promela
+       ;; exists outside of a proctype or similar "{ .. }" structure.
+       ((zerop paren-depth)
+        0)
+       ;; Indent relative to non curly-brace "paren"
+       ;; [ NOTE: I'm saving this, but don't use it any more.
+       ;;         Now, we let parens be indented like curly braces
+       ;;((and (>= paren-depth 1) (not (char-equal ?\{ paren-char)))
+       ;; (goto-char paren-point)
+       ;; (1+ (current-column)))
+       ;; 
+       ;; Last option: indent relative to contaning block(s)
+       (t
+        (goto-char orig-point)
+        (promela-calc-indent-within-block paren-point))))))
+
+(defun promela-calc-indent-within-block (&optional limit)
+  "Return the appropriate indentation for this line, assume within block.
+with optional arg, limit search back to `limit'"
+  (save-excursion
+    (let* ((stop        (or limit 1))
+           (block-point  (promela-find-start-of-containing-block stop))
+           (block-type   (promela-block-type-after block-point))
+           (indent-point (point))
+           (indent-type  (promela-block-type-after indent-point)))
+      (if (not block-type) 0
+        ;;(message "paren: %d (%d); block: %s (%d); indent: %s (%d); stop: %d"
+        ;;         paren-depth paren-point block-type block-point
+        ;;         indent-type indent-point stop)
+        (goto-char block-point)
+        (cond
+         ;; Indent (options) inside "if" or "do"
+         ((memq block-type '(selection iteration))
+          (if (re-search-forward "\\(do\\|if\\)[ \t]*::" indent-point t)
+              (- (current-column) 2)
+            (+ (current-column) promela-selection-indent)))
+         ;; indent (generic code) inside "::" option
+         ((eq 'option block-type)
+          (if (and (not indent-type)
+                   (re-search-forward "::.*->[ \t]*\\sw"
+                                      (save-excursion (end-of-line) (point))
+                                      t))
+              (1- (current-column))
+            (+ (current-column) promela-selection-option-indent))
+          )
+         ;; indent code inside "{"
+         ((eq 'block block-type)
+          (cond
+           ;; if we are indenting the end of a block,
+           ;; use indentation of start-of-block
+           ((equal 'block-end indent-type)
+            (current-indentation))
+           ;; if the start of the code inside the block is not at eol
+           ;; then indent to the same column as the block start +some
+           ;; [ but ignore comments after "{" ]
+           ((and (not (promela-effective-eolp (1+ (point))))
+                 (not (looking-at "{[ \t]*/\\*")))
+            (forward-char)             ; skip block-start
+            (skip-chars-forward "{ \t") ; skip whitespace, if any
+            (current-column))
+           ;; anything else we indent +promela-block-indent from
+           ;; the indentation of the start of block (where we are now)
+           (t
+            (+ (current-indentation)
+               promela-block-indent))))
+         ;; dunno what kind of block this is - sound an error
+         (t
+          (error "promela-calc-indent-within-block: unknown block type: %s" block-type)
+          (current-indentation)))))))
+
+(defun promela-calc-indent-within-comment ()
+  "Return the indentation amount for line, assuming that the
+current line is to be regarded as part of a block comment."
+  (save-excursion
+    (beginning-of-line)
+    (skip-chars-forward " \t")
+    (let ((indenting-end-of-comment (looking-at "\\*/"))
+          (indenting-blank-line (eolp)))
+      ;; if line is NOT blank and next char is NOT a "*'
+      (if (not (or indenting-blank-line (= (following-char) ?\*)))
+          ;; leave indent alone
+          (current-column)
+        ;; otherwise look back for _PREVIOUS_ possible nested comment start
+        (let ((comment-start (save-excursion 
+                               (re-search-backward comment-start-skip))))
+          ;; and see if there is an appropriate middle-comment "*"
+          (if (re-search-backward "^[ \t]+\\*" comment-start t)
+              (current-indentation)
+            ;; guess not, so indent relative to comment start
+            (goto-char comment-start)
+            (if indenting-end-of-comment
+                (current-column)
+              (1+ (current-column)))))))))
+
+\f
+;; -------------------------------------------------------------------------
+;; Misc other support functions
+
+(defun promela-parse-partial-sexp (&optional start limit)
+  "Return the partial parse state of current defun or from optional start
+to end limit"
+  (save-excursion
+    (let ((end (or limit (point))))
+      (if start
+          (goto-char start)
+        (promela-beginning-of-defun))
+      (parse-partial-sexp (point) end))))
+
+;;(defun promela-at-end-of-block-p ()
+;;  "Return t if cursor is at the end of a promela block"
+;;  (save-excursion
+;;    (let ((eol (progn (end-of-line) (point))))
+;;      (beginning-of-line)
+;;      (skip-chars-forward " \t")
+;;      ;;(re-search-forward "\\(}\\|\\b\\(od\\|fi\\)\\b\\)" eol t))))
+;;      (looking-at "[ \t]*\\(od\\|fi\\)\\b"))))
+
+(defun promela-inside-comment-p ()
+  "Check if the point is inside a comment block."
+  (save-excursion
+    (let ((origpoint (point))
+          state)
+      (goto-char 1)
+      (while (> origpoint (point))
+       (setq state (parse-partial-sexp (point) origpoint 0)))
+      (nth 4 state))))
+
+(defun promela-inside-comment-or-string-p ()
+  "Check if the point is inside a comment or a string."
+  (save-excursion
+    (let ((origpoint (point))
+          state)
+      (goto-char 1)
+      (while (> origpoint (point))
+       (setq state (parse-partial-sexp (point) origpoint 0)))
+      (or (nth 3 state) (nth 4 state)))))
+
+
+(defun promela-effective-eolp (&optional point)
+  "Check if we are at the effective end-of-line, ignoring whitespace"
+  (save-excursion
+    (if point (goto-char point))
+    (skip-chars-forward " \t")
+    (eolp)))
+
+(defun promela-check-expansion ()
+  "If abbrev was made within a comment or a string, de-abbrev!"
+  (if promela-inside-comment-or-string-p
+       (unexpand-abbrev)))
+
+(defun promela-block-type-after (&optional point)
+  "Return the type of block after current point or parameter as a symbol.
+Return one of 'iteration `do', 'selection `if', 'option `::',
+'block `{' or `}' or nil if none of the above match."
+  (save-excursion
+    (goto-char (or point (point)))
+    (skip-chars-forward " \t")
+    (cond
+     ((looking-at "do\\b") 'iteration)
+     ;;((looking-at "od\\b") 'iteration-end)
+     ((looking-at "if\\b") 'selection)
+     ;;((looking-at "fi\\b") 'selection-end)
+     ((looking-at "::") 'option)
+     ((looking-at "[{(]") 'block)
+     ((looking-at "[})]") 'block-end)
+     (t nil))))
+
+(defun promela-find-start-of-containing-comment (&optional limit)
+  "Return the start point of the containing comment block.
+Stop at `limit' or beginning of buffer."
+  (let ((stop (or limit 1)))
+    (save-excursion
+      (while (and (>= (point) stop)
+                  (nth 4 (promela-parse-partial-sexp)))
+        (re-search-backward comment-start-skip stop t))
+      (point))))
+
+(defun promela-find-start-of-containing-block (&optional limit)
+  "Return the start point of the containing `do', `if', `::' or
+`{' block or containing comment.
+Stop at `limit' or beginning of buffer."
+  (save-excursion
+    (skip-chars-forward " \t")
+    (let* ((type  (promela-block-type-after))
+           (stop  (or limit
+                      (save-excursion (promela-beginning-of-defun) (point))))
+           (state (promela-parse-partial-sexp stop))
+           (level (if (looking-at "\\(od\\|fi\\)\\b")
+                      2
+                    (if (zerop (nth 0 state)) 0 1))))
+      ;;(message "find-start-of-containing-block: type: %s; level %d; stop %d"
+      ;;         type level stop)
+      (while (and (> (point) stop) (not (zerop level)))
+       (re-search-backward
+             "\\({\\|}\\|::\\|\\b\\(do\\|od\\|if\\|fi\\)\\b\\)"
+             stop 'move)
+        ;;(message "looking from %d back-to %d" (point) stop)
+       (setq state (promela-parse-partial-sexp stop))
+       (setq level (+ level
+                       (cond ((or (nth 3 state) (nth 4 state))          0)
+                             ((and (= 1 level) (looking-at "::")
+                                   (not (equal type 'option)))         -1)
+                             ((looking-at "\\({\\|\\(do\\|if\\)\\b\\)") -1)
+                             ((looking-at "\\(}\\|\\(od\\|fi\\)\\b\\)") +1)
+                             (t 0)))))
+      (point))))
+
+(defun promela-find-start-of-containing-block-or-comment (&optional limit)
+  "Return the start point of the containing comment or
+the start of the containing `do', `if', `::' or `{' block.
+Stop at limit or beginning of buffer."
+  (if (promela-inside-comment-p)
+      (promela-find-start-of-containing-comment limit)
+    (promela-find-start-of-containing-block limit)))
+
+;; -------------------------------------------------------------------------
+;; Debugging/testing
+
+;; (defun promela-mode-toggle-debug ()
+;;   (interactive)
+;;   (make-local-variable 'debug-on-error)
+;;   (setq debug-on-error (not debug-on-error)))
+
+;;(defun promela-mode-revert-buffer ()
+;;  (interactive)
+;;  (revert-buffer t t))
+
+;; -------------------------------------------------------------------------
+;;###autoload
+
+(provide 'promela-mode)
+
+\f
+;;----------------------------------------------------------------------
+;; Change History:
+;;
+;; $Log: promela-mode.el,v $
+;; Revision 1.11  2001/07/09 18:36:45  engstrom
+;;  - added comments on use of font-lock-maximum-decoration
+;;  - moved basic preprocess directive fontification to "level 2"
+;;
+;; Revision 1.10  2001/05/22 16:29:59  engstrom
+;;  - fixed error introduced in fontification levels stuff (xemacs only)
+;;
+;; Revision 1.9  2001/05/22 16:21:29  engstrom
+;;  - commented out the compilation / syntax check stuff for now
+;;
+;; Revision 1.8  2001/05/22 16:18:49  engstrom
+;;  - Munched history in preparation for first non-Honeywell release
+;;  - Added "levels" of fontification to be controlled by the std. variable:
+;;      'font-lock-maximum-decoration'
+;;
+;; Revision 1.7  2001/04/20 01:41:46  engstrom
+;; Revision 1.6  2001/04/06 23:57:18  engstrom
+;; Revision 1.5  2001/04/04 20:04:15  engstrom
+;; Revision 1.4  2001/03/15 02:22:18  engstrom
+;; Revision 1.3  2001/03/09 19:39:51  engstrom
+;; Revision 1.2  2001/03/01 18:07:47  engstrom
+;; Revision 1.1  2001/02/01 xx:xx:xx  engstrom
+;;     migrated to CVS versioning...
+;; Pre-CVS-History:
+;;   99-10-04 V0.4 EDE        Fixed bug in end-of-block indentation
+;;                            Simplified indentation code significantly
+;;   99-09-2x V0.3 EDE        Hacked on indentation more while at FM'99
+;;   99-09-16 V0.2 EDE        Hacked, hacked, hacked on indentation
+;;   99-04-01 V0.1 EDE        Introduced (less-than) half-baked indentation
+;;   98-11-05 V0.0 EDE        Created - much code stolen from rexx-mode.el
+;;                            Mostly just a fontification mode -
+;;                            (indentation is HARD ;-)
+;;
+;; EOF promela-mode.el
This page took 0.032335 seconds and 4 git commands to generate.