changelog shortlog tags changeset files revisions annotate raw

grok-lisp.el

changeset 10: 94cb77bd35e5
parent:faa7d0170f17
author: Dmitry Dzhus <dima@sphinx.net.ru>
date: Sun Aug 03 15:05:18 2008 +0400 (5 months ago)
permissions: -rw-r--r--
description: Small fix
1;;; grok-lisp.el --- Extract or graph sources with Emacs Semantic
2
3;; Copyright (C) 2007, 2008 Dmitry Dzhus
4
5;; Author: Dmitry Dzhus <mail@sphinx.net.ru>
6;; Keywords: lisp semantic graph
7
8;; This program is free software: you can redistribute it and/or
9;; modify it under the terms of the GNU General Public License as
10;; published by the Free Software Foundation, either version 3 of the
11;; License, or (at your option) any later version.
12
13;; This program is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with this program. If not, see
20;; <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23
24;; This code is intended to be used in Emacs batch mode. It allows you
25;; to print contents of Semantic tag in file to standard output and to
26;; print dependency DOT graph of Semantic tags in a list of files. See
27;; article at http://sphinx.net.ru/blog/entry/semantic-wizardry/ (in
28;; russian).
29
30;; The following command prints source depgraph to standard output:
31;;
32;; emacs --batch -l grok-lisp.el --exec "(print-files-depgraph '(function) \"some-file.el\")" 2> /dev/null
33;;
34;; This is for printing contents of arbitary tag in arbitary source file:
35;;
36;; emacs --batch --l grok-lisp.el --exec '(print-tag-from-file "some-tag" "some-source.scm")' 2> /dev/null
37
38;; This package has been tested with Emacs Lisp and Scheme sources. It
39;; contains a Lisp specific hack in `get-tag-deps', you may need to
40;; tweak it in order to parse sources in other languages.
41
42;;; Code:
43
44(require 'semantic)
45(require 'semanticdb)
46(semanticdb-toggle-global-mode)
47
48(defun get-file-tags (file-name)
49 "Return a Semantic tag table in FILE-NAME."
50 (with-current-buffer
51 (find-file-noselect file-name)
52 (semantic-fetch-tags)))
53
54(defun get-tag-body (tag)
55 "Return full TAG source code as a string.
56
57TAG is valid Semantic tag."
58 (let ((from (semantic-tag-start tag))
59 (to (semantic-tag-end tag))
60 (buffer (semantic-tag-buffer tag)))
61 (with-current-buffer buffer
62 (buffer-substring from to))))
63
64(defun get-tag-deps (tag tag-table types)
65 "Scan TAG for tags which are also in TAG-TABLE.
66
67Only tokens with one of specified TYPES are considered to be a
68tag dependency."
69(let ((from (semantic-tag-start tag))
70 (to (semantic-tag-end tag))
71 (buffer (semantic-tag-buffer tag))
72 ;; Build associative list with tag names as keys
73 (deps (mapcar
74 (lambda (tag)
75 (cons (semantic-tag-name tag)
76 tag))
77 tag-table)))
78 (with-current-buffer buffer
79 (let (result)
80 ;; cddddr is a Lisp-oriented hack to prevent tag itself from
81 ;; inclusion to dependency list
82 (dolist (lexem (cddddr (semantic-lex from to 1.0e+INF)) result)
83 (if (memq (car lexem) types)
84 (let* ((lexem-string (buffer-substring
85 (cadr lexem)
86 (cddr lexem)))
87 (found-tag (assoc lexem-string
88 deps)))
89 (if found-tag
90 (add-to-list 'result (cdr found-tag) t)))))))))
91
92(defun print-tag-from-file (tag-name file-name)
93 "Print body of tag with TAG-NAME from FILE-NAME."
94(interactive "sTag name: \nfFile name: ")
95 (let ((tag-table (get-file-tags file-name)))
96 (princ (format "%s"
97 (get-tag-body
98 (semantic-find-first-tag-by-name
99 tag-name
100 tag-table))))))
101
102(defun get-file-tag-classes (file-name classes)
103 "Get a list of all tags declared in FILE-NAME which class is in CLASSES.
104
105CLASSES is a list of Semantic classes."
106 (let ((result)
107 (all-tags (get-file-tags file-name)))
108 (dolist (tag-class classes result)
109 (setq result (append result
110 (semantic-find-tags-by-class
111 tag-class all-tags))))))
112
113(defun get-file-tag-classes-deep (file-name classes)
114 "List all tags declared in FILE-NAME and includes which class is in CLASSES.
115
116CLASSES is a list of Semantic classes.
117
118Does the same as `get-file-tag-classes' taking included files
119into account."
120 (with-current-buffer
121 (find-file-noselect file-name)
122 (let ((result))
123 (dolist (tag-class classes result)
124 (setq result (append result (semanticdb-strip-find-results
125 (semanticdb-find-tags-by-class tag-class))))))))
126
127(defun get-file-depgraph (file-name classes)
128 "Extract from FILE-NAME tags of CLASSES with their dependencies.
129
130CLASSES is a list of Semantic classes.
131
132Return a list of pairs (TAG . DEPS) where DEPS is a list of
133functions TAG depends on."
134(let ((deep-tag-table (get-file-tag-classes-deep file-name classes))
135 (file-tag-table (get-file-tag-classes file-name classes))
136 (depgraph))
137 (dolist (tag file-tag-table depgraph)
138 (let ((deps (get-tag-deps tag deep-tag-table '(NAME symbol))))
139 (add-to-list 'depgraph (cons tag deps) t)))))
140
141(defun print-files-depgraph (classes &rest file-names)
142 "Print depgraph with tags of CLASSES found in FILE-NAMES.
143
144CLASSES is a list of Semantic classes (description of Semantic
145classes is available in CEDET manual). Usually you'll use
146`'(function)'.
147
148FILE-NAMES are source code files to search for tags in.
149
150Output format is DOT, so it's suitable for further processing
151with Graphviz tools."
152(princ "digraph D {\n")
153 (princ "overlap=scale;\n")
154 (dolist (file file-names)
155 (let ((depgraph (get-file-depgraph file classes)))
156 (dolist (dep-list-for-tag depgraph)
157 (let ((function-name (semantic-tag-name
158 (car dep-list-for-tag))))
159 (princ (format "\"%s\";\n" function-name))
160 (dolist (dependency (cdr dep-list-for-tag))
161 (princ (format "\"%s\" -> \"%s\";\n"
162 (semantic-tag-name dependency)
163 function-name)))))))
164 (princ "}\n"))
165
166(provide 'grok-lisp)
167
168;;; grok-lisp.el ends here