Mercurial > hg > xemacs-beta
diff lisp/modes/verilog-mode.el @ 22:8fc7fe29b841 r19-15b94
Import from CVS: tag r19-15b94
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:50:29 +0200 |
parents | |
children | ec9a17fef872 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/modes/verilog-mode.el Mon Aug 13 08:50:29 2007 +0200 @@ -0,0 +1,3078 @@ +;;; verilog-mode.el --- major mode for editing verilog source in Emacs + +;; Copyright (C) 1996 Free Software Foundation, Inc. + +;; Author: Michael McNamara (mac@silicon-sorcery.com) +;; President, Silicon Sorcery +;; Keywords: languages + +;; This file is part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: + +;; $Header: /afs/informatik.uni-tuebingen.de/local/web/xemacs/xemacs-cvs/XEmacs/xemacs-19/lisp/modes/verilog-mode.el,v 1.1 1997/02/13 18:53:08 steve Exp $ +;; For help figuring out what to do with this file, visit +;; <http://www.silicon-sorcery.com/emacs_install.html> + +;; This mode borrows heavily from the pascal-mode and the cc-mode of emacs + +;; USAGE +;; ===== + +;; A major mode for editing Verilog HDL source code. When you have +;; entered Verilog mode, you may get more info by pressing C-h m. You +;; may also get online help describing various functions by: C-h f +;; <Name of function you want described> + +;; To set up automatic verilog mode, put this file in your load path, +;; and include stuff like this in your .emacs: + +;; (autoload 'verilog-mode "verilog-mode" "Verilog mode" t ) +;; (setq auto-mode-alist (cons '("\\.v\\'" . verilog-mode) auto-mode-alist)) +;; (setq auto-mode-alist (cons '("\\.dv\\'" . verilog-mode) auto-mode-alist)) + +;; If you want to customize Verilog mode to fit your needs better, +;; you may add these lines (the values of the variables presented +;; here are the defaults): +;; +;; ;; User customization for Verilog mode +;; (setq verilog-indent-level 3 +;; verilog-case-indent 2 +;; verilog-auto-newline t +;; verilog-auto-indent-on-newline t +;; verilog-tab-always-indent t +;; verilog-auto-endcomments t +;; verilog-minimum-comment-distance 40 +;; verilog-indent-begin-after-if t +;; verilog-auto-lineup '(all)) + +;; I've put in the common support for colored displays for older +;; emacs-19 behaviour, and newer emacs-19 behaviour, as well as +;; support for xemacs. After that, customizing according to your +;; particular emacs version is up to you. I've used the following +;; for emacs 19.27 and emacs 19.30; also xemacs seems to work for me +;; as well. I must caution that since the font-lock package doesn't +;; have a version number, I've had to key off the emacs version +;; number, which might not corrolate with the font-lock package you +;; happen to be using... + +;; Cut the following (From ";;;; - HERE - " to ";;;; - THERE -") and +;; place the text in your .emacs file. The delete all the single ; +;; at the beginning of the lines. + +;; (If you set the mark at the word HERE, (get cursor of the word +;; and type C-@) and point at word THERE, and then type C-u M-x +;; comment-region it will magically delete all the ; for you) + +;; As coded this should work for modern versions of emacs, and also +;; should be a basis where you could build from to get colors for +;; other modes. It owes a fair bit to the excellent sample.emacs +;; from Xemacs. + + +;; ;;; - HERE - +;;(defvar background-mode 'light) +;;(defvar display-type 'color) +;; ;; figure out background color. We could ask the user, but that would be too easy +;;(cond +;; ((and +;; (fboundp 'device-type) +;; (string= "x" (device-type))) +;; (setq display-type (device-class) +;; background-mode +;; (condition-case nil +;; (let ((bg-resource (x-get-resource ".backgroundMode" "BackgroundMode" 'string)) +;; (params (frame-parameters))) +;; (cond (bg-resource (intern (downcase bg-resource))) +;; ((and (cdr (assq 'background-color params)) +;; (< (apply '+ (x-color-values +;; (cdr (assq 'background-color params)))) +;; (/ (apply '+ (x-color-values "white")) 3))) +;; 'dark) +;; ((and (cdr (assq 'border-color params)) +;; (> (apply '+ (color-instance-rgb-components +;; (make-color-instance (cdr (assq 'border-color params))))) +;; (/ 255 3))) +;; 'dark) +;; (t 'light))) +;; (error 'light)) +;; ) +;; ) +;; ((and +;; (boundp 'window-system) +;; (string= window-system "x")) +;; (setq display-type +;; (condition-case nil +;; (let ((display-resource (x-get-resource ".displayType" "DisplayType"))) +;; (cond (display-resource (intern (downcase display-resource))) +;; ((x-display-color-p) 'color) +;; ((x-display-grayscale-p) 'grayscale) +;; (t 'mono))) +;; (error 'mono)) +;; ) +;; (setq background-mode +;; (condition-case nil +;; (let ((bg-resource (x-get-resource ".backgroundMode" +;; "BackgroundMode" )) +;; (params (frame-parameters))) +;; (cond (bg-resource (intern (downcase bg-resource))) +;; ((and (cdr (assq 'background-color params)) +;; (< (apply '+ (x-color-values +;; (cdr (assq 'background-color params)))) +;; (/ (apply '+ (x-color-values "white")) 3))) +;; 'dark) +;; ((and (fboundp 'color-instance-rgb-components ) +;; (cdr (assq 'border-color params)) +;; (> (apply '+ (color-instance-rgb-components +;; (make-color-instance (cdr (assq 'border-color params))))) +;; (/ 255 3))) +;; 'dark) +;; (t 'light))) +;; (error 'light)) +;; ) +;; )) + +;;(message "It appears you have a %s background" background-mode) + +;; ; Now do emacs version specific color setup +;;(cond +;; ((and (string-match "XEmacs" emacs-version) +;; (boundp 'emacs-major-version) +;; (= emacs-major-version 19) +;; (>= emacs-minor-version 12)) + +;; ;; If you want the default colors, you could do this: +;; ;; (setq font-lock-use-default-fonts nil) +;; ;; (setq font-lock-use-default-colors t) +;; ;; but I want to specify my own colors, so I turn off all +;; ;; default values. +;; (setq font-lock-use-default-fonts nil) +;; (setq font-lock-use-default-colors nil) +;; (require 'font-lock) + +;; ;; Mess around with the faces a bit. Note that you have +;; ;; to change the font-lock-use-default-* variables *before* +;; ;; loading font-lock, and wait till *after* loading font-lock +;; ;; to customize the faces. + +;; ;; (use copy-face instead of make-face-italic/make-face-bold because +;; ;; the startup code does intelligent things to the 'italic and 'bold +;; ;; faces to ensure that they are different from the default face. +;; ;; For example, if the default face is bold, then the 'bold face +;; ;; will be unbold.) +;; ;; Underling comments looks terrible on tty's +;; (set-face-underline-p 'font-lock-comment-face nil 'global 'tty) +;; (set-face-highlight-p 'font-lock-comment-face t 'global 'tty) + +;; (make-face-unitalic 'font-lock-comment-face) +;; (make-face-unitalic 'font-lock-string-face) +;; (copy-face 'bold 'font-lock-function-name-face) +;; (cond +;; ((eq background-mode 'light) +;; (set-face-foreground 'font-lock-comment-face "orchid") +;; (set-face-foreground 'font-lock-function-name-face "red") +;; (set-face-foreground 'font-lock-keyword-face "blue") +;; (set-face-foreground 'font-lock-string-face "steelblue") +;; (set-face-foreground 'font-lock-type-face "darkgreen") +;; ) +;; ((eq background-mode 'dark) +;; (set-face-foreground 'font-lock-comment-face "#efc80c") +;; (set-face-foreground 'font-lock-function-name-face "red") +;; (set-face-foreground 'font-lock-keyword-face "tan") +;; (set-face-foreground 'font-lock-string-face "lightskyblue") +;; (set-face-foreground 'font-lock-type-face "Aquamarine") +;; ) +;; ) +;; ;; misc. faces +;; (and (find-face 'font-lock-preprocessor-face) ; 19.13 and above +;; (copy-face 'bold 'font-lock-preprocessor-face)) +;; ) +;; ((> emacs-minor-version 29) +;; (if (eq background-mode 'light) +;; (setq font-lock-face-attributes +;; '( +;; (font-lock-comment-face "orchid" nil nil t nil) +;; (font-lock-function-name-face "red" nil t nil nil) +;; (font-lock-keyword-face "blue" nil nil nil nil) +;; (font-lock-reference-face "indianred" nil t nil nil ) +;; (font-lock-string-face "steelblue" nil nil nil nil) +;; (font-lock-type-face "darkgreen" nil nil nil nil) +;; (font-lock-variable-name-face "brown") +;; ) +;; ) +;; (setq font-lock-face-attributes +;; '( +;; (font-lock-comment-face "#efc80c" nil nil t nil) +;; (font-lock-function-name-face "red" nil t nil nil) +;; (font-lock-keyword-face "tan" nil nil nil nil) +;; (font-lock-reference-face "indianred" nil t nil nil ) +;; (font-lock-string-face "lightskyblue" nil nil nil nil) +;; (font-lock-type-face "Aquamarine" nil nil nil nil) +;; (font-lock-variable-name-face "LightGoldenrod") +;; ) +;; ) +;; ) +;; ) +;; (t +;; (if (eq background-mode 'dark) +;; (progn +;; (make-face 'my-font-lock-function-name-face) +;; (set-face-foreground 'my-font-lock-function-name-face "red") +;; (setq font-lock-function-name-face 'my-font-lock-function-name-face) + +;; (make-face 'my-font-lock-keyword-face) +;; (set-face-foreground 'my-font-lock-keyword-face "tan") +;; (setq font-lock-keyword-face 'my-font-lock-keyword-face) + +;; (make-face 'my-font-lock-string-face) +;; (set-face-foreground 'my-font-lock-string-face "lightskyblue") +;; (setq font-lock-string-face 'my-font-lock-string-face) + +;; (make-face 'my-font-lock-type-face) +;; (set-face-foreground 'my-font-lock-type-face "#efc80c") ; yellow +;; (setq font-lock-type-face 'my-font-lock-type-face) + +;; (make-face 'my-font-lock-variable-name-face) +;; (set-face-foreground 'my-font-lock-variable-name-face "LightGoldenrod") +;; (setq font-lock-variable-name-face 'my-font-lock-variable-name-face) +;; ) +;; (progn +;; (make-face 'my-font-lock-function-name-face) +;; (set-face-foreground 'my-font-lock-function-name-face "DarkGreen") +;; (setq font-lock-function-name-face 'my-font-lock-function-name-face) + +;; (make-face 'my-font-lock-keyword-face) +;; (set-face-foreground 'my-font-lock-keyword-face "indianred") +;; (setq font-lock-keyword-face 'my-font-lock-keyword-face) + +;; (make-face 'my-font-lock-string-face) +;; (set-face-foreground 'my-font-lock-string-face "RoyalBlue") +;; (setq font-lock-string-face 'my-font-lock-string-face) + +;; (make-face 'my-font-lock-type-face) +;; (set-face-foreground 'my-font-lock-type-face "#003800") ; yellow +;; (setq font-lock-type-face 'my-font-lock-type-face) + +;; (make-face 'my-font-lock-variable-name-face) +;; (set-face-foreground 'my-font-lock-variable-name-face "LightGoldenrod") +;; (setq font-lock-variable-name-face 'my-font-lock-variable-name-face) +;; ) +;; ) +;; ) +;; ) + +;;(cond +;; ((eq display-type 'color) +;; ;; Pretty Colors in source windows. +;; (require 'font-lock) +;; (autoload 'turn-on-fast-lock "fast-lock" +;; "Unconditionally turn on Fast Lock mode.") +;; (add-hook 'c-mode-hook 'font-lock-mode) +;; (add-hook 'verilog-mode-hook 'font-lock-mode) +;; (add-hook 'perl-mode-hook 'font-lock-mode) +;; (add-hook 'elisp-mode-hook 'font-lock-mode) +;; (add-hook 'asm-mode-hook 'font-lock-mode) +;; (setq fast-lock-cache-directories '("~/.backups" ".")) +;; (setq c-font-lock-keywords c-font-lock-keywords-2) +;; (setq c++-font-lock-keywords c++-font-lock-keywords-2) +;; (autoload 'verilog-make-faces "verilog-mode" "Set up faces for verilog") +;; (if (not (string-match "XEmacs" emacs-version)) +;; (progn +;; (cond +;; ((eq background-mode 'dark) +;; ;; Make background a light gray +;; (set-face-background (quote region) "gray30")) +;; ;; Make background a dark gray +;; ((eq background-mode 'light) +;; (set-face-background (quote region) "gray70")) +;; ) +;; ) +;; ) +;; ) +;; ((eq display-type 'mono) +;; (progn +;; ;; Frames are too expensive to create +;; ;; on my NCD running x-remote, which happens +;; ;; to be the only place I run X mono color +;; (setq vm-frame-per-composition nil +;; vm-frame-per-folder nil) +;; ) +;; ) +;; ) +;; ;;; - THERE - + +;; KNOWN BUGS / BUGREPORTS +;; ======================= This is beta code, and likely has +;; bugs. Please report any and all bugs to me at mac@silicon-sorcery.com. +;; + +;;; Code: + +(provide 'verilog-mode) + +;; This variable will always hold the version number of the mode +(defconst verilog-mode-version "$$Revision: 1.1 $$" + "Version of this verilog mode.") + +(defvar verilog-indent-level 3 + "*Indentation of Verilog statements with respect to containing block.") + +(defvar verilog-cexp-indent 1 + "*Indentation of Verilog statements split across lines.") + +(defvar verilog-case-indent 2 + "*Indentation for case statements.") + +(defvar verilog-auto-newline t + "*Non-nil means automatically newline after semicolons") + +(defvar verilog-auto-indent-on-newline t + "*Non-nil means automatically indent line after newline") + +(defvar verilog-tab-always-indent t + "*Non-nil means TAB in Verilog mode should always reindent the current line, +regardless of where in the line point is when the TAB command is used.") + +(defvar verilog-indent-begin-after-if t + "*If true, indent begin statements following if, else, while, for and repeat. +otherwise, line them up.") + +(defvar verilog-auto-endcomments t + "*Non-nil means a comment /* ... */ is set after the ends which ends cases and +functions. The name of the function or case will be set between the braces.") + +(defvar verilog-minimum-comment-distance 40 + "*Minimum distance between begin and end required before a comment will be inserted. +Setting this variable to zero results in every end aquiring a comment; the default avoids +too many redundanet comments in tight quarters") + +(defvar verilog-auto-lineup '(all) "*List of contexts where auto + lineup of :'s or ='s should be done. Elements can be of type: + 'declaration' or 'case', which will do auto lineup in declarations + or case-statements respectively. The word 'all' will do all + lineups. '(case declaration) for instance will do lineup in + case-statements and parameterlist, while '(all) will do all + lineups." ) + +(defvar verilog-mode-abbrev-table nil + "Abbrev table in use in Verilog-mode buffers.") + +(defvar verilog-font-lock-keywords-after-1930 + '( + ("^[ \t]*\\(function\\|task\\|module\\|macromodule\\|primitive\\)\\>[ \t]*" + 1 font-lock-keyword-face) + ("^[ \t]*\\(function\\|task\\|module\\|macromodule\\|primitive\\)\\>[ \t]*\\(\\sw+\\)" + 2 font-lock-function-name-face nil t) + ("\\\\[^ \t]*" 0 'font-lock-function-name-face) ( + "\\(@\\)\\|\\(#\[ \t\]*\\(\\(\[0-9\]+\\('[hdxbo][0-9_xz]*\\)?\\)\\|\\((\[^)\]*)\\)\\)\\)" + 0 font-lock-type-face) + ("\\(`[ \t]*[A-Za-z][A-Za-z0-9_]*\\)" 0 font-lock-type-face) + ("\\<\\(in\\(teger\\|put\\|out\\)\\|parameter\\|defparam\\|output\\|supply[01]?\\|event\\|tri\\(0\\|1\\|reg\\|and\\|or\\)?\\|w\\(ire\\|or\\|and\\)\\|time\\|re\\(al\\(time\\)?\\|g\\)\\)\\>" + 0 font-lock-type-face) + ("\\(\\$[a-zA-Z][a-zA-Z0-9_\\$]*\\)\\|\\(\\<\\(begin\\|case[xz]?\\|end\\(case\\|function\\|task\\|module\\|table\\|primitive\\|specify\\)?\\|a\\(ssign\\|lways\\)\\|default\\|initial\\|table\\|\\(pos\\|neg\\)edge\\|else\\|for\\(ever\\|k\\)?\\|join\\|if\\|repeat\\|then\\|while\\|specify\\)\\>\\)" + 0 font-lock-keyword-face) + ) +) +(defvar verilog-font-lock-keywords nil) +(defvar verilog-font-lock-keywords-before-1930 + '( + ("^[ \t]*\\(function\\|task\\|module\\|macromodule\\|primitive\\)\\>[ \t]*" . 1) + ("^[ \t]*\\(function\\|task\\|module\\|macromodule\\|primitive\\)\\>[ \t]*\\(\\sw+\\)" + 2 font-lock-function-name-face nil t) + ("\\(\\\\[^ \t]*\\)\\|\\(`[ \t]*[A-Za-z][A-Za-z0-9_]*\\)" 0 font-lock-function-name-face) + ("[@#]" . font-lock-type-face) + ("\\<\\(in\\(teger\\|put\\|out\\)\\|parameter\\|defparam\\|output\\|supply[01]?\\|event\\|tri\\(0\\|1\\|reg\\|and\\|or\\)?\\|w\\(ire\\|or\\|and\\)\\|time\\|re\\(al\\(time\\)?\\|g\\)\\)\\>" + 0 font-lock-type-face) + ("\\(\\$[a-zA-Z][a-zA-Z0-9_\\$]*\\)\\|\\(\\<\\(begin\\|case[xz]?\\|end\\(case\\|function\\|task\\|module\\|table\\|primitive\\|specify\\)?\\|a\\(ssign\\|lways\\)\\|default\\|initial\\|table\\|\\(pos\\|neg\\)edge\\|else\\|for\\(ever\\|k\\)?\\|join\\|if\\|repeat\\|then\\|while\\|specify\\)\\>\\)" . font-lock-keyword-face) + ) +) + +(defvar verilog-imenu-generic-expression + '("^[ \t]*\\(module\\|macromodule\\|primitive\\)[ \t\n]+\\([a-zA-Z0-9_.:]+\\)" . (2)) + "Imenu expression for Verilog-mode. See `imenu-generic-expression'.") + +(defvar verilog-mode-abbrev-table nil + "Abbrev table in use in Verilog-mode buffers.") + + +(define-abbrev-table 'verilog-mode-abbrev-table ()) + +(defvar verilog-mode-map () + "Keymap used in Verilog mode.") +(if verilog-mode-map + () + (setq verilog-mode-map (make-sparse-keymap)) + (define-key verilog-mode-map ";" 'electric-verilog-semi) + (define-key verilog-mode-map ":" 'electric-verilog-colon) + (define-key verilog-mode-map "=" 'electric-verilog-equal) + (define-key verilog-mode-map "\`" 'electric-verilog-tick) + (define-key verilog-mode-map "\t" 'electric-verilog-tab) + (define-key verilog-mode-map "\r" 'electric-verilog-terminate-line) + (define-key verilog-mode-map "\M-\C-b" 'electric-verilog-backward-sexp) + (define-key verilog-mode-map "\M-\C-f" 'electric-verilog-forward-sexp) + (define-key verilog-mode-map "\M-\r" (function (lambda () + (interactive) (electric-verilog-terminate-line 1)))) + (define-key verilog-mode-map "\177" 'backward-delete-char-untabify) + (define-key verilog-mode-map "\M-\t" 'verilog-complete-word) + (define-key verilog-mode-map "\M-?" 'verilog-show-completions) + (define-key verilog-mode-map "\M-\C-h" 'verilog-mark-defun) + (define-key verilog-mode-map "\C-c\C-b" 'verilog-insert-block) + (define-key verilog-mode-map "\C-cb" 'verilog-label-be) + (define-key verilog-mode-map "\M-*" 'verilog-star-comment) + (define-key verilog-mode-map "\C-c\C-c" 'verilog-comment-area) + (define-key verilog-mode-map "\C-c\C-u" 'verilog-uncomment-area) + (define-key verilog-mode-map "\M-\C-a" 'verilog-beg-of-defun) + (define-key verilog-mode-map "\M-\C-e" 'verilog-end-of-defun) + (define-key verilog-mode-map "\C-c\C-d" 'verilog-goto-defun) + ) + + + +;;; +;;; Regular expressions used to calculate indent, etc. +;;; +(defconst verilog-symbol-re "\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>") +(defconst verilog-case-re "\\(\\<case[xz]?\\>[^:]\\)") +;; Want to match +;; aa : +;; aa,bb : +;; a[34:32] : +;; a, +;; b : +(defconst verilog-no-indent-begin-re "\\<\\(if\\|else\\|while\\|for\\|repeat\\|always\\)\\>") +(defconst verilog-endcomment-reason-re + (concat + "\\(\\<fork\\>\\)\\|\\(\\<begin\\>\\)\\|\\(\\<if\\>\\)\\|\\(\\<else\\>\\)\\|" + "\\(\\<task\\>\\)\\|\\(\\<function\\>\\)\\|\\(\\<initial\\>\\)\\|\\(\\<always\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<while\\>\\)\\|\\(\\<for\\(ever\\)?\\>\\)\\|\\(\\<repeat\\>\\)\\|\\(\\<wait\\>\\)\\|" + "#")) + +(defconst verilog-named-block-re "begin[ \t]*:") +(defconst verilog-beg-block-re "\\<\\(begin\\|case\\|casex\\|casez\\|fork\\|table\\|specify\\)\\>") +(defconst verilog-beg-block-re-1 "\\<\\(begin\\)\\|\\(case[xz]?\\)\\|\\(fork\\)\\|\\(table\\)\\|\\(specify\\)\\|\\(function\\)\\|\\(task\\)\\>") +(defconst verilog-end-block-re "\\<\\(end\\|join\\|endcase\\|endtable\\|endspecify\\)\\>") +(defconst verilog-end-block-re-1 "\\(\\<end\\>\\)\\|\\(\\<endcase\\>\\)\\|\\(\\<join\\>\\)\\|\\(\\<endtable\\>\\)\\|\\(\\<endspecify\\>\\)\\|\\(\\<endfunction\\>\\)\\|\\(\\<endtask\\>\\)") +(defconst verilog-declaration-re + (concat "\\(\\<in\\(put\\|out\\|teger\\)\\>\\|" + "\\<parameter\\>\\|\\<defparam\\>\\|\\<output\\>\\|\\<event\\>\\|" + "\\<re\\(al\\|g\\|altime\\)\\>\\|" + "\\<time\\>\\|\\<tri\\(0\\|1\\|and\\|or\\|reg\\)?\\>\\|" + "\\<supply[01]\\>\\|\\<w\\(and\\|or\\|ire\\)\\>\\)")) +(defconst verilog-declaration-re-1 (concat "^[ \t]*" verilog-declaration-re "[ \t]*\\(\\[[^]]*\\][ \t]*\\)?")) +(defconst verilog-defun-re "\\<\\(module\\|macromodule\\|primitive\\)\\>") +(defconst verilog-end-defun-re "\\<\\(endmodule\\|endprimitive\\)\\>") +(defconst verilog-zero-indent-re + (concat verilog-defun-re "\\|" verilog-end-defun-re)) +(defconst verilog-directive-re + "\\(`else\\)\\|\\(`ifdef\\)\\|\\(`endif\\)\\|\\(`define\\)\\|\\(`undef\\)\\|\\(`include\\)") +(defconst verilog-autoindent-lines-re + (concat + "\\<\\(\\(macro\\)?module\\|primitive\\|end\\(case\\|function\\|task\\|module\\|primitive\\|specify\\|table\\)?\\|join\\|begin\\|else\\)\\>\\|`\\(else\\|ifdef\\|endif\\)\\|" + verilog-directive-re + "\\>")) +(defconst verilog-behavorial-block-beg-re + "\\(\\<initial\\>\\|\\<always\\>\\|\\<function\\>\\|\\<task\\>\\)") +(defconst verilog-indent-reg + (concat "\\(\\<begin\\>\\|\\<case[xz]?\\>[^:]\\|\\<specify\\>\\|\\<fork\\>\\|\\<table\\>\\)\\|" + "\\(\\<end\\>\\|\\<join\\>\\|\\<endcase\\>\\|\\<endtable\\>\\|\\<endspecify\\>\\)\\|" + "\\(\\<module\\>\\|\\<macromodule\\>\\|\\<primitive\\>\\|\\<initial\\>\\|\\<always\\>\\)\\|" + "\\(\\<endmodule\\>\\|\\<endprimitive\\>\\)\\|" + "\\(\\<endtask\\>\\|\\<endfunction\\>\\)\\|" + "\\(\\<function\\>\\|\\<task\\>\\)" +;; "\\|\\(\\<if\\>\\|\\<else\\>\\)" + )) +(defconst verilog-complete-reg + "\\(\\<always\\>\\)\\|\\(\\<repeat\\>\\)\\|\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<while\\>\\)\\|\\(\\<if\\>\\)\\|\\(\\<for\\(ever\\)?\\>\\)") +(defconst verilog-end-statement-re + (concat "\\(" verilog-beg-block-re "\\)\\|\\(" + verilog-end-block-re "\\)")) +(defconst verilog-endcase-re + (concat verilog-case-re "\\|" + "\\(endcase\\)\\|" + verilog-defun-re + )) +;;; Strings used to mark beginning and end of excluded text +(defconst verilog-exclude-str-start "/* -----\\/----- EXCLUDED -----\\/-----") +(defconst verilog-exclude-str-end " -----/\\----- EXCLUDED -----/\\----- */") + +(defconst verilog-emacs-features + (let ((major (and (boundp 'emacs-major-version) + emacs-major-version)) + (minor (and (boundp 'emacs-minor-version) + emacs-minor-version)) + flavor comments) + ;; figure out version numbers if not already discovered + (and (or (not major) (not minor)) + (string-match "\\([0-9]+\\).\\([0-9]+\\)" emacs-version) + (setq major (string-to-int (substring emacs-version + (match-beginning 1) + (match-end 1))) + minor (string-to-int (substring emacs-version + (match-beginning 2) + (match-end 2))))) + (if (not (and major minor)) + (error "Cannot figure out the major and minor version numbers.")) + ;; calculate the major version + (cond + ((= major 18) (setq major 'v18)) ;Emacs 18 + ((= major 4) (setq major 'v18)) ;Epoch 4 + ((= major 19) (setq major 'v19 ;Emacs 19 + flavor (if (or (string-match "Lucid" emacs-version) + (string-match "XEmacs" emacs-version)) + 'XEmacs 'FSF))) + ((= major 20) (setq major 'v20 ;XEmacs 20 + flavor 'XEmacs)) + ;; I don't know + (t (error "Cannot recognize major version number: %s" major))) + ;; All XEmacs 19's (formerly Lucid) use 8-bit modify-syntax-entry + ;; flags, as do all patched (obsolete) Emacs 19, Emacs 18, + ;; Epoch 4's. Only vanilla Emacs 19 uses 1-bit flag. Lets be + ;; as smart as we can about figuring this out. + (if (or (eq major 'v20) (eq major 'v19)) + (let ((table (copy-syntax-table))) + (modify-syntax-entry ?a ". 12345678" table) + (cond + ;; XEmacs pre 20 and Emacs pre 19.30 use vectors for syntax tables. + ((vectorp table) + (if (= (logand (lsh (aref table ?a) -16) 255) 255) + (setq comments '8-bit) + (setq comments '1-bit))) + ;; XEmacs 20 is known to be 8-bit + ((eq flavor 'XEmacs) (setq comments '8-bit)) + ;; Emacs 19.30 and beyond are known to be 1-bit + ((eq flavor 'FSF) (setq comments '1-bit)) + ;; Don't know what this is + (t (error "Couldn't figure out syntax table format.")) + )) + ;; Emacs 18 has no support for dual comments + (setq comments 'no-dual-comments)) + ;; lets do some minimal sanity checking. + (if (or + ;; Lemacs before 19.6 had bugs + (and (eq major 'v19) (eq flavor 'XEmacs) (< minor 6)) + ;; Emacs 19 before 19.21 has known bugs + (and (eq major 'v19) (eq flavor 'FSF) (< minor 21)) + ) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "The version of Emacs that you are running, %s, +has known bugs in its syntax parsing routines which will affect the +performance of verilog-mode. You should strongly consider upgrading to the +latest available version. verilog-mode may continue to work, after a +fashion, but strange indentation errors could be encountered." + emacs-version)))) + ;; Emacs 18, with no patch is not too good + (if (and (eq major 'v18) (eq comments 'no-dual-comments)) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "The version of Emacs 18 you are running, %s, +has known deficiencies in its ability to handle the dual verilog +(and C++) comments, (e.g. the // and /* */ comments). This will +not be much of a problem for you if you only use the /* */ comments, +but you really should strongly consider upgrading to one of the latest +Emacs 19's. In Emacs 18, you may also experience performance degradations. +Emacs 19 has some new built-in routines which will speed things up for you. +Because of these inherent problems, verilog-mode is not supported +on emacs-18." + emacs-version)))) + ;; Emacs 18 with the syntax patches are no longer supported + (if (and (eq major 'v18) (not (eq comments 'no-dual-comments))) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "You are running a syntax patched Emacs 18 variant. While this should +work for you, you may want to consider upgrading to Emacs 19. +The syntax patches are no longer supported either for verilog-mode.")))) + (list major comments)) + "A list of features extant in the Emacs you are using. +There are many flavors of Emacs out there, each with different +features supporting those needed by verilog-mode. Here's the current +supported list, along with the values for this variable: + + Vanilla Emacs 18/Epoch 4: (v18 no-dual-comments) + Emacs 18/Epoch 4 (patch2): (v18 8-bit) + XEmacs (formerly Lucid) 19: (v19 8-bit) + Emacs 19: (v19 1-bit).") + +(defconst verilog-comment-start-regexp "//\\|/\\*" + "Dual comment value for `comment-start-regexp'.") + +(defun verilog-populate-syntax-table (table) + ;; Populate the syntax TABLE + ;; DO NOT TRY TO SET _ (UNDERSCORE) TO WORD CLASS! + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?_ "w" table) + (modify-syntax-entry ?\' "." table) +) + +(defun verilog-setup-dual-comments (table) + ;; Set up TABLE to handle block and line style comments + (cond + ((memq '8-bit verilog-emacs-features) + ;; XEmacs (formerly Lucid) has the best implementation + (modify-syntax-entry ?/ ". 1456" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + ;; Give CR the same syntax as newline, for selective-display + (modify-syntax-entry ?\^m "> b" table)) + ((memq '1-bit verilog-emacs-features) + ;; Emacs 19 does things differently, but we can work with it + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + ;; Give CR the same syntax as newline, for selective-display + (modify-syntax-entry ?\^m "> b" table)) + )) + +(defvar verilog-mode-syntax-table nil + "Syntax table used in verilog-mode buffers.") +(if verilog-mode-syntax-table + () + (setq verilog-mode-syntax-table (make-syntax-table)) + (verilog-populate-syntax-table verilog-mode-syntax-table) + ;; add extra comment syntax + (verilog-setup-dual-comments verilog-mode-syntax-table) + ) +;;; +;;; Macros +;;; + +(defsubst verilog-re-search-forward (REGEXP BOUND NOERROR) + "Like re-search-forward, but skips over matches in comments or strings" + (set-match-data '(nil nil)) + (while (and + (re-search-forward REGEXP BOUND NOERROR) + (and (verilog-skip-forward-comment-or-string) + (progn + (store-match-data '(nil nil)) + (if BOUND + (< (point) BOUND) + t) + ) + ) + ) + ) + (match-end 0)) + +(defsubst verilog-re-search-backward (REGEXP BOUND NOERROR) + "Like re-search-backward, but skips over matches in comments or strings" + (set-match-data '(nil nil)) + (while (and + (re-search-backward REGEXP BOUND NOERROR) + (verilog-skip-backward-comment-or-string) + (not (set-match-data '(nil nil)))) + ()) + (match-end 0)) + +(defsubst verilog-get-beg-of-line (&optional arg) + (save-excursion + (beginning-of-line arg) + (point))) + +(defsubst verilog-get-end-of-line (&optional arg) + (save-excursion + (end-of-line arg) + (point))) + +(defun verilog-declaration-end () + (search-forward ";")) + +(defun electric-verilog-backward-sexp () + "Move backward over a sexp" + (interactive) + ;; before that see if we are in a comment + (verilog-backward-sexp) +) +(defun electric-verilog-forward-sexp () + "Move backward over a sexp" + (interactive) + ;; before that see if we are in a comment + (verilog-forward-sexp) +) + +(defun verilog-backward-sexp () + (let ((reg) + (elsec 1) + (found nil) + ) + (if (not (looking-at "\\<")) + (forward-word -1)) + (cond + ((verilog-skip-backward-comment-or-string) + ) + ((looking-at "\\<else\\>") + (setq reg (concat + verilog-end-block-re + "\\|\\(\\<else\\>\\)" + "\\|\\(\\<if\\>\\)" + )) + (while (and (not found) + (verilog-re-search-backward reg nil 'move)) + (cond + ((match-end 1) ; endblock + ; try to leap back to matching outward block by striding across + ; indent level changing tokens then immediately + ; previous line governs indentation. + (verilog-leap-to-head) + ) + ((match-end 2) ; else, we're in deep + (setq elsec (1+ elsec)) + ) + ((match-end 3) ; found it + (setq elsec (1- elsec)) + (if (= 0 elsec) + ;; Now previous line describes syntax + (setq found 't) + )) + ) + ) + ) + ((looking-at verilog-end-block-re-1);; end|join|endcase|endtable|endspecify + (verilog-leap-to-head) + ) + ((looking-at "\\(endmodule\\>\\)\\|\\(\\<endprimitive\\>\\)") + (cond + ((match-end 1) + (verilog-re-search-backward "\\<\\(macro\\)?module\\>" nil 'move)) + ((match-end 2) + (verilog-re-search-backward "\\<primitive\\>" nil 'move)) + (t + (backward-sexp 1)))) + (t + (backward-sexp)) + ) ;; cond + ) + ) +(defun verilog-forward-sexp () + (let ((reg) + (st (point))) + (if (not (looking-at "\\<")) + (forward-word -1)) + (cond + ((verilog-skip-forward-comment-or-string) + (verilog-forward-syntactic-ws) + ) + ((looking-at verilog-beg-block-re-1);; begin|fork|case|table|specify + (cond + ((match-end 1) ; end + ;; Search forward for matching begin + (setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" ) + ) + ((match-end 2) ; endcase + ;; Search forward for matching case + (setq reg "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" ) + ) + ((match-end 3) ; join + ;; Search forward for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" ) + ) + ((match-end 4) ; endtable + ;; Search forward for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" ) + ) + ((match-end 5) ; endspecify + ;; Search forward for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" ) + ) + ((match-end 6) ; endfunction + ;; Search forward for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" ) + ) + ((match-end 7) ; endspecify + ;; Search forward for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" ) + ) + ) + (if (forward-word 1) + (catch 'skip + (let ((nest 1)) + (while (verilog-re-search-forward reg nil 'move) + (cond + ((match-end 2) ; end + (setq nest (1- nest)) + (if (= 0 nest) + (throw 'skip 1))) + ((match-end 1) ; begin + (setq nest (1+ nest))))) + ) + ) + ) + ) + ((looking-at "\\(\\<\\(macro\\)?module\\>\\)\\|\\(\\<primitive\\>\\)") + (cond + ((match-end 1) + (verilog-re-search-forward "\\<endmodule\\>" nil 'move)) + ((match-end 2) + (verilog-re-search-forward "\\<endprimitive\\>" nil 'move)) + (t + (goto-char st) + (if (= (following-char) ?\) ) + (forward-char 1) + (forward-sexp 1))))) + (t + (goto-char st) + (if (= (following-char) ?\) ) + (forward-char 1) + (forward-sexp 1))) + ) ;; cond + ) + ) + + +(defun verilog-declaration-beg () + (verilog-re-search-backward verilog-declaration-re (bobp) t)) + +(defsubst verilog-within-string () + (save-excursion + (nth 3 (parse-partial-sexp (verilog-get-beg-of-line) (point))))) + + +;;;###autoload +(defun verilog-mode () +"Major mode for editing Verilog code. \\<verilog-mode-map> +NEWLINE, TAB indents for Verilog code. +Delete converts tabs to spaces as it moves back. +Supports highlighting. + +Variables controlling indentation/edit style: + + verilog-indent-level (default 3) + Indentation of Verilog statements with respect to containing block. + verilog-cexp-indent (default 1) + Indentation of Verilog statements broken across lines. + verilog-case-indent (default 2) + Indentation for case statements. + verilog-auto-newline (default nil) + Non-nil means automatically newline after simcolons and the punctation mark + after an end. + verilog-auto-indent-on-newline (default t) + Non-nil means automatically indent line after newline + verilog-tab-always-indent (default t) + Non-nil means TAB in Verilog mode should always reindent the current line, + regardless of where in the line point is when the TAB command is used. + verilog-indent-begin-after-if (default t) + Non-nil means to indent begin statements following a preceeding + if, else, while, for and repeat statements, if any. otherwise, + the begin is lined up with the preceeding token. If t, you get: + if (a) + begin + otherwise you get: + if (a) + begin + verilog-auto-endcomments (default t) + Non-nil means a comment /* ... */ is set after the ends which ends cases, tasks, functions and modules. + The type and name of the object will be set between the braces. + verilog-auto-lineup (default `(all)) + List of contexts where auto lineup of :'s or ='s should be done. + +Turning on Verilog mode calls the value of the variable verilog-mode-hook with +no args, if that value is non-nil. +Other useful functions are: +\\[verilog-complete-word]\t-complete word with appropriate possibilities (functions, verilog keywords...) +\\[verilog-comment-area]\t- Put marked area in a comment, fixing nested comments. +\\[verilog-uncomment-area]\t- Uncomment an area commented with \ +\\[verilog-comment-area]. +\\[verilog-insert-block]\t- insert begin ... end; +\\[verilog-star-comment]\t- insert /* ... */ +\\[verilog-mark-defun]\t- Mark function. +\\[verilog-beg-of-defun]\t- Move to beginning of current function. +\\[verilog-end-of-defun]\t- Move to end of current function. +\\[verilog-label-be]\t- Label matching begin ... end, fork ... join and case ... endcase statements; +" + (interactive) + (kill-all-local-variables) + (use-local-map verilog-mode-map) + (setq major-mode 'verilog-mode) + (setq mode-name "Verilog") + (setq local-abbrev-table verilog-mode-abbrev-table) + (set-syntax-table verilog-mode-syntax-table) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'verilog-indent-line) + (setq comment-indent-function 'verilog-indent-comment) + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments nil) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-multi-line) + (make-local-variable 'comment-start-skip) + (setq comment-start "// " + comment-end "" + comment-start-skip "/\\*+ *\\|// *" + comment-multi-line nil) + ;; Imenu support + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression verilog-imenu-generic-expression) + ;; Font lock support + (make-local-variable 'font-lock-keywords) + (if (string-match "XEmacs\\|Lucid" emacs-version) + (setq verilog-font-lock-keywords verilog-font-lock-keywords-after-1930 ) + (cond ((> emacs-minor-version 29) + (setq verilog-font-lock-keywords verilog-font-lock-keywords-after-1930 )) + ('t + (setq verilog-font-lock-keywords verilog-font-lock-keywords-before-1930 )) + )) + (setq font-lock-keywords verilog-font-lock-keywords) + (run-hooks 'verilog-mode-hook)) + + +;;; +;;; Electric functions +;;; +(defun electric-verilog-terminate-line (&optional arg) + "Terminate line and indent next line." + (interactive) + ;; before that see if we are in a comment + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ; Inside // comment + (if (eolp) + (progn + (delete-horizontal-space) + (newline)) + (progn + (newline) + (insert-string "// ") + (beginning-of-line) + )) + (verilog-indent-line) + ) + ((nth 4 state) ; Inside any comment (hence /**/) + (newline) + (beginning-of-line) + + (verilog-indent-comment t) + (insert-string "* ") + ) + ((eolp) + ;; First, check if current line should be indented + (if (save-excursion + (delete-horizontal-space) + (beginning-of-line) + (skip-chars-forward " \t") + (if (looking-at verilog-autoindent-lines-re) + (let ((indent-str (verilog-indent-line))) + ;; Maybe we should set some endcomments + (if verilog-auto-endcomments + (verilog-set-auto-endcomments indent-str arg)) + (end-of-line) + (delete-horizontal-space) + (if arg + () + (newline)) + nil) + (progn + (end-of-line) + (delete-horizontal-space) + (newline)))) + (newline) + (forward-line 1)) + ;; Indent next line + (if verilog-auto-indent-on-newline + (verilog-indent-line)) + ) + (t + (newline) + ) + ) + ) + ) + +(defun electric-verilog-semi () + "Insert `;' character and reindent the line." + (interactive) + (insert last-command-char) + (save-excursion + (beginning-of-line) + (verilog-indent-line)) + (if (and verilog-auto-newline + (= 0 (verilog-parenthesis-depth))) + (electric-verilog-terminate-line))) + +(defun electric-verilog-colon () + "Insert `:' and do all indentions except line indent on this line." + (interactive) + (insert last-command-char) + ;; Do nothing if within string. + (if (or + (verilog-within-string) + (not (verilog-in-case-region-p))) + () + (save-excursion + (let ((p (point)) + (lim (progn (verilog-beg-of-statement) (point)))) + (goto-char p) + (verilog-backward-case-item lim) + (verilog-indent-line))) +;; (let ((verilog-tab-always-indent nil)) +;; (verilog-indent-line)) + ) + ) + +(defun electric-verilog-equal () + "Insert `=', and do indention if within block." + (interactive) + (insert last-command-char) +;; Could auto line up expressions, but not yet +;; (if (eq (car (verilog-calculate-indent)) 'block) +;; (let ((verilog-tab-always-indent nil)) +;; (verilog-indent-command))) +) + + +(defun electric-verilog-tick () + "Insert back-tick, and indent to coulmn 0 if this is a CPP directive." + (interactive) + (insert last-command-char) + (if (save-excursion (beginning-of-line) (looking-at "^[ \t]*\`\\(\\<ifdef\\>\\|\\\<else\\>\\|\\<endif\\>\\|\\<define\\>\\)")) + (save-excursion (beginning-of-line) + (delete-horizontal-space)))) + +(defun electric-verilog-tab () + "Function called when TAB is pressed in Verilog mode." + (interactive) + ;; If verilog-tab-always-indent, indent the beginning of the line. + (if verilog-tab-always-indent + (let* ((boi-point (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (let (type state ) + (setq type (verilog-indent-line)) + (setq state (car type)) + (cond + ((eq state 'block) + (if (looking-at verilog-behavorial-block-beg-re ) + (error (concat "The reserved word \"" + (buffer-substring (match-beginning 0) (match-end 0)) + "\" must be at the behavorial level!")))) + )) + (back-to-indentation) + (point)))) + (if (< (point) boi-point) + (back-to-indentation))) + (progn (insert "\t")) + ) + ) + + + +;;; +;;; Interactive functions +;;; +(defun verilog-insert-block () + "Insert Verilog begin ... end; block in the code with right indentation." + (interactive) + (verilog-indent-line) + (insert "begin") + (electric-verilog-terminate-line) + (save-excursion + (electric-verilog-terminate-line) + (insert "end") + (beginning-of-line) + (verilog-indent-line))) + +(defun verilog-star-comment () + "Insert Verilog star comment at point." + (interactive) + (verilog-indent-line) + (insert "/*") + (save-excursion + (newline) + (insert " */")) + (newline) + (insert " * ")) + +(defun verilog-mark-defun () + "Mark the current verilog function (or procedure). +This puts the mark at the end, and point at the beginning." + (interactive) + (push-mark (point)) + (verilog-end-of-defun) + (push-mark (point)) + (verilog-beg-of-defun) + (if (fboundp 'zmacs-activate-region) + (zmacs-activate-region))) + +(defun verilog-comment-area (start end) + "Put the region into a Verilog comment. +The comments that are in this area are \"deformed\": +`*)' becomes `!(*' and `}' becomes `!{'. +These deformed comments are returned to normal if you use +\\[verilog-uncomment-area] to undo the commenting. + +The commented area starts with `verilog-exclude-str-start', and ends with +`verilog-include-str-end'. But if you change these variables, +\\[verilog-uncomment-area] won't recognize the comments." + (interactive "r") + (save-excursion + ;; Insert start and endcomments + (goto-char end) + (if (and (save-excursion (skip-chars-forward " \t") (eolp)) + (not (save-excursion (skip-chars-backward " \t") (bolp)))) + (forward-line 1) + (beginning-of-line)) + (insert verilog-exclude-str-end) + (setq end (point)) + (newline) + (goto-char start) + (beginning-of-line) + (insert verilog-exclude-str-start) + (newline) + ;; Replace end-comments within commented area + (goto-char end) + (save-excursion + (while (re-search-backward "\\*/" start t) + (replace-match "!/*" t t))) + ) +) + +(defun verilog-uncomment-area () + "Uncomment a commented area; change deformed comments back to normal. +This command does nothing if the pointer is not in a commented +area. See also `verilog-comment-area'." + (interactive) + (save-excursion + (let ((start (point)) + (end (point))) + ;; Find the boundaries of the comment + (save-excursion + (setq start (progn (search-backward verilog-exclude-str-start nil t) + (point))) + (setq end (progn (search-forward verilog-exclude-str-end nil t) + (point)))) + ;; Check if we're really inside a comment + (if (or (equal start (point)) (<= end (point))) + (message "Not standing within commented area.") + (progn + ;; Remove endcomment + (goto-char end) + (beginning-of-line) + (let ((pos (point))) + (end-of-line) + (delete-region pos (1+ (point)))) + ;; Change comments back to normal + (save-excursion + (while (re-search-backward "!/\\*" start t) + (replace-match "*/" t t))) + ;; Remove startcomment + (goto-char start) + (beginning-of-line) + (let ((pos (point))) + (end-of-line) + (delete-region pos (1+ (point))))))))) + +(defun verilog-beg-of-defun () + "Move backward to the beginning of the current function or procedure." + (interactive) + (verilog-re-search-backward verilog-defun-re nil 'move) + ) +(defun verilog-end-of-defun () + (interactive) + (verilog-re-search-forward verilog-end-defun-re nil 'move) + ) + +(defun verilog-label-be (&optional arg) + "Label matching begin ... end, fork ... join and case ... endcase statements in this module; +With argument, first kill any existing labels." + (interactive) + (let ((cnt 0) + (oldpos (point)) + (b (progn + (verilog-beg-of-defun) + (point-marker))) + (e (progn + (verilog-end-of-defun) + (point-marker))) + ) + (goto-char (marker-position b)) + (if (> (- e b) 200) + (message "Relabeling module...")) + (while (and + (> (marker-position e) (point)) + (verilog-re-search-forward + (concat + "\\<end\\(\\(function\\)\\|\\(task\\)\\|\\(module\\)\\|\\(primitive\\)\\|\\(case\\)\\)?\\>" + "\\|\\(`endif\\)\\|\\(`else\\)") + nil 'move)) + (goto-char (match-beginning 0)) + (let ((indent-str (verilog-indent-line))) + (verilog-set-auto-endcomments indent-str 't) + (end-of-line) + (delete-horizontal-space) + ) + (setq cnt (1+ cnt)) + (if (= 9 (% cnt 10)) + (message "%d..." cnt)) + ) + (goto-char oldpos) + (if (or + (> (- e b) 200) + (> cnt 20)) + (message "%d lines autocommented" cnt)) + ) + ) + +(defun verilog-beg-of-statement () + "Move backward to beginning of statement" + (interactive) + (while (save-excursion + (and + (not (looking-at verilog-complete-reg)) + (skip-chars-backward " \t") + (not (or (bolp) (= (preceding-char) ?\;))) + ) + ) + (skip-chars-backward " \t") + (verilog-backward-token)) + (let ((last (point))) + (while (progn + (setq last (point)) + (and (not (looking-at verilog-complete-reg)) + (verilog-continued-line)))) + (goto-char last) + (verilog-forward-syntactic-ws) + ) + ) +(defun verilog-end-of-statement () + "Move forward to end of current statement." + (interactive) + (let ((nest 0) pos) + (if (not (looking-at "[ \t\n]")) (forward-sexp -1)) + (or (looking-at verilog-beg-block-re) + ;; Skip to end of statement + (setq pos (catch 'found + (while t + (forward-sexp 1) + (verilog-skip-forward-comment-or-string) + (cond ((looking-at "[ \t]*;") + (skip-chars-forward "^;") + (forward-char 1) + (throw 'found (point))) + ((save-excursion + (forward-sexp -1) + (looking-at verilog-beg-block-re)) + (goto-char (match-beginning 0)) + (throw 'found nil)) + ((eobp) + (throw 'found (point)))))))) + (if (not pos) + ;; Skip a whole block + (catch 'found + (while t + (verilog-re-search-forward verilog-end-statement-re nil 'move) + (setq nest (if (match-end 1) + (1+ nest) + (1- nest))) + (cond ((eobp) + (throw 'found (point))) + ((= 0 nest) + (throw 'found (verilog-end-of-statement)))))) + pos))) +(defun verilog-in-case-region-p () + "Return TRUE if in a case region: more specifically, point @ in the line foo : @ begin" + (interactive) + (save-excursion + (if (and + (progn (verilog-forward-syntactic-ws) + (looking-at "\\<begin\\>")) + (progn (verilog-backward-syntactic-ws) + (= (preceding-char) ?\:))) + (catch 'found + (let ((nest 1)) + (while t + (verilog-re-search-backward "\\(\\<module\\>\\)\\|\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)\\>" nil 'move) + (cond + ((match-end 3) + (setq nest (1+ nest))) + ((match-end 2) + (if (= nest 1) + (throw 'found 1)) + (setq nest (1- nest)) + ) + ( t + (throw 'found (= nest 0))) + ) + ) + ) + ) + nil) + ) + ) +(defun verilog-backward-case-item (lim) + "Skip backward to nearest enclosing case item" + (interactive) + (let ( + (str 'nil) + (lim1 (progn + (save-excursion (verilog-re-search-backward verilog-endcomment-reason-re lim 'move) + (point))))) + ;; Try to find the real : + (if (save-excursion (search-backward ":" lim1 t)) + (let ((colon 0) + b e ) + (while (and (< colon 1) + (verilog-re-search-backward "\\(\\[\\)\\|\\(\\]\\)\\|\\(:\\)" lim1 'move)) + (cond + ((match-end 1) ;; [ + (setq colon (1+ colon)) + (if (>= colon 0) + (error "unbalanced ["))) + ((match-end 2) ;; ] + (setq colon (1- colon))) + + ((match-end 3) ;; : + (setq colon (1+ colon))) + + ) + ) + ;; Skip back to begining of case item + (skip-chars-backward "\t ") + (verilog-skip-backward-comment-or-string) + (setq e (point)) + (setq b (progn + (if (verilog-re-search-backward "\\<\\(case[zx]?\\)\\>\\|;\\|\\<end\\>" nil 'move) + (progn + (cond + ((match-end 1) + (goto-char (match-end 1)) + (verilog-forward-ws&directives) + (if (looking-at "(") + (progn + (forward-sexp) + (verilog-forward-ws&directives) + )) + (point)) + (t + (goto-char (match-end 0)) + (verilog-forward-ws&directives) + (point)) + )) + (error "Malformed case item") + ) + ) + ) + (setq str (buffer-substring b e)) + (if (setq e (string-match "[ \t]*\\(\\(\n\\)\\|\\(//\\)\\|\\(/\\*\\)\\)" str)) + (setq str (concat (substring str 0 e) "..."))) + str) + 'nil) + ) + ) + + +;;; +;;; Other functions +;;; + +(defun kill-existing-comment () + "kill autocomment on this line" + (save-excursion + (let* ( + (e (progn + (end-of-line) + (point))) + (b (progn + (beginning-of-line) + (search-forward "//" e t)))) + (if b + (delete-region (- b 2) e)) + ) + ) + ) + +(defun verilog-set-auto-endcomments (indent-str kill-existing-comment) + "Insert `// case: 7 ' or `// NAME ' on this line if appropriate. +Insert `// case expr ' if this line ends a case block. +Insert `// ifdef FOO ' if this line ends code conditional on FOO. +Insert `// NAME ' if this line ends a module or primitive named NAME." + (save-excursion + (cond + (; Comment close preprocessor directives + (and + (looking-at "\\(`endif\\)\\|\\(`else\\)") + (or kill-existing-comment + (not (save-excursion + (end-of-line) + (search-backward "//" (verilog-get-beg-of-line) t))))) + (let ( (reg "\\(`else\\)\\|\\(`ifdef\\)\\|\\(`endif\\)") + (nest 1) + b e + (else (if (match-end 2) + 1 + 0)) + ) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (save-excursion + (backward-sexp 1) + (while (and (/= nest 0) + (verilog-re-search-backward reg nil 'move)) + (cond + ((match-end 1) ; `else + (if (= nest 1) + (setq else 1))) + ((match-end 2) ; `ifdef + (setq nest (1- nest))) + ((match-end 3) ; `endif + (setq nest (1+ nest))) + )) + (if (match-end 0) + (setq b (progn + (skip-chars-forward "^ \t") + (verilog-forward-syntactic-ws) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point) + )))) + (if b + (if (> (- (point) b) verilog-minimum-comment-distance) + (insert (concat (if + (= else 0) + " // ifdef " + " // !ifdef ") + (buffer-substring b e)))) + (progn + (insert " // unmatched `endif") + (ding 't)) + ))) + + (; Comment close case/function/task/module and named block + (and (looking-at "\\<end") + (or kill-existing-comment + (not (save-excursion + (end-of-line) + (search-backward "//" (verilog-get-beg-of-line) t))))) + (let ((type (car indent-str))) + (if (eq type 'declaration) + () + (if + (looking-at "\\(\\<endcase\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<end\\(\\(function\\)\\|\\(task\\)\\|\\(module\\)\\|\\(primitive\\)\\)\\>\\)") + (cond + (;- This is a case block; search back for the start of this case + (match-end 1) + + (let ((err 't) + (str "UNMATCHED!!")) + (save-excursion + (verilog-leap-to-head) + (if (match-end 0) + (progn + (goto-char (match-end 1)) + (setq str (concat (buffer-substring (match-beginning 1) (match-end 1)) + (verilog-get-expr))) + (setq err nil)))) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (insert (concat " // " str )) + (if err (ding 't)) + )) + + (;- This is a begin..end block + (match-end 2) + (let ((str " // UNMATCHED !!") + (err 't) + (here (point)) + there + cntx + ) + (save-excursion + (verilog-leap-to-head) + (setq there (point)) + (if (not (match-end 0)) + (progn + (goto-char here) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (insert str) + (ding 't) + ) + (let ( sp + (lim (save-excursion (verilog-beg-of-defun) (point))) + (here (point)) + ) + (cond + (;-- handle named block differently + (looking-at verilog-named-block-re) + (search-forward ":") + (setq there (point)) + (setq str (verilog-get-expr)) + (setq err nil) + (setq str (concat " // block: " str ))) + + ((verilog-in-case-region-p) ;-- handle case item differently + (goto-char here) + (setq str (verilog-backward-case-item lim)) + (setq there (point)) + (setq err nil) + (setq str (concat " // case: " str )) + ) + (;- try to find "reason" for this begin + (cond + (; + (eq here (progn (verilog-beg-of-statement) (point))) + (setq err nil) + (setq str "")) + ((looking-at verilog-endcomment-reason-re) + (setq there (match-end 0)) + (setq cntx (concat + (buffer-substring (match-beginning 0) (match-end 0)) " ")) + (cond + (; + (match-end 2) + (setq err nil) + (save-excursion + (goto-char sp) + (if (and (verilog-continued-line) + (looking-at "\\<repeat\\>\\|\\<wait\\>\\|\\<always\\>")) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq str + (concat " // " + (buffer-substring (match-beginning 0) (match-end 0)) " " + (verilog-get-expr)))) + (setq str "") + ) + ) + ) + (;- else + (match-end 4) + (let ((nest 0) + ( reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<if\\>\\)") + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + (if (= 0 nest) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // else: !if" str )) + (throw 'skip 1)) + ))) + ) + ) + ) + ) + (;- task/function/initial et cetera + t + (match-end 0) + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // " cntx str ))) + + (;-- otherwise... + (setq str " // auto-endcomment confused ") + ) + ) + ) + ((and + (verilog-in-case-region-p) ;-- handle case item differently + (progn + (setq there (point)) + (goto-char here) + (setq str (verilog-backward-case-item lim)))) + (setq err nil) + (setq str (concat " // case: " str )) + ) + ) + ) + ) + ) + (goto-char here) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (if (or err + (> (- here there) verilog-minimum-comment-distance)) + (insert str)) + (if err (ding 't)) + ) + ) + ) + ) + + + (;- this is end{function,task,module} + t + (let (string reg (width nil)) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (backward-sexp) + (cond + ((match-end 5) + (setq reg "\\(\\<function\\>\\)\\|\\(\\<\\(endfunction\\|task\\|\\(macro\\)?module\\|primitive\\)\\>\\)") + (setq width "\\([ \t]*\\[[^]]*\\]\\)?") + ) + ((match-end 6) + (setq reg "\\(\\<task\\>\\)\\|\\(\\<\\(endtask\\|function\\|\\(macro\\)?module\\|primitive\\)\\>\\)")) + ((match-end 7) + (setq reg "\\(\\<\\(macro\\)?module\\>\\)\\|\\<endmodule\\>")) + ((match-end 8) + (setq reg "\\(\\<primitive\\>\\)\\|\\(\\<\\(endprimitive\\|function\\|task\\|\\(macro\\)?module\\)\\>\\)")) + ) + (let (b e) + (save-excursion + (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) + (setq b (progn + (skip-chars-forward "^ \t") + (verilog-forward-ws&directives) + (if (and width (looking-at width)) + (progn + (goto-char (match-end 0)) + (verilog-forward-ws&directives) + )) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))) + (setq string (buffer-substring b e))) + (t + (ding 't) + (setq string "unmactched end(function|task|module|primitive)"))))) + (end-of-line) + (insert (concat " // " string ))) + ) + ) + ) + ) + ) + ) + ) + ) + ) + +(defun verilog-get-expr() + "Grab expression at point, e.g, case ( a | b & (c ^d))" + (let* ((b (progn + (verilog-forward-syntactic-ws) + (skip-chars-forward " \t") + (point))) + (e (let ((par 1)) + (cond + ((looking-at "(") + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\((\\)\\|\\()\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))) + (point)) + ((looking-at "\\[") + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\(\\[\\)\\|\\(\\]\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))) + (verilog-forward-syntactic-ws) + (skip-chars-forward "^ \t\n") + (point)) + ((looking-at "/[/\\*]") + b) + ('t + (skip-chars-forward "^: \t\n") + (point) + )))) + (str (buffer-substring b e))) + (if (setq e (string-match "[ \t]*\\(\\(\n\\)\\|\\(//\\)\\|\\(/\\*\\)\\)" str)) + (setq str (concat (substring str 0 e) "..."))) + str) + ) + + +;;; +;;; Indentation +;;; +(defconst verilog-indent-alist + '((block . (+ ind verilog-indent-level)) + (case . (+ ind verilog-case-indent)) + (cparenexp . (+ ind verilog-indent-level)) + (cexp . (+ ind verilog-indent-level)) + (defun . verilog-indent-level) + (declaration . verilog-indent-level) + (tf . verilog-indent-level) + (behavorial . verilog-indent-level) + (statement . ind) + (cpp . 0) + (comment . (verilog-indent-comment)) + (unknown . 3) + (string . 0))) + +(defun verilog-calculate-indent () + "Calculate the indent of the current Verilog line, through examination +of previous lines. Once a line is found that is definitive as to the +type of the current line, return that lines' indent level and it's +type. Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." + (save-excursion + (let* ((starting_position (point)) + (par 0) + (begin (looking-at "[ \t]*begin\\>")) + (type (catch 'nesting + ;; Keep working backwards until we can figure out + ;; what type of statement this is. + ;; Basically we need to figure out + ;; 1) if this is a continuation of the previous line; + ;; 2) are we in a block scope (begin..end) + + ;; if we are in a comment, done. + (if (verilog-in-star-comment-p) (throw 'nesting 'comment)) + + ;; if we are in a parenthesized list, done. + (if (verilog-in-paren) (progn (setq par 1) (throw 'nesting 'block))) + + ;; See if we are continuing a previous line + (while t + ;; trap out if we crawl off the top of the buffer + (if (bobp) (throw 'nesting 'cpp)) + + (if (verilog-continued-line) + (let ((sp (point))) + (if (and + (not (looking-at verilog-complete-reg)) + (verilog-continued-line)) + (progn (goto-char sp) + (throw 'nesting 'cexp)) + (goto-char sp)) + (if (and begin + (not verilog-indent-begin-after-if) + (looking-at verilog-no-indent-begin-re)) + (throw 'nesting 'statement) + (throw 'nesting 'cexp))) + + ;; not a continued line + (goto-char starting_position)) + + (if (looking-at "\\<else\\>") + ;; search back for governing if, striding across begin..end pairs + ;; appropriately + (let ((reg (concat + verilog-end-block-re + "\\|\\(\\<else\\>\\)" + "\\|\\(\\<if\\>\\)" + )) + (elsec 1) + ) + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; endblock + ; try to leap back to matching outward block by striding across + ; indent level changing tokens then immediately + ; previous line governs indentation. + (let ((reg)(nest 1)) + (looking-at verilog-end-block-re-1);; end|join|endcase|endtable|endspecify + (cond + ((match-end 1) ; end + ;; Search back for matching begin + (setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" ) + ) + ((match-end 2) ; endcase + ;; Search back for matching case + (setq reg "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" ) + ) + ((match-end 3) ; join + ;; Search back for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" ) + ) + ((match-end 4) ; endtable + ;; Search back for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" ) + ) + ((match-end 5) ; endspecify + ;; Search back for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" ) + ) + ((match-end 6) ; endfunction + ;; Search back for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" ) + ) + ((match-end 7) ; endspecify + ;; Search back for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" ) + ) + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest)) + (if (= 0 nest) + (throw 'skip 1))) + ((match-end 2) ; end + (setq nest (1+ nest))))) + ) + ) + ) + ((match-end 2) ; else, we're in deep + (setq elsec (1+ elsec)) + ) + ((match-end 3) ; found it + (setq elsec (1- elsec)) + (if (= 0 elsec) + ;; Now previous line describes syntax + (throw 'nesting 'statement) + ))) + ) + ) + ) + (while (verilog-re-search-backward verilog-indent-reg nil 'move) + (cond + ((match-end 1) ; beg-block + (looking-at verilog-beg-block-re-1) + (cond + ((match-end 2) (throw 'nesting 'case)) + (t (throw 'nesting 'block)))) + + ((match-end 2) ;; end-block + (verilog-leap-to-head) + (if (verilog-in-case-region-p) + (progn + (verilog-leap-to-case-head) + (if (looking-at verilog-case-re) + (throw 'nesting 'case)) + ))) + + ((or (match-end 3) ;; module.. primitive + (match-end 5)) ;; endtask.. + (throw 'nesting 'defun)) + + ((match-end 4) ;; endmodule + (throw 'nesting 'cpp)) + + ((match-end 6) ;; function/task + (throw 'nesting 'behavorial)) + + ((bobp) + (throw 'nesting 'cpp)) + ) + ) + ) + ) + ) + ) + ;; Return type of block and indent level. + (if (not type) + (setq type 'cpp)) + (if (> par 0) ; Unclosed Parenthesis + (list 'cparenexp par) + (if (eq type 'case) + (list type (verilog-case-indent-level)) + (list type (verilog-indent-level))))))) +(defun verilog-leap-to-case-head () "" + (let ((nest 1)) + (while (/= 0 nest) + (verilog-re-search-backward "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" nil 'move) + (cond + ((match-end 1) + (setq nest (1- nest))) + ((match-end 2) + (setq nest (1+ nest))) + ((bobp) + (ding 't) + (setq nest 0)) + ) + ) + ) + ) + +(defun verilog-leap-to-head () "foo" + (let (reg + snest + (nest 1)) + (if (looking-at verilog-end-block-re-1);; end|join|endcase|endtable|endspecify + (progn + (cond + ((match-end 1) ; end + ;; Search back for matching begin + (setq reg (concat "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|" + "\\(\\<endcase\\>\\)\\|\\(\\<join\\>\\)" ))) + + ((match-end 2) ; endcase + ;; Search back for matching case + (setq reg "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" ) + ) + ((match-end 3) ; join + ;; Search back for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" ) + ) + ((match-end 4) ; endtable + ;; Search back for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" ) + ) + ((match-end 5) ; endspecify + ;; Search back for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" ) + ) + ((match-end 6) ; endfunction + ;; Search back for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" ) + ) + ((match-end 7) ; endspecify + ;; Search back for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" ) + ) + ) + (catch 'skip + (let (sreg) + (while (verilog-re-search-backward reg nil 'move) + + (cond + ((match-end 1) ; begin + (setq nest (1- nest)) + (if (= 0 nest) + ;; Now previous line describes syntax + (throw 'skip 1)) + (if (and snest + (= snest nest)) + (setq reg sreg)) + ) + ((match-end 2) ; end + (setq nest (1+ nest)) + ) + ((match-end 3) + ;; endcase, jump to case + (setq snest nest) + (setq nest (1+ nest)) + (setq sreg reg) + (setq reg "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" ) + ) + ((match-end 4) + ;; join, jump to fork + (setq snest nest) + (setq nest (1+ nest)) + (setq sreg reg) + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" ) + ) + ) + ) + ) + ) + ) + ) + ) + ) +(defun verilog-continued-line () + "Return true if this is a continued line. + Set point to where line starts" + (let ((continued 't)) + (if (eq 0 (forward-line -1)) + (progn + (end-of-line) + (verilog-backward-ws&directives) + (if (bobp) + (setq continued nil) + (while (and continued + (save-excursion + (skip-chars-backward " \t") + (not (bolp)))) + (setq continued (verilog-backward-token)) + ) ;; while + ) + ) + (setq continued nil) + ) + continued) + ) + +(defun verilog-backward-token () + "step backward token, returning true if we are now at an end of line token" + (verilog-backward-syntactic-ws) + (cond + ((bolp) + nil) + (;-- Anything ending in a ; is complete + (= (preceding-char) ?\;) + nil) +;; (;-- Anything ending in a , is deemed complete +;; (= (preceding-char) ?\,) +;; nil) + + (;-- Could be 'case (foo)' or 'always @(bar)' which is complete + (= (preceding-char) ?\)) + (progn + (backward-char) + (backward-up-list 1) + (verilog-backward-syntactic-ws) + (forward-word -1) + (not (looking-at "\\<case[xz]?\\>[^:]")))) + + (;-- any of begin|initial|while are complete statements; 'begin : foo' is also complete + t + (forward-word -1) + (cond + ( + (looking-at "\\(initial\\>\\)\\|\\(always\\>\\)") + t) + ( + (looking-at verilog-indent-reg) + nil) + (t + (let + ((back (point))) + (verilog-backward-syntactic-ws) + (cond + ((= (preceding-char) ?\:) + (backward-char) + (verilog-backward-syntactic-ws) + (backward-sexp) + (if (looking-at "begin") + nil + t) + ) + ((= (preceding-char) ?\#) + (backward-char) + t) + + (t + (goto-char back) + t) + ) + ) + ) + ) + ) + ) +) + +(defun verilog-backward-syntactic-ws (&optional lim) + ;; Backward skip over syntactic whitespace for Emacs 19. + (save-restriction + (let* ((lim (or lim (point-min))) + (here lim) + bol + ) + (if (< lim (point)) + (progn + (narrow-to-region lim (point)) + (while (/= here (point)) + (setq here (point)) + (forward-comment (-(buffer-size))) + (save-excursion + (setq bol (progn (beginning-of-line) (point)))) + (search-backward "//" bol t) + ))) + ))) + +(defun verilog-forward-syntactic-ws (&optional lim) + ;; forward skip over syntactic whitespace for Emacs 19. + (save-restriction + (let* ((lim (or lim (point-max))) + (here lim) + ) + (if (> lim (point)) + (progn + (narrow-to-region (point) lim) + (while (/= here (point)) + (setq here (point)) + (forward-comment (buffer-size)) + ))) + ))) + +(defun verilog-backward-ws&directives (&optional lim) + ;; Backward skip over syntactic whitespace and compiler directives for Emacs 19. + (save-restriction + (let* ((lim (or lim (point-min))) + (here lim) + jump + ) + (if (< lim (point)) + (progn + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 4 state) ;; in /* */ comment + (verilog-re-search-backward "/\*" nil 'move) + ) + ((nth 7 state) ;; in // comment + (verilog-re-search-backward "//" nil 'move) + ))) + (narrow-to-region lim (point)) + (while (/= here (point)) + (setq here (point)) + (forward-comment (-(buffer-size))) + (save-excursion + (beginning-of-line) + (if (looking-at "[ \t]*\\(`define\\)\\|\\(`ifdef\\)\\|\\(`else\\)\\|\\(`endif\\)\\|\\(`timescale\\)\\|\\(`include\\)") + (setq jump t) + (setq jump nil))) + (if jump + (beginning-of-line)) + ))) + ))) + +(defun verilog-forward-ws&directives (&optional lim) + ;; forward skip over syntactic whitespace and compiler directives for Emacs 19. + (save-restriction + (let* ((lim (or lim (point-max))) + (here lim) + jump + ) + (if (> lim (point)) + (progn + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 4 state) ;; in /* */ comment + (verilog-re-search-forward "/\*" nil 'move) + ) + ((nth 7 state) ;; in // comment + (verilog-re-search-forward "//" nil 'move) + ))) + (narrow-to-region (point) lim) + (while (/= here (point)) + (setq here (point)) + (forward-comment (buffer-size)) + (save-excursion + (beginning-of-line) + (if (looking-at "[ \t]*\\(`define\\)\\|\\(`ifdef\\)\\|\\(`else\\)\\|\\(`endif\\)\\|\\(`timescale\\)") + (setq jump t))) + (if jump + (beginning-of-line 2)) + ))) + ))) +(defun verilog-parenthesis-depth () + "Return non zero if in parenthetical-expression" + (save-excursion + (car (parse-partial-sexp (point-min) (point))))) + +(defun verilog-in-comment-or-string-p () + "Return true if in a string or comment" + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (or (nth 3 state) (nth 4 state) (nth 7 state))) ; Inside string or comment + ) + +(defun verilog-in-star-comment-p () + "Return true if in a star comment" + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (nth 4 state)) + ) + +(defun verilog-in-paren () + "Return true if in a parenthetical expression" + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (/= 0 (nth 0 state))) + ) + +(defun verilog-skip-forward-comment-or-string () + "Return true if in a string or comment" + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 3 state) ;Inside string + (goto-char (nth 3 state)) + t) + ((nth 7 state) ;Inside // comment + (forward-line 1) + t) + ((nth 4 state) ;Inside any comment (hence /**/) + (search-forward "*/")) + (t + nil) + ) + ) + ) + +(defun verilog-skip-backward-comment-or-string () + "Return true if in a string or comment" + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 3 state) ;Inside string + (search-backward "\"") + t) + ((nth 7 state) ;Inside // comment + (search-backward "//") + t) + ((nth 4 state) ;Inside /* */ comment + (search-backward "/*") + t) + (t + nil) + ) + ) + ) + +(defun verilog-skip-forward-comment-p () + "If in comment, move to end and return true" + (let (state) + (progn + (setq state + (save-excursion + (parse-partial-sexp (point-min) (point)))) + (cond + ((nth 3 state) + t) + ((nth 7 state) ;Inside // comment + (end-of-line) + (forward-char 1) + t) + ((nth 4 state) ;Inside any comment + t) + (t + nil) + ) + ) + ) + ) + +(defun verilog-indent-line-relative () + "Cheap version of indent line that only looks at + a few lines to determine indent level" + (interactive) + (let ((indent-str)) + (save-excursion + (beginning-of-line) + (if (looking-at "^[ \t]*$") + (cond ;- A blank line; No need to be too smart. + ((bobp) + (setq indent-str (list 'cpp 0))) + ((verilog-continued-line) + (let ((sp (point))) + (if (verilog-continued-line) + (progn (goto-char sp) + (setq indent-str (list 'statement (verilog-indent-level)))) + (goto-char sp) + (setq indent-str (list 'block (verilog-indent-level)))))) + (t + (setq indent-str (verilog-calculate-indent)))) + (setq indent-str (verilog-calculate-indent)) + ) + ) + (verilog-do-indent indent-str) + ) + ) +(defun verilog-indent-line () + "Indent for special part of code." + (if (looking-at verilog-directive-re) + ;; We could nicely nest `ifdef's, but... + (progn + (delete-horizontal-space) + (indent-to 0) + (list 'cpp 0)) ; Return verilog-calculate-indent data + (verilog-do-indent (verilog-calculate-indent))) + ) + +(defun verilog-do-indent (indent-str) + "" + (let ((type (car indent-str)) + (ind (car (cdr indent-str)))) + (delete-horizontal-space) + (cond + (; handle comma continued exp + (eq type 'cexp) + (let ((here (point))) + (if (progn (verilog-backward-syntactic-ws) + (= (preceding-char) ?\,)) + (let* ( fst + (column + (save-excursion + (backward-char 1) + (verilog-beg-of-statement) + (setq fst (point)) + (if (looking-at verilog-declaration-re) + (progn ;; we have multiple words + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (if (= (following-char) ?\[) + (progn + (forward-char 1) + (backward-up-list -1) + (skip-chars-forward " \t") + ) + ) + ) + (;; we have a single word + goto-char fst) + ) + (current-column) + ) + ) + ) + (goto-char here) + (beginning-of-line) + (delete-horizontal-space) + (indent-to column)) + (progn + (goto-char here) + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + ;; (verilog-comment-depth type val) + (delete-horizontal-space) + (indent-to val) + )) + ) + ) + ) + (;-- Declaration -- maybe line 'em up + (and (not (or + (eq type 'cpp) + (eq type 'comment))) + (looking-at verilog-declaration-re) + (or (memq 'all verilog-auto-lineup) + (memq 'declaration verilog-auto-lineup))) + (verilog-indent-declaration (cond ((eq type 'defun) 0) + (t ind))) + ) + (; handle inside parenthetical expressions + (eq type 'cparenexp) + (let ((column (save-excursion + (backward-up-list 1) + (forward-char 1) + (skip-chars-forward " \t") + (current-column)))) + (beginning-of-line) + (delete-horizontal-space) + (indent-to column))) + + (;-- Case -- maybe line 'em up + (and (eq type 'case) (not (looking-at "^[ \t]*$"))) + (progn + (cond + ((looking-at "\\<endcase\\>") + (indent-to ind)) + (t + (indent-to (eval (cdr (assoc type verilog-indent-alist)))) + )))) + + (;-- Handle the ends + (looking-at verilog-end-block-re) + (if (eq type 'statement) + (indent-to (- ind verilog-indent-level)) + (indent-to ind))) + (;-- defun + (and (eq type 'defun) + (looking-at verilog-zero-indent-re)) + (indent-to 0)) + + (;-- Everything else + t + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + ;; (verilog-comment-depth type val) + (delete-horizontal-space) + (indent-to val) + )) + ) + (if (looking-at "[ \t]+$") + (skip-chars-forward " \t")) + indent-str ; Return verilog-calculate-indent data + ) +) + +(defun verilog-indent-level () + "Return the indent-level the current statement has." + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (current-column))) + + +(defun verilog-case-indent-level () + "Return the indent-level the current statement has. +Do not count named blocks or case-statements." + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (cond + ((looking-at verilog-named-block-re) + (current-column)) + ((and (not (looking-at verilog-case-re)) + (looking-at "[^:;]+[ \t]*:")) + (search-forward ":" nil t) + (skip-chars-forward " \t") + (current-column)) + (t + (current-column))))) + +(defun verilog-indent-comment (&optional arg) + "Indent current line as comment. +If optional arg is non-nil, just return the +column number the line should be indented to." + (let* ((stcol + (cond + ((verilog-in-star-comment-p) + (save-excursion + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + ( comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))) + ) + )) + (if arg + (progn + (delete-horizontal-space) + (indent-to stcol)) + stcol + ) + ) + ) + +;;; + + +(defun verilog-indent-declaration (base-ind &optional arg start end) + "Indent current lines as declaration, lining up the variable names" + (interactive) + (let ((pos (point-marker)) + (lim (save-excursion (progn (end-of-line) (point-marker)))) + ) + (if (and (not (or arg start)) (not (verilog-re-search-forward verilog-declaration-re lim t))) + () + (progn + (beginning-of-line) + (delete-horizontal-space) + (indent-to (+ base-ind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (let* ((pos2 (point-marker)) + (more 1) + here + (stpos (if start start + (save-excursion + + (goto-char pos2) + (catch 'first + (while more + (setq here (point)) + (verilog-backward-syntactic-ws) + (if (= (preceding-char) ?\;) + (backward-char)) + (verilog-beg-of-statement) + (if (bobp) + (throw 'first (point-marker))) + (if (looking-at verilog-declaration-re) + (setq more (/= (point) here)) + (throw 'first (point-marker)))) + (throw 'first (point-marker))) + ) + ) + ) + (edpos (if end + (set-marker (make-marker) end) + lim)) + ind) + (goto-char stpos) + ;; Indent lines in declaration block + (if arg + (while (<= (point) (marker-position edpos)) + (beginning-of-line) + (delete-horizontal-space) + (cond + ((looking-at "^[ \t]*$") + ()) + ((not (looking-at verilog-declaration-re)) + (indent-to arg)) + (t + (indent-to (+ arg verilog-indent-level)))) + (forward-line 1))) + + ;; Do lineup + (setq ind (verilog-get-lineup-indent stpos edpos)) + (goto-char stpos) + (if (> (- edpos stpos) 100) + (message "Lining up declarations..(please stand by)")) + (let (e) + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (if (verilog-re-search-forward verilog-declaration-re-1 e 'move) + (just-one-space)) +;; (forward-char -1)) + (save-excursion + (let ((p (point))) + (beginning-of-line) + (if (verilog-re-search-forward "\\[" p 'move) + (progn + (forward-char -1) + (just-one-space))) + )) + (delete-horizontal-space) + (indent-to ind) + (beginning-of-line) + (delete-horizontal-space) + (indent-to (+ base-ind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (forward-line 1))))) + + ;; If arg - move point + (message "") + (if arg (forward-line -1) + (goto-char (marker-position pos)))))) + +; "Return the indent level that will line up several lines within the region +;from b to e nicely. The lineup string is str." +(defun verilog-get-lineup-indent (b edpos) + (save-excursion + (let ((ind 0) e) + (goto-char b) + ;; Get rightmost position + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (if (verilog-re-search-forward verilog-declaration-re-1 e 'move) + (progn + (goto-char (match-end 0)) + (verilog-backward-syntactic-ws) + (if (> (current-column) ind) + (setq ind (current-column))) + (goto-char (match-end 0))))) + (if (> ind 0) + (1+ ind) + ;; No lineup-string found + (goto-char b) + (end-of-line) + (skip-chars-backward " \t") + (1+ (current-column)))))) + +;; A useful mode debugging aide +(defun verilog-comment-depth (type val) + "" + (save-excursion + (let + ((b (prog2 + (beginning-of-line) + (point-marker) + (end-of-line))) + (e (point-marker))) + (if (re-search-backward " /\\* \[#-\]# \[a-z\]+ \[0-9\]+ ## \\*/" b t) + (progn + (replace-match " /* -# ## */") + (end-of-line)) + (progn + (end-of-line) + (insert " /* ## ## */")))) + (backward-char 6) + (insert + (format "%s %d" type val)) + ) + ) +;;; +;;; +;;; Completion +;;; +(defvar verilog-str nil) +(defvar verilog-all nil) +(defvar verilog-pred nil) +(defvar verilog-buffer-to-use nil) +(defvar verilog-flag nil) +(defvar verilog-toggle-completions nil + "*Non-nil means \\<verilog-mode-map>\\[verilog-complete-word] should try all possible completions one by one. +Repeated use of \\[verilog-complete-word] will show you all of them. +Normally, when there is more than one possible completion, +it displays a list of all possible completions.") + + +(defvar verilog-type-keywords + '("buf" "bufif0" "bufif1" "cmos" "defparam" "inout" "input" + "integer" "nand" "nmos" "nor" "not" "notif0" "notif1" "or" "output" "parameter" + "pmos" "pull0" "pull1" "pullup" "rcmos" "real" "realtime" "reg" "rnmos" "rpmos" "rtran" + "rtranif0" "rtranif1" "time" "tran" "tranif0" "tranif1" "tri" "tri0" "tri1" + "triand" "trior" "trireg" "wand" "wire" "wor" "xnor" "xor" ) + "*Keywords for types used when completing a word in a declaration or parmlist. +\(eg. integer, real, char.) The types defined within the Verilog program +will be completed runtime, and should not be added to this list.") + +(defvar verilog-defun-keywords + '("begin" "function" "task" "initial" "always" "assign" "posedge" "negedge" "endmodule") + "*Keywords to complete when standing at first word of a line in declarative scope. +\(eg. initial, always, begin, assign.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-block-keywords + '("begin" "fork" "join" "case" "end" "if" "else" "for" "while" "repeat") + "*Keywords to complete when standing at first word of a line in behavorial scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-tf-keywords + '("begin" "fork" "join" "case" "end" "endtask" "endfunction" "if" "else" "for" "while" "repeat") + "*Keywords to complete when standing at first word of a line in a task or function scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-case-keywords + '("begin" "fork" "join" "case" "end" "endcase" "if" "else" "for" "repeat") + "*Keywords to complete when standing at first word of a line in behavorial scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-separator-keywords + '("else" "then" "begin") + "*Keywords to complete when NOT standing at the first word of a statement. +\(eg. else, then.) +Variables and function names defined within the +Verilog program are completed runtime and should not be added to this list.") + +(defun verilog-string-diff (str1 str2) + "Return index of first letter where STR1 and STR2 differs." + (catch 'done + (let ((diff 0)) + (while t + (if (or (> (1+ diff) (length str1)) + (> (1+ diff) (length str2))) + (throw 'done diff)) + (or (equal (aref str1 diff) (aref str2 diff)) + (throw 'done diff)) + (setq diff (1+ diff)))))) + +;; Calculate all possible completions for functions if argument is `function', +;; completions for procedures if argument is `procedure' or both functions and +;; procedures otherwise. + +(defun verilog-func-completion (type) + ;; Build regular expression for module/task/function names + (if (string= verilog-str "") + (setq verilog-str "[a-zA-Z_]")) + (let ((verilog-str (concat (cond + ((eq type 'module) "\\<\\(module\\)\\s +") + ((eq type 'tf) "\\<\\(task\\|function\\)\\s +") + (t "\\<\\(task\\|function\\|module\\)\\s +")) + "\\<\\(" verilog-str "[a-zA-Z0-9_.]*\\)\\>")) + match) + + (if (not (looking-at verilog-defun-re)) + (verilog-re-search-backward verilog-defun-re nil t)) + (forward-char 1) + + ;; Search through all reachable functions + (goto-char (point-min)) + (while (verilog-re-search-forward verilog-str (point-max) t) + (progn (setq match (buffer-substring (match-beginning 2) + (match-end 2))) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + (if (match-beginning 0) + (goto-char (match-beginning 0))))) + +(defun verilog-get-completion-decl () + ;; Macro for searching through current declaration (var, type or const) + ;; for matches of `str' and adding the occurence tp `all' + (let ((end (save-excursion (verilog-declaration-end) + (point))) + match) + ;; Traverse lines + (while (< (point) end) + (if (verilog-re-search-forward verilog-declaration-re-1 (verilog-get-end-of-line) t) + ;; Traverse current line + (while (and (verilog-re-search-forward + (concat "\\((\\|\\<\\(var\\|type\\|const\\)\\>\\)\\|" + verilog-symbol-re) + (verilog-get-beg-of-line) t) + (not (match-end 1))) + (setq match (buffer-substring (match-beginning 0) (match-end 0))) + (if (string-match (concat "\\<" verilog-str) match) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all)))))) + (if (verilog-re-search-forward "\\<record\\>" (verilog-get-end-of-line) t) + (verilog-declaration-end) + (forward-line 1))))) + +(defun verilog-type-completion () + "Calculate all possible completions for types." + (let ((start (point)) + goon) + ;; Search for all reachable type declarations + (while (or (verilog-beg-of-defun) + (setq goon (not goon))) + (save-excursion + (if (and (< start (prog1 (save-excursion (verilog-end-of-defun) + (point)) + (forward-char 1))) + (verilog-re-search-forward + "\\<type\\>\\|\\<\\(begin\\|function\\|procedure\\)\\>" + start t) + (not (match-end 1))) + ;; Check current type declaration + (verilog-get-completion-decl)))))) + +(defun verilog-var-completion () + "Calculate all possible completions for variables (or constants)." + nil) +; Not done yet; in 1.99 perhaps +; (let ((start (point)) +; goon twice) +; ;; Search for all reachable var declarations +; (while (or (verilog-beg-of-defun) +; (setq goon (not goon))) +; (save-excursion +; (if (> start (prog1 (save-excursion (verilog-end-of-defun) +; (point)))) +; () ; Declarations not reacable +; (cond ((and (verilog-re-search-forward verilog-declaration-re start t) +; ;; Check var/const declarations +; (verilog-get-completion-decl))))))))) + + +(defun verilog-keyword-completion (keyword-list) + "Give list of all possible completions of keywords in KEYWORD-LIST." + (mapcar '(lambda (s) + (if (string-match (concat "\\<" verilog-str) s) + (if (or (null verilog-pred) + (funcall verilog-pred s)) + (setq verilog-all (cons s verilog-all))))) + keyword-list)) + +;; Function passed to completing-read, try-completion or +;; all-completions to get completion on STR. If predicate is non-nil, +;; it must be a function to be called for every match to check if this +;; should really be a match. If flag is t, the function returns a list +;; of all possible completions. If it is nil it returns a string, the +;; longest possible completion, or t if STR is an exact match. If flag +;; is 'lambda, the function returns t if STR is an exact match, nil +;; otherwise. + +(defun verilog-completion (verilog-str verilog-pred verilog-flag) + (save-excursion + (let ((verilog-all nil)) + ;; Set buffer to use for searching labels. This should be set + ;; within functins which use verilog-completions + (set-buffer verilog-buffer-to-use) + + ;; Determine what should be completed + (let ((state (car (verilog-calculate-indent)))) + (cond ((eq state 'defun) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'module) + (verilog-keyword-completion verilog-defun-keywords)) + + ((eq state 'block) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-block-keywords)) + + ((eq state 'case) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-case-keywords)) + + ((eq state 'tf) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-tf-keywords)) + + (t;--Anywhere else + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'both) + (verilog-keyword-completion verilog-separator-keywords)))) + + ;; Now we have built a list of all matches. Give response to caller + (verilog-completion-response)))) + +(defun verilog-completion-response () + (cond ((or (equal verilog-flag 'lambda) (null verilog-flag)) + ;; This was not called by all-completions + (if (null verilog-all) + ;; Return nil if there was no matching label + nil + ;; Get longest string common in the labels + (let* ((elm (cdr verilog-all)) + (match (car verilog-all)) + (min (length match)) + tmp) + (if (string= match verilog-str) + ;; Return t if first match was an exact match + (setq match t) + (while (not (null elm)) + ;; Find longest common string + (if (< (setq tmp (verilog-string-diff match (car elm))) min) + (progn + (setq min tmp) + (setq match (substring match 0 min)))) + ;; Terminate with match=t if this is an exact match + (if (string= (car elm) verilog-str) + (progn + (setq match t) + (setq elm nil)) + (setq elm (cdr elm))))) + ;; If this is a test just for exact match, return nil ot t + (if (and (equal verilog-flag 'lambda) (not (equal match 't))) + nil + match)))) + ;; If flag is t, this was called by all-completions. Return + ;; list of all possible completions + (verilog-flag + verilog-all))) + +(defvar verilog-last-word-numb 0) +(defvar verilog-last-word-shown nil) +(defvar verilog-last-completions nil) + +(defun verilog-complete-word () + "Complete word at current point. +\(See also `verilog-toggle-completions', `verilog-type-keywords', +`verilog-start-keywords' and `verilog-separator-keywords'.)" + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (verilog-str (buffer-substring b e)) + ;; The following variable is used in verilog-completion + (verilog-buffer-to-use (current-buffer)) + (allcomp (if (and verilog-toggle-completions + (string= verilog-last-word-shown verilog-str)) + verilog-last-completions + (all-completions verilog-str 'verilog-completion))) + (match (if verilog-toggle-completions + "" (try-completion + verilog-str (mapcar '(lambda (elm) + (cons elm 0)) allcomp))))) + ;; Delete old string + (delete-region b e) + + ;; Toggle-completions inserts whole labels + (if verilog-toggle-completions + (progn + ;; Update entry number in list + (setq verilog-last-completions allcomp + verilog-last-word-numb + (if (>= verilog-last-word-numb (1- (length allcomp))) + 0 + (1+ verilog-last-word-numb))) + (setq verilog-last-word-shown (elt allcomp verilog-last-word-numb)) + ;; Display next match or same string if no match was found + (if (not (null allcomp)) + (insert "" verilog-last-word-shown) + (insert "" verilog-str) + (message "(No match)"))) + ;; The other form of completion does not necessarly do that. + + ;; Insert match if found, or the original string if no match + (if (or (null match) (equal match 't)) + (progn (insert "" verilog-str) + (message "(No match)")) + (insert "" match)) + ;; Give message about current status of completion + (cond ((equal match 't) + (if (not (null (cdr allcomp))) + (message "(Complete but not unique)") + (message "(Sole completion)"))) + ;; Display buffer if the current completion didn't help + ;; on completing the label. + ((and (not (null (cdr allcomp))) (= (length verilog-str) + (length match))) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a keypress. Then delete *Completion* window + (momentary-string-display "" (point)) + (delete-window (get-buffer-window (get-buffer "*Completions*"))) + ))))) + +(defun verilog-show-completions () + "Show all possible completions at current point." + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (verilog-str (buffer-substring b e)) + ;; The following variable is used in verilog-completion + (verilog-buffer-to-use (current-buffer)) + (allcomp (if (and verilog-toggle-completions + (string= verilog-last-word-shown verilog-str)) + verilog-last-completions + (all-completions verilog-str 'verilog-completion)))) + ;; Show possible completions in a temporary buffer. + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a keypress. Then delete *Completion* window + (momentary-string-display "" (point)) + (delete-window (get-buffer-window (get-buffer "*Completions*"))))) + + +(defun verilog-get-default-symbol () + "Return symbol around current point as a string." + (save-excursion + (buffer-substring (progn + (skip-chars-backward " \t") + (skip-chars-backward "a-zA-Z0-9_") + (point)) + (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))))) + +(defun verilog-build-defun-re (str &optional arg) + "Return function/task/module starting with STR as regular expression. +With optional second arg non-nil, STR is the complete name of the instruction." + (if arg + (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "\\)\\>") + (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "[a-zA-Z0-9_]*\\)\\>"))) + +;; Function passed to completing-read, try-completion or +;; all-completions to get completion on any function name. If +;; predicate is non-nil, it must be a function to be called for every +;; match to check if this should really be a match. If flag is t, the +;; function returns a list of all possible completions. If it is nil +;; it returns a string, the longest possible completion, or t if STR +;; is an exact match. If flag is 'lambda, the function returns t if +;; STR is an exact match, nil otherwise. + + +(defun verilog-comp-defun (verilog-str verilog-pred verilog-flag) + (save-excursion + (let ((verilog-all nil) + match) + + ;; Set buffer to use for searching labels. This should be set + ;; within functins which use verilog-completions + (set-buffer verilog-buffer-to-use) + + (let ((verilog-str verilog-str)) + ;; Build regular expression for functions + (if (string= verilog-str "") + (setq verilog-str (verilog-build-defun-re "[a-zA-Z_]")) + (setq verilog-str (verilog-build-defun-re verilog-str))) + (goto-char (point-min)) + + ;; Build a list of all possible completions + (while (verilog-re-search-forward verilog-str nil t) + (setq match (buffer-substring (match-beginning 2) (match-end 2))) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + + ;; Now we have built a list of all matches. Give response to caller + (verilog-completion-response)))) + +(defun verilog-goto-defun () + "Move to specified Verilog module/task/function. +The default is a name found in the buffer around point." + (interactive) + (let* ((default (verilog-get-default-symbol)) + ;; The following variable is used in verilog-comp-function + (verilog-buffer-to-use (current-buffer)) + (default (if (verilog-comp-defun default nil 'lambda) + default "")) + (label (if (not (string= default "")) + ;; Do completion with default + (completing-read (concat "Label: (default " default ") ") + 'verilog-comp-defun nil t "") + ;; There is no default value. Complete without it + (completing-read "Label: " + 'verilog-comp-defun nil t "")))) + ;; If there was no response on prompt, use default value + (if (string= label "") + (setq label default)) + ;; Goto right place in buffer if label is not an empty string + (or (string= label "") + (progn + (goto-char (point-min)) + (re-search-forward (verilog-build-defun-re label t)) + (beginning-of-line))))) +(defun verilog-showscopes () + "list all scopes in this module" + (interactive) + (let ( + (buffer (current-buffer)) + (linenum 1) + (nlines 0) + (first 1) + (prevpos (point-min)) + (final-context-start (make-marker)) + (regexp "\\(module\\s-+\\w+\\s-*(\\)\\|\\(\\w+\\s-+\\w+\\s-*(\\)") + ) + (with-output-to-temp-buffer "*Occur*" + (save-excursion + (message (format "Searching for %s ..." regexp)) + ;; Find next match, but give up if prev match was at end of buffer. + (while (and (not (= prevpos (point-max))) + (verilog-re-search-forward regexp nil t)) + (goto-char (match-beginning 0)) + (beginning-of-line) + (save-match-data + (setq linenum (+ linenum (count-lines prevpos (point))))) + (setq prevpos (point)) + (goto-char (match-end 0)) + (let* ((start (save-excursion + (goto-char (match-beginning 0)) + (forward-line (if (< nlines 0) nlines (- nlines))) + (point))) + (end (save-excursion + (goto-char (match-end 0)) + (if (> nlines 0) + (forward-line (1+ nlines)) + (forward-line 1)) + (point))) + (tag (format "%3d" linenum)) + (empty (make-string (length tag) ?\ )) + tem) + (save-excursion + (setq tem (make-marker)) + (set-marker tem (point)) + (set-buffer standard-output) + (setq occur-pos-list (cons tem occur-pos-list)) + (or first (zerop nlines) + (insert "--------\n")) + (setq first nil) + (insert-buffer-substring buffer start end) + (backward-char (- end start)) + (setq tem (if (< nlines 0) (- nlines) nlines)) + (while (> tem 0) + (insert empty ?:) + (forward-line 1) + (setq tem (1- tem))) + (let ((this-linenum linenum)) + (set-marker final-context-start + (+ (point) (- (match-end 0) (match-beginning 0)))) + (while (< (point) final-context-start) + (if (null tag) + (setq tag (format "%3d" this-linenum))) + (insert tag ?:))))))) + (set-buffer-modified-p nil)))) +;;; verilog.el ends here