-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
verilog-ext-typedef.el
232 lines (198 loc) · 10.2 KB
/
verilog-ext-typedef.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
;;; verilog-ext-typedef.el --- Verilog-ext Typedefs -*- lexical-binding: t -*-
;; Copyright (C) 2022-2024 Gonzalo Larumbe
;; Author: Gonzalo Larumbe <[email protected]>
;; URL: https://github.com/gmlarumbe/verilog-ext
;; 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 3 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, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Typedef utils
;;; Code:
(require 'async)
(require 'verilog-ext-nav)
(defvar verilog-ext-typedef-align-words-current-proj nil)
(defvar verilog-ext-typedef-align-words-re-alist nil)
(defconst verilog-ext-typedef-cache-file (file-name-concat verilog-ext-cache-dir "typedefs"))
(defconst verilog-ext-typedef-cache-log-file (file-name-concat verilog-ext-cache-dir "typedefs.log"))
(defconst verilog-ext-typedef-async-inject-variables-re
(eval-when-compile
(regexp-opt '("load-path"
"buffer-file-name"
"default-directory"
"verilog-ext-project-alist")
'symbols)))
(defun verilog-ext-typedef--var-find (regex &optional limit)
"Search for REGEX and bound to LIMIT.
Match data is expected to fit that one of
`verilog-ext-typedef-var-decl-single-re' or
`verilog-ext-typedef-var-decl-multiple-re'."
(let (found pos type)
(save-excursion
(while (and (not found)
(verilog-re-search-forward regex limit t))
(setq type (match-string-no-properties 1))
(unless (or (member type verilog-keywords)
(save-excursion
(goto-char (match-beginning 1))
(verilog-in-parenthesis-p)))
(setq found t)
(setq pos (point)))))
(when found
(goto-char pos)
type)))
(defun verilog-ext-typedef--var-buffer-update (regex)
"Scan REGEX on current buffer and update list of user typedefs.
See `verilog-ext-typedef-align-words-current-proj'.
Used for fontification and alignment."
(let (type)
(save-excursion
(goto-char (point-min))
(while (setq type (verilog-ext-typedef--var-find regex))
(unless (member type verilog-ext-typedef-align-words-current-proj)
(push type verilog-ext-typedef-align-words-current-proj))))))
(defun verilog-ext-typedef--tf-args-buffer-update ()
"Scan functions/tasks arguments on current buffer to update user typedefs list.
See `verilog-ext-typedef-align-words-current-proj'.
Used for fontification and alignment."
(let (tf-args arg-proc) ; tf-args is expected to be a list of strings
(save-excursion
(goto-char (point-min))
;; Iterate over file functions and tasks
(while (setq tf-args (alist-get 'args (verilog-ext-find-function-task-fwd)))
(unless (equal tf-args '(""))
(dolist (arg tf-args)
;; Iterate over words of one argument and process them to obtain the typedef
(setq arg-proc arg)
;; Skip verilog keywords
(while (string-match (concat "^" verilog-ext-keywords-re "\\s-*") arg-proc)
(setq arg-proc (substring arg-proc (match-end 0) (length arg-proc))))
;; Typedef word will be the first one of the argument
(when (equal 0 (string-match (string-remove-suffix ";" verilog-ext-typedef-var-decl-single-re) arg-proc))
(setq arg-proc (car (split-string arg-proc " ")))
(unless (member arg-proc verilog-ext-typedef-align-words-current-proj)
(push arg-proc verilog-ext-typedef-align-words-current-proj)))))))))
(defun verilog-ext-typedef--class-buffer-update ()
"Scan class declarations on current buffer to update user typedef list."
(let (word)
(save-excursion
(goto-char (point-min))
(while (setq word (alist-get 'name (verilog-ext-find-class-fwd)))
(unless (member word verilog-ext-typedef-align-words-current-proj)
(push word verilog-ext-typedef-align-words-current-proj))))))
(defun verilog-ext-typedef--typedef-buffer-update (regex)
"Scan REGEX typedef declarations on current buffer to update user typedef list."
(let (word)
(save-excursion
(goto-char (point-min))
(while (verilog-re-search-forward regex nil t)
(setq word (match-string-no-properties 2))
(unless (member word verilog-ext-typedef-align-words-current-proj)
(push word verilog-ext-typedef-align-words-current-proj))))))
(defun verilog-ext-typedef--var-decl-update ()
"Scan Verilog buffers and update typedef vars.
I.e: populate `verilog-ext-typedef-align-words-current-proj'."
(verilog-ext-typedef--var-buffer-update verilog-ext-typedef-var-decl-single-re)
(verilog-ext-typedef--var-buffer-update verilog-ext-typedef-var-decl-multiple-re)
(verilog-ext-typedef--tf-args-buffer-update)
(verilog-ext-typedef--class-buffer-update)
(verilog-ext-typedef--typedef-buffer-update verilog-ext-typedef-class-re)
(verilog-ext-typedef--typedef-buffer-update verilog-ext-typedef-generic-re))
(defun verilog-ext-typedef-get (&optional verbose)
"Scan all (System)Verilog files of current project and udpate typedef list.
It will return the updated value of
`verilog-ext-typedef-align-words-current-proj', which can be used later along
with `verilog-regexp-words' to update the variable
`verilog-align-typedef-regexp'. This enables the fontification and alignment of
user typedefs.
If optional arg VERBOSE is enabled, dump output to a logfile for potential debug
in corresponding async function."
(interactive "P")
(let* ((proj (verilog-ext-buffer-proj))
(files (verilog-ext-proj-files proj))
(num-files (length files))
(num-files-processed 0)
(log-file verilog-ext-typedef-cache-log-file)
(tags-progress-reporter (make-progress-reporter "[Typedefs collection]: " 0 num-files)))
(setq verilog-ext-typedef-align-words-current-proj nil) ; Reset value
(when verbose
(delete-file log-file))
(dolist (file files)
(progress-reporter-update tags-progress-reporter num-files-processed (format "[%s]" file))
(when verbose
(append-to-file (format "(%0d%%) [Typedef collection] Processing %s\n" (/ (* num-files-processed 100) num-files) file) nil log-file))
(with-temp-buffer
(insert-file-contents file)
(verilog-ext-with-no-hooks
(verilog-mode))
(verilog-ext-typedef--var-decl-update))
(setq num-files-processed (1+ num-files-processed)))
;; Postprocess obtained results (remove keywords and generic types that were uppercase)
(mapc (lambda (elm)
(when (member elm verilog-keywords)
(delete elm verilog-ext-typedef-align-words-current-proj)))
verilog-ext-typedef-align-words-current-proj)
(let ((case-fold-search nil))
(setq verilog-ext-typedef-align-words-current-proj (seq-remove (lambda (s)
(not (string-match-p "[[:lower:]]" s)))
verilog-ext-typedef-align-words-current-proj)))
;; Store results
(when verilog-ext-typedef-align-words-current-proj
(verilog-ext-proj-setcdr proj verilog-ext-typedef-align-words-re-alist (verilog-regexp-words verilog-ext-typedef-align-words-current-proj)))
(when verilog-ext-cache-enable
(verilog-ext-serialize verilog-ext-typedef-align-words-re-alist verilog-ext-typedef-cache-file))
;; Report end and return value for async processing
(message "Finished collection of typedefs!")
verilog-ext-typedef-align-words-re-alist))
(defun verilog-ext-typedef-get-async (&optional verbose)
"Update typedef list of current asynchronously.
With current-prefix or VERBOSE, dump output log."
(interactive "P")
(let ((proj-root (verilog-ext-buffer-proj-root)))
(unless proj-root
(user-error "Not in a Verilog project buffer"))
(message "Starting typedef collection for %s" proj-root)
(async-start
`(lambda ()
,(async-inject-variables verilog-ext-typedef-async-inject-variables-re)
(require 'verilog-ext)
(verilog-ext-typedef-get ,@verbose))
(lambda (result)
(message "Finished collection of typedefs!")
(setq verilog-ext-typedef-align-words-re-alist result)))))
(defun verilog-ext-typedef-proj-hook ()
"Hook to run when typedef feature is enabled."
(let ((proj (verilog-ext-buffer-proj)))
(when (and (eq major-mode 'verilog-mode) proj)
(setq-local verilog-align-typedef-regexp (verilog-ext-aget verilog-ext-typedef-align-words-re-alist proj)))))
(defun verilog-ext-typedef-set (&optional disable)
"Enable or DISABLE typedef feature.
INFO: Enabling this feature will override the value of
`verilog-align-typedef-regexp'."
(if disable
(remove-hook 'verilog-mode-hook #'verilog-ext-typedef-proj-hook)
(add-hook 'verilog-mode-hook #'verilog-ext-typedef-proj-hook)
(when verilog-ext-cache-enable
(setq verilog-ext-typedef-align-words-re-alist (verilog-ext-unserialize verilog-ext-typedef-cache-file)))))
(defun verilog-ext-typedef-clear-cache (&optional all)
"Clear typedef cache files for current project.
With prefix arg, clear cache for ALL projects."
(interactive "P")
(if (not all)
(let ((proj (verilog-ext-buffer-proj)))
(unless proj
(user-error "Not in a Verilog project buffer"))
(verilog-ext-proj-setcdr proj verilog-ext-typedef-align-words-re-alist nil)
(verilog-ext-serialize verilog-ext-typedef-align-words-re-alist verilog-ext-typedef-cache-file)
(message "[%s] Cleared typedef cache!" proj))
(setq verilog-ext-typedef-align-words-re-alist nil)
(verilog-ext-serialize verilog-ext-typedef-align-words-re-alist verilog-ext-typedef-cache-file)
(message "Cleared all projects tags cache!")))
(provide 'verilog-ext-typedef)
;;; verilog-ext-typedef.el ends here