Skip to content

Commit 44cd062

Browse files
committed
Add hierarchy support for tree-sitter backend
1 parent 1a5fd18 commit 44cd062

File tree

5 files changed

+216
-85
lines changed

5 files changed

+216
-85
lines changed

test/verilog-ext-tests-hierarchy.el

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,30 @@
6767
(clone-indirect-buffer-other-window "*debug*" t))
6868
(insert-file-contents test-file)
6969
(verilog-mode)
70-
(verilog-ext-workspace-hierarchy-builtin-parse)
70+
(verilog-ext-workspace-hierarchy-parse)
7171
(verilog-ext-hierarchy-current-buffer)))
7272
;; builtin-outshine
7373
((and (eq verilog-ext-hierarchy-backend 'builtin)
7474
(eq verilog-ext-hierarchy-frontend 'outshine))
75-
(verilog-ext-workspace-hierarchy-builtin-parse)
75+
(verilog-ext-workspace-hierarchy-parse)
76+
(save-window-excursion
77+
(find-file test-file)
78+
(verilog-ext-hierarchy-current-buffer)
79+
(buffer-substring-no-properties (point-min) (point-max))))
80+
;; tree-sitter-hierarchy
81+
((and (eq verilog-ext-hierarchy-backend 'tree-sitter)
82+
(eq verilog-ext-hierarchy-frontend 'hierarchy))
83+
(with-temp-buffer
84+
(when debug
85+
(clone-indirect-buffer-other-window "*debug*" t))
86+
(insert-file-contents test-file)
87+
(verilog-ts-mode)
88+
(verilog-ext-workspace-hierarchy-parse)
89+
(verilog-ext-hierarchy-current-buffer)))
90+
;; tree-sitter-outshine
91+
((and (eq verilog-ext-hierarchy-backend 'tree-sitter)
92+
(eq verilog-ext-hierarchy-frontend 'outshine))
93+
(verilog-ext-workspace-hierarchy-parse)
7694
(save-window-excursion
7795
(find-file test-file)
7896
(verilog-ext-hierarchy-current-buffer)

test/verilog-ext-tests-tree-sitter.el

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
(require 'verilog-ext-tests-font-lock)
2929
(require 'verilog-ext-tests-indent)
30+
(require 'verilog-ext-tests-hierarchy)
3031

3132

3233
(ert-deftest tree-sitter::font-lock ()
@@ -42,6 +43,52 @@
4243
(dolist (file test-files)
4344
(should (verilog-ext-test-indent-compare file :tree-sitter)))))
4445

46+
(ert-deftest hierarchy::tree-sitter-hierarchy ()
47+
(let ((verilog-ext-hierarchy-backend 'tree-sitter)
48+
(verilog-ext-hierarchy-frontend 'hierarchy))
49+
(should (string= (with-temp-buffer
50+
(hierarchy-print (verilog-ext-test-hierarchy) (lambda (node) node))
51+
(buffer-substring-no-properties (point-min) (point-max)))
52+
"instances
53+
instances.block0:I_BLOCK0
54+
instances.block1:I_BLOCK1
55+
instances.block2:I_BLOCK2
56+
instances.block3:I_BLOCK3
57+
instances.test_if:I_TEST_IF
58+
instances.test_if_params:ITEST_IF_PARAMS
59+
instances.test_if_params_array:ITEST_IF_PARAMS_ARRAY[5:0]
60+
instances.test_if_params_empty:I_TEST_IF_PARAMS_EMPTY
61+
instances.block_ws_0:I_BLOCK_WS_0
62+
instances.block_ws_1:I_BLOCK_WS_1
63+
"))))
64+
65+
(ert-deftest hierarchy::tree-sitter-outshine ()
66+
(let ((verilog-ext-hierarchy-backend 'tree-sitter)
67+
(verilog-ext-hierarchy-frontend 'outshine))
68+
(should (equal (verilog-ext-test-hierarchy)
69+
"// Hierarchy generated by `verilog-ext'
70+
71+
// * instances
72+
// ** block0
73+
// ** block1
74+
// ** block2
75+
// ** block3
76+
// ** test_if
77+
// ** test_if_params
78+
// ** test_if_params_array[5:0]
79+
// ** test_if_params_empty
80+
// ** block_ws_0
81+
// ** block_ws_1
82+
83+
84+
// * Buffer local variables
85+
// Local Variables:
86+
// eval: (verilog-mode 1)
87+
// eval: (verilog-ext-hierarchy-outshine-nav-mode 1)
88+
// End:
89+
"))))
90+
91+
4592

4693
(provide 'verilog-ext-tests-tree-sitter)
4794

ts-mode/verilog-ts-mode.el

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ Snippet fetched from `treesit--indent-1'."
154154
(interactive)
155155
(verilog-ts-nodes-current-buffer "module_instantiation"))
156156

157+
(defun verilog-ts-module-declarations ()
158+
"Return module declarations of current file."
159+
(interactive)
160+
(verilog-ts-nodes-current-buffer "module_declaration"))
161+
157162
(defun verilog-ts-always-blocks ()
158163
"Return always blocks of current file."
159164
(interactive)
@@ -1102,19 +1107,18 @@ SystemVerilog parser."
11021107
((null ts-node)
11031108
subtrees)
11041109
(subtrees
1105-
(let ((parent-label
1106-
(funcall verilog-ts-imenu-format-parent-item-label-function
1107-
type name))
1108-
(jump-label
1109-
(funcall
1110-
verilog-ts-imenu-format-parent-item-jump-label-function
1111-
type name)))
1110+
(let ((parent-label (funcall verilog-ts-imenu-format-parent-item-label-function
1111+
type
1112+
name))
1113+
(jump-label (funcall verilog-ts-imenu-format-parent-item-jump-label-function
1114+
type
1115+
name)))
11121116
`((,parent-label
11131117
,(cons jump-label marker)
11141118
,@subtrees))))
1115-
(t (let ((label
1116-
(funcall verilog-ts-imenu-format-item-label-function
1117-
type name)))
1119+
(t (let ((label (funcall verilog-ts-imenu-format-item-label-function
1120+
type
1121+
name)))
11181122
(list (cons label marker)))))))
11191123

11201124
(defun verilog-ts-imenu-create-index (&optional node)

verilog-ext-hierarchy.el

Lines changed: 115 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ backend."
7272

7373

7474
;;;; Utils
75+
;;;;; hierarchy.el
76+
(defvar verilog-ext-hierarchy-current-flat-hierarchy nil
77+
"Current flat hierarchy.
78+
79+
Used by `verilog-ext-hierarchy-extract--internal' and its subroutines.
80+
81+
Needed since `verilog-ext-hierarchy-extract--childrenfn' can only have one
82+
argument (item).")
83+
7584
(defun verilog-ext-hierarchy--get-node-leaf (node)
7685
"Return leaf name of hierarchical reference NODE.
7786
E.g: return \"leaf\" for \"top.block.subblock.leaf\"."
@@ -84,6 +93,50 @@ E.g: return \"top.block.subblock\" for \"top.block.subblock.leaf\"."
8493
(unless (string= prefix "")
8594
prefix)))
8695

96+
(defun verilog-ext-hierarchy-extract--childrenfn (item)
97+
"Childrenfn for `hierarchy'.
98+
Arg ITEM are hierarchy nodes."
99+
(let* ((prefix (verilog-ext-hierarchy--get-node-prefix item))
100+
(leaf (verilog-ext-hierarchy--get-node-leaf item))
101+
(children (cdr (assoc (car (split-string leaf ":")) verilog-ext-hierarchy-current-flat-hierarchy))))
102+
(mapcar (lambda (child) (concat (when prefix (concat prefix ".")) leaf "." child)) children)))
103+
104+
(defun verilog-ext-hierarchy-extract--construct-node (node hierarchy)
105+
"Recursively build HIERARCHY for NODE using childrenfn."
106+
(let ((children (mapcar (lambda (child)
107+
(concat node "." child))
108+
(cdr (assoc (verilog-ext-hierarchy--get-node-leaf node) verilog-ext-hierarchy-current-flat-hierarchy)))))
109+
(when children
110+
(hierarchy-add-tree hierarchy node nil #'verilog-ext-hierarchy-extract--childrenfn)
111+
(dolist (child children)
112+
(verilog-ext-hierarchy-extract--construct-node child hierarchy)))
113+
hierarchy))
114+
115+
(defun verilog-ext-hierarchy-extract--internal (module)
116+
"Construct hierarchy struct for MODULE.
117+
118+
Modules and instances will be analyzed from the value of
119+
`verilog-ext-hierarchy-current-flat-hierarchy'.
120+
This alist must be populated before calling the function!
121+
122+
`verilog-ext-hierarchy-current-flat-hierarchy' is an alist of the form:
123+
((moduleA instanceA1:NAME_A1 instanceA2:NAME_A2 ...)
124+
(moduleB instanceB1:NAME_B1 instanceB2:NAME_B2 ...)
125+
..)
126+
127+
Return populated `hierarchy' struct."
128+
;; Some checks
129+
(unless verilog-ext-hierarchy-current-flat-hierarchy
130+
(user-error "Empty hierarchy database, maybe run first `verilog-ext-workspace-hierarchy-parse'?"))
131+
(unless (assoc module verilog-ext-hierarchy-current-flat-hierarchy)
132+
(user-error "Could not find %s in the flat-hierarchy" module))
133+
(if (not (cdr (assoc module verilog-ext-hierarchy-current-flat-hierarchy)))
134+
(user-error "Current module has no instances")
135+
;; Construct node
136+
(verilog-ext-hierarchy-extract--construct-node module (hierarchy-new))))
137+
138+
139+
;;;;; Frontend format conversion
87140
(defun verilog-ext-hierarchy--convert-struct-to-string (hierarchy-struct)
88141
"Convert HIERARCHY-STRUCT to a string.
89142
Used to convert hierarchy formats for displaying on different frontends."
@@ -162,6 +215,7 @@ Alist will be of the form (module instance1:NAME1 instance2:NAME2 ...)."
162215
;; Return value
163216
hierarchy-alist))
164217

218+
165219
;;;; Backends/extraction
166220
;;;;; Vhier
167221
(defconst verilog-ext-hierarchy-vhier-buffer-name "*Verilog-Perl*"
@@ -173,10 +227,9 @@ Alist will be of the form (module instance1:NAME1 instance2:NAME2 ...)."
173227
"--no-missing"
174228
"--missing-modules"))
175229

176-
(defun verilog-ext-hierarchy-extract-vhier (module)
230+
(defun verilog-ext-hierarchy-vhier-extract (module)
177231
"Extract hierarchy of MODULE using Verilog-Perl vhier as a backend.
178232
Return hierarchy as an indented string."
179-
(interactive)
180233
(unless (executable-find "vhier")
181234
(error "Executable vhier not found"))
182235
(let* ((library-args (verilog-expand-command "__FLAGS__"))
@@ -199,74 +252,73 @@ Return hierarchy as an indented string."
199252
(verilog-ext-replace-regexp-whole-buffer (concat "\\(?1:" verilog-identifier-sym-re "\\) \\(?2:" verilog-identifier-sym-re "\\)") "\\2:\\1")
200253
(buffer-substring-no-properties (point-min) (point-max)))))
201254

202-
;;;;; Builtin
203-
(defvar verilog-ext-hierarchy-builtin-current-flat-hierarchy nil
204-
"Current flat hierarchy.
205-
Used by `verilog-ext-hierarchy-extract-builtin' and its subroutines. Needed
206-
since `verilog-ext-hierarchy-extract-builtin--childrenfn' can only have one
207-
argument (item).")
208255

256+
;;;;; Tree-sitter
257+
(defun verilog-ext-hierarchy-tree-sitter-parse-file (file)
258+
"Return alist with modules and instances from FILE.
259+
260+
Each alist element car is a found module in the file.
261+
These elements cdr are the list of that module's instances.
262+
263+
Instances have module:INST format to make them unique for `hierarchy'
264+
displaying. Modules have no instance name since they are parsed on its
265+
declaration."
266+
(let (modules inst-nodes inst-type inst-name instances module-instances-alist)
267+
(with-temp-buffer
268+
(insert-file-contents file)
269+
(verilog-ts-mode)
270+
(setq modules (verilog-ts-module-declarations))
271+
(dolist (module modules)
272+
(goto-char (cadr module))
273+
(setq inst-nodes (cdr (treesit-induce-sparse-tree (verilog-ts--node-at-bol) "module_instantiation")))
274+
(dolist (inst-node inst-nodes)
275+
(setq inst-type (treesit-node-text (treesit-search-subtree (car inst-node) "simple_identifier") :no-props))
276+
(setq inst-name (treesit-node-text (treesit-search-subtree (car inst-node) "name_of_instance") :no-props))
277+
(push (concat inst-type ":" inst-name) instances))
278+
(push (cons (car module) (nreverse instances)) module-instances-alist))
279+
module-instances-alist)))
280+
281+
(defun verilog-ext-hierarchy-tree-sitter-extract (module)
282+
"Extract hierarchy of MODULE using tree-sitter as a backend.
283+
284+
Populate `verilog-ext-hierarchy-current-flat-hierarchy' with alist of modules
285+
and instances."
286+
(unless (eq verilog-ext-hierarchy-backend 'tree-sitter)
287+
(error "Wrong backend!"))
288+
(verilog-ext-hierarchy-extract--internal module))
289+
290+
291+
;;;;; Builtin
209292
(defun verilog-ext-hierarchy-builtin-parse-file (file)
210-
"Return list with modules and instances from FILE.
293+
"Return alist with modules and instances from FILE.
211294
212-
The returned list car is the first found module in the file.
213-
The returned list cdr is the list of that module's instances.
295+
Each alist element car is a found module in the file.
296+
These elements cdr are the list of that module's instances.
214297
215298
Instances have module:INST format to make them unique for `hierarchy'
216299
displaying. Modules have no instance name since they are parsed on its
217300
declaration."
218-
(let (modules instances)
301+
(let (modules instances module-instances-alist)
219302
(with-temp-buffer
220303
(insert-file-contents file)
221304
(verilog-mode)
222305
(setq modules (verilog-ext-scan-buffer-modules))
223-
(when modules
306+
(dolist (module modules)
307+
(setq instances nil)
224308
(while (verilog-ext-find-module-instance-fwd)
225309
(push (concat (match-string-no-properties 1) ":" (match-string-no-properties 2)) instances))
226-
(cons (car modules) (reverse instances))))))
227-
228-
(defun verilog-ext-hierarchy-extract-builtin--childrenfn (item)
229-
"Childrenfn for `hierarchy'.
230-
Arg ITEM are hierarchy nodes."
231-
(let* ((prefix (verilog-ext-hierarchy--get-node-prefix item))
232-
(leaf (verilog-ext-hierarchy--get-node-leaf item))
233-
(children (cdr (assoc (car (split-string leaf ":")) verilog-ext-hierarchy-builtin-current-flat-hierarchy))))
234-
(mapcar (lambda (child) (concat (when prefix (concat prefix ".")) leaf "." child)) children)))
310+
(push (cons module (reverse instances)) module-instances-alist))
311+
module-instances-alist)))
235312

236-
(defun verilog-ext-hierarchy-extract-builtin--construct-node (node hierarchy)
237-
"Recursively build HIERARCHY for NODE using childrenfn."
238-
(let ((children (mapcar (lambda (child)
239-
(concat node "." child))
240-
(cdr (assoc (verilog-ext-hierarchy--get-node-leaf node) verilog-ext-hierarchy-builtin-current-flat-hierarchy)))))
241-
(when children
242-
(hierarchy-add-tree hierarchy node nil #'verilog-ext-hierarchy-extract-builtin--childrenfn)
243-
(dolist (child children)
244-
(verilog-ext-hierarchy-extract-builtin--construct-node child hierarchy)))
245-
hierarchy))
313+
(defun verilog-ext-hierarchy-builtin-extract (module)
314+
"Extract hierarchy of MODULE using builtin Elisp backend.
246315
247-
(defun verilog-ext-hierarchy-extract-builtin (module &optional flat-hierarchy)
248-
"Construct hierarchy for MODULE using builtin backend.
316+
Populate `verilog-ext-hierarchy-current-flat-hierarchy' with alist of modules
317+
and instances."
318+
(unless (eq verilog-ext-hierarchy-backend 'builtin)
319+
(error "Wrong backend!"))
320+
(verilog-ext-hierarchy-extract--internal module))
249321

250-
Modules and instances will be analyzed from FLAT-HIERARCHY input if provided.
251-
Otherwise, extract from `verilog-ext-hierarchy-builtin-current-flat-hierarchy':
252-
- This is a list of the form (module instance1:NAME1 instance2:NAME2 ...)
253-
254-
This optional arg is intended to be used for conversion between vhier/builtin.
255-
256-
Return populated `hierarchy' struct."
257-
(let ((hierarchy-struct (hierarchy-new))
258-
(hierarchy-alist (or flat-hierarchy
259-
verilog-ext-hierarchy-builtin-current-flat-hierarchy)))
260-
(unless hierarchy-alist
261-
(user-error "Empty hierarchy database, maybe run first `verilog-ext-workspace-hierarchy-builtin-parse'?"))
262-
(unless (assoc module hierarchy-alist)
263-
(user-error "Could not find %s in the flat-hierarchy" module))
264-
(if (not (cdr (assoc module hierarchy-alist)))
265-
(user-error "Current module has no instances")
266-
;; DANGER: Don't forget to update `verilog-ext-hierarchy-builtin-current-flat-hierarchy'
267-
;; before populating the`hierarchy-struct' if using flat-hierarchy as an input!
268-
(setq verilog-ext-hierarchy-builtin-current-flat-hierarchy hierarchy-alist)
269-
(verilog-ext-hierarchy-extract-builtin--construct-node module hierarchy-struct))))
270322

271323
;;;; Frontends/navigation
272324
;;;;; hierarchy.el
@@ -462,10 +514,13 @@ If these have been set before, keep their values."
462514
"Construct hierarchy for MODULE depending on selected backend."
463515
(cond (;; Verilog-Perl vhier
464516
(eq verilog-ext-hierarchy-backend 'vhier)
465-
(verilog-ext-hierarchy-extract-vhier module)) ; Returns indented string
466-
;; Built-in
467-
((eq verilog-ext-hierarchy-backend 'builtin)
468-
(verilog-ext-hierarchy-extract-builtin module)) ; Returns populated hierarchy struct
517+
(verilog-ext-hierarchy-vhier-extract module)) ; Returns indented string
518+
(;; Tree-sitter
519+
(eq verilog-ext-hierarchy-backend 'tree-sitter)
520+
(verilog-ext-hierarchy-tree-sitter-extract module)) ; Returns populated hierarchy struct
521+
(;; Built-in
522+
(eq verilog-ext-hierarchy-backend 'builtin)
523+
(verilog-ext-hierarchy-builtin-extract module)) ; Returns populated hierarchy struct
469524
;; Fallback
470525
(t (error "Must set a proper extraction backend in `verilog-ext-hierarchy-backend'"))))
471526

@@ -488,7 +543,8 @@ convert between an indented string and a populated hierarchy struct."
488543
(when (stringp hierarchy)
489544
(let ((top-module (string-trim-left (car (split-string (car (split-string hierarchy "\n")) ":")))) ; First line of the string, as parsed by vhier
490545
(hierarchy-alist (verilog-ext-hierarchy--convert-string-to-alist hierarchy)))
491-
(setq display-hierarchy (verilog-ext-hierarchy-extract-builtin top-module hierarchy-alist))))
546+
(setq verilog-ext-hierarchy-current-flat-hierarchy hierarchy-alist)
547+
(setq display-hierarchy (verilog-ext-hierarchy-extract--internal top-module))))
492548
(verilog-ext-hierarchy-display-twidget display-hierarchy))
493549
;; Fallback
494550
(t (error "Must set a proper display frontend in `verilog-ext-hierarchy-frontend'")))))

0 commit comments

Comments
 (0)