diff --git a/config.el b/config.el index fea7616..e5a79a2 100644 --- a/config.el +++ b/config.el @@ -353,6 +353,11 @@ (use-package! duplicate-thing :bind (("M-C" . duplicate-thing))) +;; P4 programming mode. +(use-package! p4_16-mode + :mode (("\\.p4\\'" . p4_16-mode) + ("\\.p4i\\'" . p4_16-mode))) + ;; Navigate betweeon occurences of the same symbol. (use-package! symbol-overlay :bind (("M-RET" . symbol-overlay-put) diff --git a/packages.el b/packages.el index ff70443..34467aa 100644 --- a/packages.el +++ b/packages.el @@ -10,11 +10,14 @@ ;;(package! some-package) (package! deadgrep) (package! duplicate-thing) +(package! p4_16 + :recipe (:local-repo "repos/p4_16-mode")) (package! symbol-overlay) (package! treemacs-icons-dired) (package! whole-line-or-region) (package! x-lib :recipe (:local-repo "repos/x-lib")) +(package! xcscope) ;; required for p4_16-mode ;; To install a package directly from a remote git repo, you must specify a ;; `:recipe'. You'll find documentation on what `:recipe' accepts here: diff --git a/repos/p4_16-mode/p4_16-mode.el b/repos/p4_16-mode/p4_16-mode.el new file mode 100644 index 0000000..ba65e5e --- /dev/null +++ b/repos/p4_16-mode/p4_16-mode.el @@ -0,0 +1,234 @@ +;;; p4_16-mode.el --- Support for the P4_16 programming language + +;; Copyright (C) 2016- Barefoot Networks +;; Author: Vladimir Gurevich +;; Maintainer: Vladimir Gurevich +;; Created: 15 April 2017 +;; Version: 0.2 +;; Keywords: languages p4_16 +;; Homepage: http://p4.org + +;; This file is not part of GNU Emacs. + +;; This file is free software… + +;; This mode has preliminary support for P4_16. It covers the core language, +;; but it is not clear yet, how we can highlight the indentifiers, defined +;; for a particular architecture. Core library definitions are included + +;; Placeholder for user customization code +(defvar p4_16-mode-hook nil) + +(defun p4_16-electric-brace (arg) + "Insert a brace." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (save-excursion + (move-beginning-of-line nil) + (indent-for-tab-command))) + +;; Define the keymap (for now it is pretty much default) +(defvar p4_16-mode-map + (let ((map (make-keymap))) + (define-key map "\C-j" 'newline-and-indent) + (define-key map "{" 'p4_16-electric-brace) + (define-key map "}" 'p4_16-electric-brace) + (define-key map "\C-c\C-c" 'comment-region) + map) + "Keymap for P4_16 major mode") + +;; Syntactic HighLighting + +;; Main keywors (declarations and operators) +(setq p4_16-keywords + '("action" "apply" + "control" + "default" + "else" "enum" "extern" "exit" + "header" "header_union" + "if" + "match_kind" + "package" "parser" + "return" + "select" "state" "struct" "switch" + "table" "transition" "tuple" "typedef" "type" + "verify" + )) + +(setq p4_16-annotations + '("@name" "@metadata" "@alias" + )) + +(setq p4_16-attributes + '("const" "in" "inout" "out" + ;; Tables + "key" "actions" "default_action" "entries" "implementation" + "counters" "meters" + )) + +(setq p4_16-variables + '("packet_in" "packet_out" + )) + +(setq p4_16-operations + '("&&&" ".." "++" "?" ":")) + +(setq p4_16-constants + '( + ;;; Don't care + "_" + ;;; bool + "false" "true" + ;;; error + "NoError" "PacketTooShort" "NoMatch" "StackOutOfBounds" + "OverwritingHeader" "HeaderTooShort" "ParserTiimeout" + ;;; match_kind + "exact" "ternary" "lpm" "range" + ;;; We can add constants for supported architectures here + )) + +(setq p4_16-types + '("bit" "bool" "int" "varbit" "void" "error" + )) + +(setq p4_16-primitives + '( + ;;; Header methods + "isValid" "setValid" "setInvalid" + ;;; Table Methods + "hit" "action_run" + ;;; packet_in methods + "extract" "lookahead" "advance" "length" + ;;; packet_out methods + "emit" + ;;; Known parser states + "accept" "reject" + ;;; misc + "NoAction" + )) + +(setq p4_16-cpp + '("#include" + "#define" "#undef" + "#if" "#ifdef" "#ifndef" + "#elif" "#else" + "#endif" + "defined" + "#line" "#file")) + +(setq p4_16-cppwarn + '("#error" "#warning")) + +;; Optimize the strings +(setq p4_16-keywords-regexp (regexp-opt p4_16-keywords 'words)) +(setq p4_16-annotations-regexp (regexp-opt p4_16-annotations 1)) +(setq p4_16-attributes-regexp (regexp-opt p4_16-attributes 'words)) +(setq p4_16-variables-regexp (regexp-opt p4_16-variables 'words)) +(setq p4_16-operations-regexp (regexp-opt p4_16-operations 'words)) +(setq p4_16-constants-regexp (regexp-opt p4_16-constants 'words)) +(setq p4_16-types-regexp (regexp-opt p4_16-types 'words)) +(setq p4_16-primitives-regexp (regexp-opt p4_16-primitives 'words)) +(setq p4_16-cpp-regexp (regexp-opt p4_16-cpp 1)) +(setq p4_16-cppwarn-regexp (regexp-opt p4_16-cppwarn 1)) + + +;; create the list for font-lock. +;; each category of keyword is given a particular face +(defconst p4_16-font-lock-keywords + (list + (cons p4_16-cpp-regexp font-lock-preprocessor-face) + (cons p4_16-cppwarn-regexp font-lock-warning-face) + (cons p4_16-types-regexp font-lock-type-face) + (cons p4_16-constants-regexp font-lock-constant-face) + (cons p4_16-attributes-regexp font-lock-builtin-face) + (cons p4_16-variables-regexp font-lock-variable-name-face) + ;;; This is a special case to distinguish the method from the keyword + (cons "\\.apply" font-lock-function-name-face) + (cons p4_16-primitives-regexp font-lock-function-name-face) + (cons p4_16-operations-regexp font-lock-builtin-face) + (cons p4_16-keywords-regexp font-lock-keyword-face) + (cons p4_16-annotations-regexp font-lock-keyword-face) + (cons "\\(\\w*_t +\\)" font-lock-type-face) + (cons "[^A-Z_][A-Z] " font-lock-type-face) ;; Total hack for templates + (cons "<[A-Z, ]*>" font-lock-type-face) + (cons "\\(<[^>]+>\\)" font-lock-string-face) + (cons "\\([^_A-Za-z]\\([0-9]+w\\)?0x[0-9A-Fa-f]+\\)" font-lock-constant-face) + (cons "\\([^_A-Za-z]\\([0-9]+w\\)?0b[01]+\\)" font-lock-constant-face) + (cons "\\([^_A-Za-z][+-]?\\([0-9]+w\\)?[0-9]+\\)" font-lock-constant-face) + ;;(cons "\\(\\w*\\)" font-lock-variable-name-face) + ) + "Default Highlighting Expressions for P4_16") + +(defvar p4_16-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?_ "w" st) + (modify-syntax-entry ?/ ". 124b" st) + (modify-syntax-entry ?* ". 23" st) + (modify-syntax-entry ?\n "> b" st) + st) + "Syntax table for p4_16-mode") + +;;; Indentation +(defvar p4_16-indent-offset 4 + "Indentation offset for `p4_16-mode'.") + +(defun p4_16-indent-line () + "Indent current line for any balanced-paren-mode'." + (interactive) + (let ((indent-col 0) + (indentation-increasers "[{(]") + (indentation-decreasers "[})]") + ) + (save-excursion + (beginning-of-line) + (condition-case nil + (while t + (backward-up-list 1) + (when (looking-at indentation-increasers) + (setq indent-col (+ indent-col p4_16-indent-offset)))) + (error nil))) + (save-excursion + (back-to-indentation) + (when (and (looking-at indentation-decreasers) + (>= indent-col p4_16-indent-offset)) + (setq indent-col (- indent-col p4_16-indent-offset)))) + (indent-line-to indent-col))) + +;;; Imenu support +(require 'imenu) +(setq p4_16-imenu-generic-expression + '( + ("Controls" "^ *control +\\([A-Za-z0-9_]*\\)" 1) + ("Externs" "^ *extern +\\([A-Za-z0-9_]*\\) *\\([A-Za-z0-9_]*\\)" 2) + ("Tables" "^ *table +\\([A-Za-z0-9_]*\\)" 1) + ("Actions" "^ *action +\\([A-Za-z0-9_]*\\)" 1) + ("Parsers" "^ *parser +\\([A-Za-z0-9_]*\\)" 1) + ("Parser States" "^ *state +\\([A-Za-z0-9_]*\\)" 1) + ("Headers" "^ *header +\\([A-Za-z0-9_]*\\)" 1) + ("Header Unions" "^ *header_union +\\([A-Za-z0-9_]*\\)" 1) + ("Structs" "^ *struct +\\([A-Za-z0-9_]*\\)" 1) + )) + +;;; Cscope Support +(require 'xcscope) + +;; Put everything together +(define-derived-mode p4_16-mode prog-mode "P4_16" + "Major mode for editing P4_16 programs" + :syntax-table p4_16-mode-syntax-table + (use-local-map p4_16-mode-map) + (set (make-local-variable 'font-lock-defaults) '(p4_16-font-lock-keywords)) + (set (make-local-variable 'indent-line-function) 'p4_16-indent-line) + (setq imenu-generic-expression p4_16-imenu-generic-expression) + ;; Setting this to nil causes indentation to use only space + ;; characters, never tabs. + (setq indent-tabs-mode nil) + (setq comment-start "// ") + (setq comment-end "") + (imenu-add-to-menubar "P4_16") + (cscope-minor-mode) + (run-hooks 'p4_16-mode-hook) + ) + +;; The most important line +(provide 'p4_16-mode)