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