dotfiles

my shiny new dotfiles
git clone git://git.jakekoroman.com/dotfiles
Log | Files | Refs | README

odin-mode.el (9282B)


      1 ;;; odin-mode.el --- A minor mode for odin
      2 
      3 ;; Author: Ethan Morgan
      4 ;; Keywords: odin, language, languages, mode
      5 ;; Package-Requires: ((emacs "24.1"))
      6 ;; Homepage: https://github.com/glassofethanol/odin-mode
      7 
      8 ;; This file is NOT part of GNU Emacs.
      9 
     10 ;;; Code:
     11 
     12 (require 'cl-lib)
     13 (require 'rx)
     14 (require 'js)
     15 
     16 (defgroup odin nil
     17   "Odin mode"
     18   :group 'languages)
     19 
     20 ;; `compilation-mode' configuration
     21 
     22 (eval-after-load 'compile
     23  '(add-to-list 'compilation-error-regexp-alist '("^\\(.*?\\)(\\([0-9]+\\):\\([0-9]+\\).*" 1 2 3)))
     24 
     25 (defconst odin-mode-syntax-table
     26   (let ((table (make-syntax-table)))
     27     (modify-syntax-entry ?\" "\"" table)
     28     (modify-syntax-entry ?\\ "\\" table)
     29 
     30     ;; additional symbols
     31     (modify-syntax-entry ?' "\"" table)
     32     (modify-syntax-entry ?` "\"" table)
     33     (modify-syntax-entry ?: "." table)
     34     (modify-syntax-entry ?+ "." table)
     35     (modify-syntax-entry ?- "." table)
     36     (modify-syntax-entry ?% "." table)
     37     (modify-syntax-entry ?& "." table)
     38     (modify-syntax-entry ?| "." table)
     39     (modify-syntax-entry ?^ "." table)
     40     (modify-syntax-entry ?! "." table)
     41     (modify-syntax-entry ?$ "." table)
     42     (modify-syntax-entry ?= "." table)
     43     (modify-syntax-entry ?< "." table)
     44     (modify-syntax-entry ?> "." table)
     45     (modify-syntax-entry ?? "." table)
     46 
     47     ;; Need this for #directive regexes to work correctly
     48     (modify-syntax-entry ?#   "_" table)
     49 
     50     ;; Modify some syntax entries to allow nested block comments
     51     (modify-syntax-entry ?/ ". 124b" table)
     52     (modify-syntax-entry ?* ". 23n" table)
     53     (modify-syntax-entry ?\n "> b" table)
     54     (modify-syntax-entry ?\^m "> b" table)
     55 
     56     table))
     57 
     58 (defconst odin-builtins
     59   '("len" "cap"
     60     "typeid_of" "type_info_of"
     61     "swizzle" "complex" "real" "imag" "quaternion" "conj"
     62     "jmag" "kmag"
     63     "min" "max" "abs" "clamp"
     64     "expand_to_tuple"
     65 
     66     "init_global_temporary_allocator"
     67     "copy" "pop" "unordered_remove" "ordered_remove" "clear" "reserve"
     68     "resize" "new" "new_clone" "free" "free_all" "delete" "make"
     69     "clear_map" "reserve_map" "delete_key" "append_elem" "append_elems"
     70     "append" "append_string" "clear_dynamic_array" "reserve_dynamic_array"
     71     "resize_dynamic_array" "incl_elem" "incl_elems" "incl_bit_set"
     72     "excl_elem" "excl_elems" "excl_bit_set" "incl" "excl" "card"
     73     "assert" "panic" "unimplemented" "unreachable"))
     74 
     75 (defconst odin-keywords
     76   '("import" "foreign" "package"
     77     "where" "when" "if" "else" "for" "switch" "in" "notin" "do" "case"
     78     "break" "continue" "fallthrough" "defer" "return" "proc"
     79     "struct" "union" "enum" "bit_field" "bit_set" "map" "dynamic"
     80     "auto_cast" "cast" "transmute" "distinct" "opaque"
     81     "using" "inline" "no_inline"
     82     "size_of" "align_of" "offset_of" "type_of"
     83 
     84     "context"
     85     ;; "_"
     86 
     87     ;; Reserved
     88     "macro" "const"))
     89 
     90 (defconst odin-constants
     91   '("nil" "true" "false"
     92     "ODIN_OS" "ODIN_ARCH" "ODIN_ENDIAN" "ODIN_VENDOR"
     93     "ODIN_VERSION" "ODIN_ROOT" "ODIN_DEBUG"))
     94 
     95 (defconst odin-typenames
     96   '("bool" "b8" "b16" "b32" "b64"
     97 
     98     "int"  "i8" "i16" "i32" "i64"
     99     "i16le" "i32le" "i64le"
    100     "i16be" "i32be" "i64be"
    101     "i128" "u128"
    102     "i128le" "u128le"
    103     "i128be" "u128be"
    104 
    105     "uint" "u8" "u16" "u32" "u64"
    106     "u16le" "u32le" "u64le"
    107     "u16be" "u32be" "u64be"
    108 
    109     "f32" "f64"
    110     "complex64" "complex128"
    111 
    112     "quaternion128" "quaternion256"
    113 
    114     "rune"
    115     "string" "cstring"
    116 
    117     "uintptr" "rawptr"
    118     "typeid" "any"
    119     "byte"))
    120 
    121 (defconst odin-attributes
    122   '("builtin"
    123     "export"
    124     "static"
    125     "deferred_in" "deferred_none" "deferred_out"
    126     "require_results"
    127     "default_calling_convention" "link_name" "link_prefix"
    128     "deprecated" "private" "thread_local"))
    129 
    130 
    131 (defconst odin-proc-directives
    132   '("#force_inline"
    133     "#force_no_inline"
    134     "#type")
    135   "Directives that can appear before a proc declaration")
    136 
    137 (defconst odin-directives
    138   (append '("#align" "#packed"
    139             "#any_int"
    140             "#raw_union"
    141             "#no_nil"
    142             "#complete"
    143             "#no_alias"
    144             "#c_vararg"
    145             "#assert"
    146             "#file" "#line" "#location" "#procedure" "#caller_location"
    147             "#load"
    148             "#defined"
    149             "#bounds_check" "#no_bounds_check"
    150             "#partial") odin-proc-directives))
    151 
    152 (defun odin-wrap-word-rx (s)
    153   (concat "\\<" s "\\>"))
    154 
    155 (defun odin-wrap-keyword-rx (s)
    156   (concat "\\(?:\\S.\\_<\\|\\`\\)" s "\\_>"))
    157 
    158 (defun odin-wrap-directive-rx (s)
    159   (concat "\\_<" s "\\>"))
    160 
    161 (defun odin-wrap-attribute-rx (s)
    162   (concat "[[:space:]\n]*@[[:space:]\n]*(?[[:space:]\n]*" s "\\>"))
    163 
    164 (defun odin-keywords-rx (keywords)
    165   "build keyword regexp"
    166   (odin-wrap-keyword-rx (regexp-opt keywords t)))
    167 
    168 (defun odin-directives-rx (directives)
    169   (odin-wrap-directive-rx (regexp-opt directives t)))
    170 
    171 (defun odin-attributes-rx (attributes)
    172   (odin-wrap-attribute-rx (regexp-opt attributes t)))
    173 
    174 (defconst odin-identifier-rx "[[:word:][:multibyte:]_]+")
    175 (defconst odin-hat-type-rx (rx (group (and "^" (1+ (any word "." "_"))))))
    176 (defconst odin-dollar-type-rx (rx (group "$" (or (1+ (any word "_")) (opt "$")))))
    177 (defconst odin-number-rx
    178   (rx (and
    179        symbol-start
    180        (or (and (+ digit) (opt (and (any "eE") (opt (any "-+")) (+ digit))))
    181            (and "0" (any "xX") (+ hex-digit)))
    182        (opt (and (any "_" "A-Z" "a-z") (* (any "_" "A-Z" "a-z" "0-9"))))
    183        symbol-end)))
    184 (defconst odin-proc-rx (concat "\\(\\_<" odin-identifier-rx "\\_>\\)\\s *::\\s *\\(" (odin-directives-rx odin-proc-directives) "\\)?\\s *\\_<proc\\_>"))
    185 
    186 (defconst odin-type-rx (concat "\\_<\\(" odin-identifier-rx "\\)\\s *::\\s *\\(?:struct\\|enum\\|union\\|distinct\\)\\s *\\_>"))
    187 
    188 
    189 (defconst odin-font-lock-defaults
    190   `(
    191     ;; Types
    192     (,odin-hat-type-rx 1 font-lock-type-face)
    193     (,odin-dollar-type-rx 1 font-lock-type-face)
    194     (,(odin-keywords-rx odin-typenames) 1 font-lock-type-face)
    195     (,odin-type-rx 1 font-lock-type-face)
    196 
    197     ;; Hash directives
    198     (,(odin-directives-rx odin-directives) 1 font-lock-preprocessor-face)
    199 
    200     ;; At directives
    201     (,(odin-attributes-rx odin-attributes) 1 font-lock-preprocessor-face)
    202 
    203     ;; Keywords
    204     (,(odin-keywords-rx odin-keywords) 1 font-lock-keyword-face)
    205 
    206     ;; single quote characters
    207     ("'\\(\\\\.\\|[^']\\)'" . font-lock-constant-face)
    208 
    209     ;; Variables
    210     (,(odin-keywords-rx odin-builtins) 1 font-lock-builtin-face)
    211 
    212     ;; Constants
    213     (,(odin-keywords-rx odin-constants) 1 font-lock-constant-face)
    214 
    215     ;; Strings
    216     ;; ("\\\".*\\\"" . font-lock-string-face)
    217 
    218     ;; Numbers
    219     (,(odin-wrap-word-rx odin-number-rx) . font-lock-constant-face)
    220 
    221     ;; Procedures
    222     (,odin-proc-rx 1 font-lock-function-name-face)
    223 
    224     ("---" . font-lock-constant-face)
    225     ("\\.\\.<" . font-lock-constant-face)
    226     ("\\.\\." . font-lock-constant-face)
    227     ))
    228 
    229 ;; add setq-local for older emacs versions
    230 (unless (fboundp 'setq-local)
    231   (defmacro setq-local (var val)
    232     `(set (make-local-variable ',var) ,val)))
    233 
    234 (defconst odin--defun-rx "\(.*\).*\{")
    235 
    236 (defmacro odin-paren-level ()
    237   `(car (syntax-ppss)))
    238 
    239 (defun odin-line-is-defun ()
    240   "return t if current line begins a procedure"
    241   (interactive)
    242   (save-excursion
    243     (beginning-of-line)
    244     (let (found)
    245       (while (and (not (eolp)) (not found))
    246         (if (looking-at odin--defun-rx)
    247             (setq found t)
    248           (forward-char 1)))
    249       found)))
    250 
    251 (defun odin-beginning-of-defun (&optional count)
    252   "Go to line on which current function starts."
    253   (interactive)
    254   (let ((orig-level (odin-paren-level)))
    255     (while (and
    256             (not (odin-line-is-defun))
    257             (not (bobp))
    258             (> orig-level 0))
    259       (setq orig-level (odin-paren-level))
    260       (while (>= (odin-paren-level) orig-level)
    261         (skip-chars-backward "^{")
    262         (backward-char))))
    263   (if (odin-line-is-defun)
    264       (beginning-of-line)))
    265 
    266 (defun odin-end-of-defun ()
    267   "Go to line on which current function ends."
    268   (interactive)
    269   (let ((orig-level (odin-paren-level)))
    270     (when (> orig-level 0)
    271       (odin-beginning-of-defun)
    272       (end-of-line)
    273       (setq orig-level (odin-paren-level))
    274       (skip-chars-forward "^}")
    275       (while (>= (odin-paren-level) orig-level)
    276         (skip-chars-forward "^}")
    277         (forward-char)))))
    278 
    279 (defalias 'odin-parent-mode
    280  (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
    281 
    282 ;;;###autoload
    283 (define-derived-mode odin-mode odin-parent-mode "Odin"
    284   :syntax-table odin-mode-syntax-table
    285   :group 'odin
    286   (setq bidi-paragraph-direction 'left-to-right)
    287   (setq-local require-final-newline mode-require-final-newline)
    288   (setq-local parse-sexp-ignore-comments t)
    289   (setq-local comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
    290   (setq-local comment-start "//")
    291   (setq-local comment-end "")
    292   (setq-local indent-line-function 'js-indent-line)
    293   (setq-local font-lock-defaults '(odin-font-lock-defaults))
    294   (setq-local beginning-of-defun-function 'odin-beginning-of-defun)
    295   (setq-local end-of-defun-function 'odin-end-of-defun)
    296   (setq-local electric-indent-chars
    297               (append "{}():;," electric-indent-chars))
    298   (setq imenu-generic-expression
    299         `(("type" ,(concat "^" odin-type-rx) 1)
    300           ("proc" ,(concat "^" odin-proc-rx) 1)))
    301 
    302   (font-lock-ensure))
    303 
    304 ;;;###autoload
    305 (add-to-list 'auto-mode-alist '("\\.odin\\'" . odin-mode))
    306 
    307 (provide 'odin-mode)
    308 
    309 
    310 ;;; odin-mode.el ends here