Commit | Line | Data |
---|---|---|
34e49164 C |
1 | ;;; cocci.el --- a major mode for editing semantic patches |
2 | ||
3 | ;; Copyright (C) 2006-2007 Yoann Padioleau | |
4 | ||
7f004419 | 5 | ;; Please imagine a long and boring gnu-style copyright notice |
34e49164 C |
6 | ;; appearing just here. |
7 | ||
8 | ||
9 | ;; Emacs Lisp Archive Entry | |
7f004419 | 10 | ;; Author: Padioleau Yoann <yoann.padioleau@gmail.com>, |
34e49164 C |
11 | ;; Version: 0.2 |
12 | ;; Keywords: coccinelle patch refactoring program transformation | |
7f004419 | 13 | ;; URL: http://coccinelle.lip6.fr/ |
34e49164 C |
14 | |
15 | ||
16 | ;;; Usage | |
17 | ||
1be43e12 C |
18 | ;; Copy this file in your ~/.emacs.d directory |
19 | ;; | |
34e49164 | 20 | ;; Add the following lines to your ~/.emacs or equivalent: |
1be43e12 | 21 | ;; (load "~/.emacs.d/cocci.el") |
7f004419 | 22 | ;; (setq auto-mode-alist |
34e49164 | 23 | ;; (cons '("\\.cocci$" . cocci-mode) auto-mode-alist)) |
7f004419 | 24 | ;; (autoload 'cocci-mode "cocci" |
34e49164 C |
25 | ;; "Major mode for editing cocci code." t) |
26 | ;; | |
7f004419 C |
27 | ;; You can also use cocci-mode to edit the files containing the |
28 | ;; isomorphisms with: | |
29 | ;; (setq auto-mode-alist | |
34e49164 C |
30 | ;; (cons '("\\.iso$" . cocci-mode) auto-mode-alist)) |
31 | ;; | |
32 | ||
7f004419 | 33 | ;;; History |
34e49164 | 34 | |
7f004419 | 35 | ;; 2009-11-05 Nico: Cleanups, Change shortcut % to C-M-% (% is used in Python rule) |
34e49164 C |
36 | ;; Some cleanups done by Rene Rydhof Hansen |
37 | ||
7f004419 | 38 | ;;; Utilities |
34e49164 | 39 | |
7f004419 | 40 | (defun join-sep (sep xs) |
34e49164 C |
41 | (mapconcat 'identity xs sep)) |
42 | ||
43 | ||
7f004419 | 44 | ;;; Variables |
34e49164 C |
45 | |
46 | (defvar cocci-menu) | |
47 | ||
48 | ||
49 | ;; new (color) faces | |
50 | ||
51 | (defface cocci-number-face | |
52 | '((((background light)) (:foreground "black")) | |
53 | (((background dark)) (:foreground "yellow3"))) | |
54 | "Used for Cocci numbers") | |
55 | ||
56 | (defface cocci-punctuation-face | |
57 | '((((background light)) (:foreground "black")) | |
58 | (((background dark)) (:foreground "cyan"))) | |
59 | "Used for punctuation") | |
60 | ||
61 | (defface cocci-problem-face | |
62 | '((((background light)) (:background "deep pink")) | |
63 | (((background dark)) (:background "deep pink"))) | |
64 | "Highlighting potential problems") | |
65 | ||
66 | (defface cocci-special-face | |
67 | '((((background light)) (:foreground "blue")) | |
68 | (((background dark)) (:foreground "red"))) | |
69 | "") | |
70 | ||
71 | (defface cocci-rulename-face | |
72 | '((((background light)) (:foreground "DarkSlateGray")) | |
73 | (((background dark)) (:foreground "DarkSlateGray4"))) | |
74 | "Highlighting the rule names") | |
75 | ||
76 | (defface cocci-minus-face | |
0708f913 | 77 | '((((background light)) (:foreground "red")) |
34e49164 C |
78 | (((background dark)) (:foreground "SeaGreen3"))) |
79 | "Highlighting lines to be removed") | |
80 | ||
81 | (defface cocci-plus-face | |
0708f913 | 82 | '((((background light)) (:foreground "dark green")) |
34e49164 C |
83 | (((background dark)) (:foreground "salmon"))) |
84 | "Highlighting lines to be added") | |
85 | ||
86 | (defface cocci-match-face | |
87 | '((((background light)) (:foreground "violet red")) | |
88 | (((background dark)) (:foreground "purple"))) | |
89 | "Highlighting lines to be matched (sgrep)") | |
90 | ||
91 | ||
92 | ;; can look in lexer_cocci.mll for new identifiers | |
93 | ||
7f004419 C |
94 | (defconst cocci-c-keywords-list |
95 | '("if" "else" "while" "do" "for" "return" | |
34e49164 C |
96 | "sizeof" |
97 | "struct" "union" | |
fc1ad971 | 98 | "static" "extern" "const" "volatile" |
34e49164 C |
99 | "break" "continue" |
100 | "switch" "case" | |
101 | )) | |
102 | ||
7f004419 | 103 | (defconst cocci-declaration-keywords-list |
34e49164 | 104 | '("identifier" "type" "parameter" "constant" "expression" "statement" |
7f004419 C |
105 | "function" "local" "list" |
106 | "fresh" | |
34e49164 C |
107 | "position" |
108 | "idexpression" | |
109 | ||
fc1ad971 C |
110 | "context" |
111 | ||
7f004419 | 112 | "typedef" |
34e49164 C |
113 | "declarer" "iterator" |
114 | "pure" | |
115 | ;"error" "words" | |
7f004419 C |
116 | |
117 | "char" "short" "int" "float" "double" "long" | |
34e49164 | 118 | "void" |
7f004419 | 119 | "signed" "unsigned" |
34e49164 C |
120 | )) |
121 | ||
122 | (defconst cocci-iso-keywords-list | |
7f004419 | 123 | '("Expression" "Statement" "Type" |
34e49164 C |
124 | "Declaration" "TopLevel" "ArgExpression" |
125 | )) | |
126 | ||
127 | ||
128 | ||
129 | (defconst c-preprocessor-directives-list | |
130 | '("define" "undef" | |
131 | "if" "ifdef" "elif" "else" "endif" "ifndef" | |
132 | "include" | |
7f004419 C |
133 | "error" "pragma" |
134 | "file" "line" | |
34e49164 C |
135 | )) |
136 | ||
7f004419 | 137 | (setq cocci-font-lock-keywords |
34e49164 C |
138 | `( |
139 | ||
140 | ; blink possible errors, when - or + is not in first column | |
141 | ("^[ \t]+[-+]" . 'cocci-problem-face) | |
142 | ||
143 | ; modifiers | |
144 | ("^\\??\\+.*" . 'cocci-plus-face) | |
145 | ("^\\??-.*" . 'cocci-minus-face) | |
146 | ||
147 | ("^\\*.*" . 'cocci-match-face) | |
148 | ;("^\\??\\+.*?//" . 'cocci-plus-face) | |
149 | ; ! \\+ | |
150 | ||
151 | ; --- +++ | |
152 | ||
153 | ; #cpp | |
7f004419 | 154 | ("#\\(include\\) *\\(.*\\)" |
34e49164 C |
155 | (1 'font-lock-builtin-face) |
156 | (2 'font-lock-string-face) | |
157 | ) | |
158 | ||
159 | ; comments | |
160 | ("//.*" . 'font-lock-comment-face) | |
161 | ||
162 | ; strings | |
163 | ("\"[^\"]*\"" . 'font-lock-string-face) | |
164 | ||
165 | ; rule header | |
7f004419 C |
166 | ("@[ \t]*@" . 'cocci-special-face) |
167 | ; this rule may seems redundant with the following one, but | |
34e49164 | 168 | ; without it, @@ int x; @@ would color the int x with rulename-face. |
7f004419 | 169 | ; by using this rule, we color the @@ and so prevent the |
34e49164 C |
170 | ; next rule to be applied (cf font-lock semantic when have not the |
171 | ; OVERRIDE flag). | |
172 | ||
7f004419 | 173 | ("\\(@\\)\\(.*\\)\\(@\\)" |
34e49164 C |
174 | (1 'cocci-special-face) |
175 | (2 'cocci-rulename-face) | |
176 | (3 'cocci-special-face) | |
177 | ) | |
178 | ||
179 | ("@.*\\b\\(extends\\|\\(depends[ \t]*on\\)\\)\\b.*@" | |
180 | (1 'cocci-special-face t)) | |
181 | ||
182 | ;old: does not work, not easy to handle the rule1, rule2, rule3 list. | |
183 | ; ("@[ \t]*\\(\\(\\w+\\)[ \t,]*\\)*[ \t]*@" | |
7f004419 C |
184 | ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]*\\(@\\)" |
185 | ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]+\\(extends\\)[ \t]+\\(\\w+\\)[ \t]*\\(@\\)" | |
186 | ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]+\\(depends\\)[ \t]+\\(on\\)[ \t]+\\(\\(\\w+\\)[ ,\t]*\\)+\\(@\\)" | |
34e49164 C |
187 | |
188 | ||
189 | ; inherited variable, fontifying rulename | |
190 | (,(concat "^" | |
191 | "\\b\\(" (regexp-opt cocci-declaration-keywords-list) "\\)\\b" | |
192 | ".*?\\(\\w+\\)\\.") | |
193 | (2 'cocci-rulename-face)) | |
194 | ||
7f004419 | 195 | ;rule1.T *a; |
34e49164 C |
196 | ("^\\(\\w+\\)\\." |
197 | (1 'cocci-rulename-face)) | |
34e49164 C |
198 | |
199 | ; just for pad, metavariables in maj | |
200 | ("\\b[A-Z][0-9]?\\b" . font-lock-variable-name-face) | |
201 | ||
202 | ; todo: do also for other variable, do as in font-lock.el | |
203 | ; with font-lock-match-c-style-declaration-item-and-skip-to-next | |
204 | ||
205 | ; special cocci operators | |
206 | ("\\.\\.\\." . 'font-lock-keyword-face) | |
207 | ("^[()|]" . 'font-lock-keyword-face) | |
208 | ||
209 | ; escaped version of cocci operators | |
210 | ("\\\\[()|]" . 'font-lock-keyword-face) | |
211 | ||
212 | ("\\bwhen[ \t]+!=" . 'font-lock-keyword-face) | |
213 | ("\\bWHEN[ \t]+!=" . 'font-lock-keyword-face) | |
214 | ("\\bwhen[ \t]+=" . 'font-lock-keyword-face) | |
215 | ("\\bWHEN[ \t]+=" . 'font-lock-keyword-face) | |
7f004419 | 216 | |
34e49164 C |
217 | ; used in iso files |
218 | ("<=>" . 'font-lock-keyword-face) | |
219 | ("=>" . 'font-lock-keyword-face) | |
220 | ||
7f004419 | 221 | (,(concat "\\b\\(" (regexp-opt cocci-iso-keywords-list) "\\)\\b") . |
34e49164 C |
222 | 'cocci-special-face) |
223 | ||
224 | ("\\<[0-9]+\\>" . 'cocci-number-face) | |
225 | ||
7f004419 | 226 | (,(join-sep "\\|" |
34e49164 C |
227 | (list "(" ")" ";" "," "{" "}" "\\[" "\\]")) . 'cocci-punctuation-face) |
228 | ; . -> * + etc | |
229 | ||
230 | ; c keywords | |
7f004419 | 231 | (,(concat "\\b\\(" (regexp-opt cocci-c-keywords-list) "\\)\\b") . |
34e49164 C |
232 | 'font-lock-keyword-face) |
233 | ||
234 | ; cocci declaration keywords | |
7f004419 | 235 | (,(concat "\\b\\(" (regexp-opt cocci-declaration-keywords-list) "\\)\\b") . |
34e49164 C |
236 | 'font-lock-type-face) |
237 | ||
238 | ; cpp directives | |
239 | (,(concat "^#[ \t]*\\(" (regexp-opt c-preprocessor-directives-list) | |
240 | "\\)\\>[ \t!]*\\(\\sw+\\)?") | |
241 | (1 'font-lock-builtin-face)) | |
242 | ||
243 | )) | |
244 | ; "Expressions to highlight in cocci-mode.") | |
245 | ||
246 | ||
34e49164 C |
247 | ;; define a mode-specific abbrev table for those who use such things |
248 | (defvar cocci-mode-abbrev-table nil | |
249 | "Abbrev table used while in cocci mode.") | |
250 | (define-abbrev-table 'cocci-mode-abbrev-table nil) | |
251 | ||
252 | ||
253 | (defvar cocci-mode-map nil | |
254 | "Keymap used in `cocci-mode'.") | |
255 | (unless cocci-mode-map | |
256 | (setq cocci-mode-map (make-sparse-keymap)) | |
257 | (define-key cocci-mode-map [(meta control *)] 'switch-between-cocci-c) | |
258 | (define-key cocci-mode-map "%" 'cocci-replace-modifiers) | |
7f004419 | 259 | |
34e49164 C |
260 | ;(define-key cocci-mode-map "\C-c" 'compile) |
261 | ) | |
262 | ||
263 | ||
7f004419 | 264 | (defvar cocci-mode-syntax-table nil |
34e49164 C |
265 | "Syntax table used while in cocci mode.") |
266 | (unless cocci-mode-syntax-table | |
267 | (setq cocci-mode-syntax-table (make-syntax-table)) | |
268 | ||
269 | ; _ is part of a word. | |
7f004419 | 270 | (modify-syntax-entry ?\_ "w" cocci-mode-syntax-table) |
34e49164 C |
271 | |
272 | ; change mode for ", bad interaction with font-lock | |
7f004419 | 273 | (modify-syntax-entry ?\" "w" cocci-mode-syntax-table) |
34e49164 C |
274 | ) |
275 | ||
276 | ||
277 | ;;; Code | |
278 | ||
7f004419 | 279 | ;; helper functions for the cocci programmer |
34e49164 C |
280 | |
281 | (defun cocci-replace-modifiers (beg end str) | |
282 | "TODO" | |
283 | (interactive | |
7f004419 | 284 | (let ((str (read-string "New modifier string (+, -, space): " |
34e49164 C |
285 | nil 'my-history))) |
286 | (list (region-beginning) (region-end) str))) | |
287 | ||
288 | ;(interactive "rsNew modifier string (+, -, space): ") | |
289 | (replace-regexp "^[-+]?" str nil beg end) | |
290 | ) | |
291 | ||
292 | ;Used internally while developping coccinelle. | |
293 | ;Allow to switch between the corresponding SP and C file. | |
294 | ;todo: handle the _verxxx naming convention. | |
295 | (defun switch-between-cocci-c () | |
296 | (interactive) | |
297 | (let ((target | |
7f004419 | 298 | (cond ((string-match ".c$" (buffer-name)) |
34e49164 | 299 | (replace-match ".cocci" t t (buffer-name))) |
7f004419 | 300 | ((string-match ".cocci$" (buffer-name)) |
34e49164 C |
301 | (replace-match ".c" t t (buffer-name))) |
302 | (t | |
303 | "none")))) | |
304 | (if (get-buffer target) | |
305 | (switch-to-buffer target) | |
7f004419 | 306 | (find-file |
34e49164 C |
307 | (read-file-name "file: " nil nil t target))))) |
308 | ||
309 | (eval-after-load "cc-mode" | |
310 | '(progn | |
311 | (define-key c-mode-map [(meta control *)] 'switch-between-cocci-c)) | |
312 | ) | |
313 | ||
314 | ||
315 | ||
34e49164 C |
316 | (defvar cocci-mode-hook nil |
317 | "Hook called by `cocci-mode'") | |
318 | ||
319 | ;;;###autoload | |
320 | (defun cocci-mode () | |
321 | "Major mode for editing cocci code. | |
322 | Special commands: \\{cocci-mode-map} | |
323 | Turning on cocci-mode runs the hook `cocci-mode-hook'." | |
324 | (interactive) | |
325 | (kill-all-local-variables) | |
326 | (make-local-variable 'font-lock-defaults) | |
327 | (make-local-variable 'comment-start) | |
328 | (make-local-variable 'comment-end) | |
329 | (make-local-variable 'compile-command) | |
330 | ||
331 | (use-local-map cocci-mode-map) | |
332 | (set-syntax-table cocci-mode-syntax-table) | |
333 | (setq mode-name "cocci" | |
334 | major-mode 'cocci-mode | |
335 | local-abbrev-table cocci-mode-abbrev-table | |
336 | font-lock-defaults '(cocci-font-lock-keywords) | |
337 | comment-start "//" | |
338 | comment-end "" | |
339 | ) | |
340 | (easy-menu-add cocci-menu) | |
341 | ||
342 | (run-hooks 'cocci-mode-hook) | |
343 | ) | |
344 | ||
345 | ||
7f004419 | 346 | ;; Menu |
34e49164 C |
347 | |
348 | (easy-menu-define cocci-menu cocci-mode-map "Cocci menu" | |
349 | '("Cocci" | |
350 | ["Switch to corresponding C file" switch-between-cocci-c t] | |
351 | ["Replace modifiers" cocci-replace-modifiers t] | |
352 | )) | |
353 | ||
354 | ||
355 | ||
356 | ; put cursor before a parse error coccinelle message and it will | |
357 | ; open the corresponding file and go to corresponding line. | |
358 | (fset 'cocci-goto-next-error | |
359 | [?\C-s ?F ?i ?l ?e right right ?\C- ?\C-s ?" left ?\M-w ?\C-x ?\C-f S-insert return ?\C-\M-l C-right right C-S-right C-insert ?\C-\M-l ?\M-g S-insert return]) | |
360 | ;" | |
361 | ||
362 | ;; Provide | |
363 | (provide 'cocci-mode) | |
364 | ||
365 | ;;; cocci.el ends here |