Add P4 mode

This commit is contained in:
Wojciech Kozlowski 2022-08-13 22:39:40 +02:00
parent b542b922a0
commit b6209ca9c4
3 changed files with 242 additions and 0 deletions

View File

@ -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)

View File

@ -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:

View File

@ -0,0 +1,234 @@
;;; p4_16-mode.el --- Support for the P4_16 programming language
;; Copyright (C) 2016- Barefoot Networks
;; Author: Vladimir Gurevich <vladimir.gurevich@barefootnetworks.com>
;; Maintainer: Vladimir Gurevich <vladimir.gurevich@barefootnetworks.com>
;; 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)