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