;;; cocci.el --- a major mode for editing semantic patches ;; Copyright (C) 2006-2007 Yoann Padioleau ;; Please imagine a long and boring gnu-style copyright notice ;; appearing just here. ;; Emacs Lisp Archive Entry ;; Author: Padioleau Yoann , ;; Version: 0.2 ;; Keywords: coccinelle patch refactoring program transformation ;; URL: http://coccinelle.lip6.fr/ ;;; Usage ;; Copy this file in your ~/.emacs.d directory ;; ;; Add the following lines to your ~/.emacs or equivalent: ;; (load "~/.emacs.d/cocci.el") ;; (setq auto-mode-alist ;; (cons '("\\.cocci$" . cocci-mode) auto-mode-alist)) ;; (autoload 'cocci-mode "cocci" ;; "Major mode for editing cocci code." t) ;; ;; You can also use cocci-mode to edit the files containing the ;; isomorphisms with: ;; (setq auto-mode-alist ;; (cons '("\\.iso$" . cocci-mode) auto-mode-alist)) ;; ;;; History ;; 2009-11-05 Nico: Cleanups, Change shortcut % to C-M-% (% is used in Python rule) ;; Some cleanups done by Rene Rydhof Hansen ;;; Utilities (defun join-sep (sep xs) (mapconcat 'identity xs sep)) ;;; Variables (defvar cocci-menu) ;; new (color) faces (defface cocci-number-face '((((background light)) (:foreground "black")) (((background dark)) (:foreground "yellow3"))) "Used for Cocci numbers") (defface cocci-punctuation-face '((((background light)) (:foreground "black")) (((background dark)) (:foreground "cyan"))) "Used for punctuation") (defface cocci-problem-face '((((background light)) (:background "deep pink")) (((background dark)) (:background "deep pink"))) "Highlighting potential problems") (defface cocci-special-face '((((background light)) (:foreground "blue")) (((background dark)) (:foreground "red"))) "") (defface cocci-rulename-face '((((background light)) (:foreground "DarkSlateGray")) (((background dark)) (:foreground "DarkSlateGray4"))) "Highlighting the rule names") (defface cocci-minus-face '((((background light)) (:foreground "red")) (((background dark)) (:foreground "SeaGreen3"))) "Highlighting lines to be removed") (defface cocci-plus-face '((((background light)) (:foreground "dark green")) (((background dark)) (:foreground "salmon"))) "Highlighting lines to be added") (defface cocci-match-face '((((background light)) (:foreground "violet red")) (((background dark)) (:foreground "purple"))) "Highlighting lines to be matched (sgrep)") ;; can look in lexer_cocci.mll for new identifiers (defconst cocci-c-keywords-list '("if" "else" "while" "do" "for" "return" "sizeof" "struct" "union" "static" "extern" "const" "volatile" "break" "continue" "switch" "case" )) (defconst cocci-declaration-keywords-list '("identifier" "type" "parameter" "constant" "expression" "statement" "function" "local" "list" "fresh" "position" "idexpression" "context" "typedef" "declarer" "iterator" "pure" ;"error" "words" "char" "short" "int" "float" "double" "long" "void" "signed" "unsigned" )) (defconst cocci-iso-keywords-list '("Expression" "Statement" "Type" "Declaration" "TopLevel" "ArgExpression" )) (defconst c-preprocessor-directives-list '("define" "undef" "if" "ifdef" "elif" "else" "endif" "ifndef" "include" "error" "pragma" "file" "line" )) (setq cocci-font-lock-keywords `( ; blink possible errors, when - or + is not in first column ("^[ \t]+[-+]" . 'cocci-problem-face) ; modifiers ("^\\??\\+.*" . 'cocci-plus-face) ("^\\??-.*" . 'cocci-minus-face) ("^\\*.*" . 'cocci-match-face) ;("^\\??\\+.*?//" . 'cocci-plus-face) ; ! \\+ ; --- +++ ; #cpp ("#\\(include\\) *\\(.*\\)" (1 'font-lock-builtin-face) (2 'font-lock-string-face) ) ; comments ("//.*" . 'font-lock-comment-face) ; strings ("\"[^\"]*\"" . 'font-lock-string-face) ; rule header ("@[ \t]*@" . 'cocci-special-face) ; this rule may seems redundant with the following one, but ; without it, @@ int x; @@ would color the int x with rulename-face. ; by using this rule, we color the @@ and so prevent the ; next rule to be applied (cf font-lock semantic when have not the ; OVERRIDE flag). ("\\(@\\)\\(.*\\)\\(@\\)" (1 'cocci-special-face) (2 'cocci-rulename-face) (3 'cocci-special-face) ) ("@.*\\b\\(extends\\|\\(depends[ \t]*on\\)\\)\\b.*@" (1 'cocci-special-face t)) ;old: does not work, not easy to handle the rule1, rule2, rule3 list. ; ("@[ \t]*\\(\\(\\w+\\)[ \t,]*\\)*[ \t]*@" ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]*\\(@\\)" ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]+\\(extends\\)[ \t]+\\(\\w+\\)[ \t]*\\(@\\)" ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]+\\(depends\\)[ \t]+\\(on\\)[ \t]+\\(\\(\\w+\\)[ ,\t]*\\)+\\(@\\)" ; inherited variable, fontifying rulename (,(concat "^" "\\b\\(" (regexp-opt cocci-declaration-keywords-list) "\\)\\b" ".*?\\(\\w+\\)\\.") (2 'cocci-rulename-face)) ;rule1.T *a; ("^\\(\\w+\\)\\." (1 'cocci-rulename-face)) ; just for pad, metavariables in maj ("\\b[A-Z][0-9]?\\b" . font-lock-variable-name-face) ; todo: do also for other variable, do as in font-lock.el ; with font-lock-match-c-style-declaration-item-and-skip-to-next ; special cocci operators ("\\.\\.\\." . 'font-lock-keyword-face) ("^[()|]" . 'font-lock-keyword-face) ; escaped version of cocci operators ("\\\\[()|]" . 'font-lock-keyword-face) ("\\bwhen[ \t]+!=" . 'font-lock-keyword-face) ("\\bWHEN[ \t]+!=" . 'font-lock-keyword-face) ("\\bwhen[ \t]+=" . 'font-lock-keyword-face) ("\\bWHEN[ \t]+=" . 'font-lock-keyword-face) ; used in iso files ("<=>" . 'font-lock-keyword-face) ("=>" . 'font-lock-keyword-face) (,(concat "\\b\\(" (regexp-opt cocci-iso-keywords-list) "\\)\\b") . 'cocci-special-face) ("\\<[0-9]+\\>" . 'cocci-number-face) (,(join-sep "\\|" (list "(" ")" ";" "," "{" "}" "\\[" "\\]")) . 'cocci-punctuation-face) ; . -> * + etc ; c keywords (,(concat "\\b\\(" (regexp-opt cocci-c-keywords-list) "\\)\\b") . 'font-lock-keyword-face) ; cocci declaration keywords (,(concat "\\b\\(" (regexp-opt cocci-declaration-keywords-list) "\\)\\b") . 'font-lock-type-face) ; cpp directives (,(concat "^#[ \t]*\\(" (regexp-opt c-preprocessor-directives-list) "\\)\\>[ \t!]*\\(\\sw+\\)?") (1 'font-lock-builtin-face)) )) ; "Expressions to highlight in cocci-mode.") ;; define a mode-specific abbrev table for those who use such things (defvar cocci-mode-abbrev-table nil "Abbrev table used while in cocci mode.") (define-abbrev-table 'cocci-mode-abbrev-table nil) (defvar cocci-mode-map nil "Keymap used in `cocci-mode'.") (unless cocci-mode-map (setq cocci-mode-map (make-sparse-keymap)) (define-key cocci-mode-map [(meta control *)] 'switch-between-cocci-c) (define-key cocci-mode-map "%" 'cocci-replace-modifiers) ;(define-key cocci-mode-map "\C-c" 'compile) ) (defvar cocci-mode-syntax-table nil "Syntax table used while in cocci mode.") (unless cocci-mode-syntax-table (setq cocci-mode-syntax-table (make-syntax-table)) ; _ is part of a word. (modify-syntax-entry ?\_ "w" cocci-mode-syntax-table) ; change mode for ", bad interaction with font-lock (modify-syntax-entry ?\" "w" cocci-mode-syntax-table) ) ;;; Code ;; helper functions for the cocci programmer (defun cocci-replace-modifiers (beg end str) "TODO" (interactive (let ((str (read-string "New modifier string (+, -, space): " nil 'my-history))) (list (region-beginning) (region-end) str))) ;(interactive "rsNew modifier string (+, -, space): ") (replace-regexp "^[-+]?" str nil beg end) ) ;Used internally while developping coccinelle. ;Allow to switch between the corresponding SP and C file. ;todo: handle the _verxxx naming convention. (defun switch-between-cocci-c () (interactive) (let ((target (cond ((string-match ".c$" (buffer-name)) (replace-match ".cocci" t t (buffer-name))) ((string-match ".cocci$" (buffer-name)) (replace-match ".c" t t (buffer-name))) (t "none")))) (if (get-buffer target) (switch-to-buffer target) (find-file (read-file-name "file: " nil nil t target))))) (eval-after-load "cc-mode" '(progn (define-key c-mode-map [(meta control *)] 'switch-between-cocci-c)) ) (defvar cocci-mode-hook nil "Hook called by `cocci-mode'") ;;;###autoload (defun cocci-mode () "Major mode for editing cocci code. Special commands: \\{cocci-mode-map} Turning on cocci-mode runs the hook `cocci-mode-hook'." (interactive) (kill-all-local-variables) (make-local-variable 'font-lock-defaults) (make-local-variable 'comment-start) (make-local-variable 'comment-end) (make-local-variable 'compile-command) (use-local-map cocci-mode-map) (set-syntax-table cocci-mode-syntax-table) (setq mode-name "cocci" major-mode 'cocci-mode local-abbrev-table cocci-mode-abbrev-table font-lock-defaults '(cocci-font-lock-keywords) comment-start "//" comment-end "" ) (easy-menu-add cocci-menu) (run-hooks 'cocci-mode-hook) ) ;; Menu (easy-menu-define cocci-menu cocci-mode-map "Cocci menu" '("Cocci" ["Switch to corresponding C file" switch-between-cocci-c t] ["Replace modifiers" cocci-replace-modifiers t] )) ; put cursor before a parse error coccinelle message and it will ; open the corresponding file and go to corresponding line. (fset 'cocci-goto-next-error [?\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]) ;" ;; Provide (provide 'cocci-mode) ;;; cocci.el ends here