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