1#| -*-Scheme-*-
2
3Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4    1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6    Institute of Technology
7
8This file is part of MIT/GNU Scheme.
9
10MIT/GNU Scheme is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2 of the License, or (at
13your option) any later version.
14
15MIT/GNU Scheme is distributed in the hope that it will be useful, but
16WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with MIT/GNU Scheme; if not, write to the Free Software
22Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23USA.
24
25|#
26
27;;;; Major Mode for Verilog Programs
28
29(declare (usual-integrations))
30
31(define-command verilog-mode
32  "Enter Verilog mode."
33  ()
34  (lambda () (set-current-major-mode! (ref-mode-object verilog))))
35
36(define-major-mode verilog fundamental "Verilog"
37  "Major mode specialized for editing Verilog code.
38
39\\{verilog}"
40  (lambda (buffer)
41    (local-set-variable! syntax-table verilog-mode:syntax-table buffer)
42    (local-set-variable! syntax-ignore-comments-backwards #f buffer)
43    (local-set-variable! comment-column 40 buffer)
44    (local-set-variable! comment-locator-hook verilog-comment-locate buffer)
45    (local-set-variable! comment-indent-hook verilog-comment-indentation
46			 buffer)
47    (local-set-variable! comment-start "// " buffer)
48    (local-set-variable! comment-end "" buffer)
49    (standard-alternate-paragraph-style! buffer)
50    (local-set-variable! indent-line-procedure
51			 (ref-command keyparser-indent-line)
52			 buffer)
53    (local-set-variable! definition-start verilog-defun-start-regexp buffer)
54    (local-set-variable! require-final-newline #t buffer)
55    (local-set-variable! keyparser-description verilog-description buffer)
56    (local-set-variable! keyword-table verilog-keyword-table buffer)
57    (local-set-variable! local-abbrev-table
58			 (ref-variable verilog-mode-abbrev-table buffer)
59			 buffer)
60    (event-distributor/invoke! (ref-variable verilog-mode-hook buffer)
61			       buffer)))
62
63(define verilog-mode:syntax-table
64  (let ((syntax-table (make-char-syntax-table)))
65    (for-each (lambda (char) (set-char-syntax! syntax-table char "."))
66	      (string->list "+-=%<>&|"))
67    (set-char-syntax! syntax-table #\' "_")
68    (set-char-syntax! syntax-table #\` ". p")
69    (set-char-syntax! syntax-table #\# ". p")
70    (set-char-syntax! syntax-table #\@ ". p")
71    (set-char-syntax! syntax-table #\/ ". 1456")
72    (set-char-syntax! syntax-table #\* ". 23")
73    (set-char-syntax! syntax-table #\newline ">")
74    syntax-table))
75
76(define-key 'verilog #\linefeed 'reindent-then-newline-and-indent)
77(define-key 'verilog #\rubout 'backward-delete-char-untabify)
78(define-key 'verilog #\tab 'keyparser-indent-line)
79(define-key 'verilog #\c-m-\\ 'keyparser-indent-region)
80(define-key 'verilog #\) 'lisp-insert-paren)
81(define-key 'verilog #\] 'lisp-insert-paren)
82(define-key 'verilog #\} 'lisp-insert-paren)
83(define-key 'verilog #\m-tab 'complete-keyword)
84
85;;;; Syntax Description
86
87(define (verilog-comment-locate mark)
88  (let ((state (parse-partial-sexp mark (line-end mark 0))))
89    (and (parse-state-in-comment? state)
90	 (verilog-comment-match-start (parse-state-comment-start state))
91	 (cons (re-match-start 0) (re-match-end 0)))))
92
93(define (verilog-comment-match-start mark)
94  (re-match-forward "/\\(/+\\|\\*+\\)[ \t]*" mark))
95
96(define (verilog-comment-indentation mark)
97  (let ((column
98	 (cond ((or (and (line-start? mark)
99			 (match-forward "/*" mark))
100		    (match-forward "////" mark))
101		0)
102	       ((match-forward "///" mark)
103		(keyparser-compute-indentation mark #t))
104	       (else
105		(ref-variable comment-column mark)))))
106    (if (within-indentation? mark)
107	column
108	(max (+ (mark-column (horizontal-space-start mark)) 1)
109	     column))))
110
111(define verilog-defun-start-regexp
112  (string-append
113   "^"
114   (regexp-group "module" "macromodule" "primitive" "parameter")
115   (regexp-group "\\s " "$")))
116
117(define verilog-keyword-table
118  (alist->string-table
119   (map list
120	'("always" "and" "assign" "begin" "buf" "bufif0" "bufif1"
121		   "case" "casex" "casez" "cmos" "deassign" "default"
122		   "define" "defparam" "disable" "else" "end"
123		   "endcase" "endfunction" "endmodule" "endprimitive"
124		   "endtable" "endtask" "event" "for" "force"
125		   "forever" "fork" "function" "if" "ifdef" "include"
126		   "initial" "inout" "input" "integer" "join" "macromodule"
127		   "module" "nand" "negedge" "nmos" "nor" "not"
128		   "notif0" "notif1" "or" "output" "parameter" "pmos"
129		   "posedge" "primitive" "pulldown" "pullup" "rcmos"
130		   "real" "reg" "release" "repeat" "rnmos" "rpmos"
131		   "rtran" "rtranif0" "rtranif1" "scalared" "supply0"
132		   "supply1" "table" "task" "time" "tran" "tranif0"
133		   "tranif1" "tri" "tri0" "tri1" "triand" "trior"
134		   "trireg" "udp" "vectored" "wait" "wand" "while"
135		   "wire" "wor" "xnor" "xor"))
136   #f))
137
138(define (parse-forward-past-semicolon start end)
139  (let loop ((start start) (state #f))
140    (let ((semi (char-search-forward #\; start end #f)))
141      (and semi
142	   (let ((state (parse-partial-sexp start semi #f #f state)))
143	     (if (in-char-syntax-structure? state)
144		 (loop semi state)
145		 semi))))))
146
147(define (parse-forward-past-block-tag start end)
148  (if (re-match-forward "[ \t]*:[ \t]*" start end)
149      (forward-one-sexp start end)
150      start))
151
152(define (parse-forward-noop start end)
153  end
154  start)
155
156(define (continued-header-indent mark)
157  (+ (mark-indentation mark)
158     (ref-variable verilog-continued-header-offset mark)))
159
160(define (continued-statement-indent mark)
161  (+ (mark-indentation mark)
162     (ref-variable verilog-continued-statement-offset mark)))
163
164(define verilog-description
165  (make-keyparser-description
166   'FIND-STATEMENT-END
167   parse-forward-past-semicolon
168   'INDENT-CONTINUED-STATEMENT
169   continued-statement-indent
170   'INDENT-CONTINUED-COMMENT
171   (lambda (mark)
172     (mark-column (or (verilog-comment-match-start mark) mark)))))
173
174(define-keyparser-statement-leader #\# verilog-description
175  (re-compile-char #\# #f)
176  forward-one-sexp)
177
178(define-keyparser-statement-leader #\@ verilog-description
179  (re-compile-char #\@ #f)
180  forward-one-sexp)
181
182(define (define-standard-keyword keyword end parse-header)
183  (define-keyparser-pattern keyword verilog-description
184    (list
185     (make-keyparser-fragment 'KEYWORD
186			      keyword
187			      'PARSE-HEADER
188			      parse-header
189			      'INDENT-HEADER
190			      continued-header-indent
191			      'PARSE-BODY
192			      keyparse-forward
193			      'INDENT-BODY
194			      continued-statement-indent)
195     (and end
196	  (make-keyparser-fragment 'KEYWORD
197				   end
198				   'PARSE-HEADER
199				   parse-forward-noop
200				   'INDENT-HEADER
201				   continued-header-indent
202				   'PARSE-BODY
203				   #f
204				   'INDENT-BODY
205				   #f)))))
206
207(define-standard-keyword "always" #f
208  parse-forward-noop)
209
210(define-standard-keyword "begin" "end"
211  parse-forward-past-block-tag)
212
213(define-standard-keyword "case" "endcase"
214  forward-one-sexp)
215
216(define-standard-keyword "casex" "endcase"
217  forward-one-sexp)
218
219(define-standard-keyword "casez" "endcase"
220  forward-one-sexp)
221
222(define-standard-keyword "else" #f
223  parse-forward-noop)
224
225(define-standard-keyword "for" #f
226  forward-one-sexp)
227
228(define-standard-keyword "forever" #f
229  parse-forward-noop)
230
231(define-standard-keyword "fork" "join"
232  parse-forward-past-block-tag)
233
234(define-standard-keyword "function" "endfunction"
235  parse-forward-past-semicolon)
236
237(define-standard-keyword "if" #f
238  forward-one-sexp)
239
240(define-standard-keyword "initial" #f
241  parse-forward-noop)
242
243(define-standard-keyword "macromodule" "endmodule"
244  parse-forward-past-semicolon)
245
246(define-standard-keyword "module" "endmodule"
247  parse-forward-past-semicolon)
248
249(define-standard-keyword "primitive" "endprimitive"
250  parse-forward-past-semicolon)
251
252(define-standard-keyword "repeat" #f
253  forward-one-sexp)
254
255(define-standard-keyword "table" "endtable"
256  parse-forward-noop)
257
258(define-standard-keyword "task" "endtask"
259  parse-forward-past-semicolon)
260
261(define-standard-keyword "while" #f
262  forward-one-sexp)