ztl-mode/ztl-mode.el

121 lines
3.6 KiB
EmacsLisp

;;; ztl-mode.el --- Major mode for editing Ztl code -*- lexical-binding: t; -*-
;;
;; Licensed under the GPLv3 License.
(defvar ztl-keywords
'("fn" "to" "in" "is" "as" "use" "set" "if" "else"
"for" "loop" "concurrent" "while" "do" "exits" "exit"
"return" "const" "type" "this" "panic"
"break" "mod" "not" "and" "or" "print" "let")
"Keywords in Ztl.")
(defvar ztl-types
'("byte" "str" "real" "bool" "err" "any")
"Types in Ztl.")
(defvar ztl-constants
'("true" "false" "nil")
"Constants in Ztl.")
(defvar ztl-font-lock-keywords
`(
;; Keywords
(,(regexp-opt ztl-keywords 'words) . font-lock-keyword-face)
;; Types
(,(regexp-opt ztl-types 'words) . font-lock-type-face)
;; Constants
(,(regexp-opt ztl-constants 'words) . font-lock-constant-face)
;; Structs: CamelCase identifiers
("\\b[A-Z][a-zA-Z0-9_]*\\b" . font-lock-type-face)
;; Floating point numbers
("-?[0-9]+\\.[0-9]+" . font-lock-constant-face)
;; Ints
("-?[0-9]+" . font-lock-constant-face)
;; Strings with double quotes
("\"[^\"\n]*\"" . font-lock-string-face)
;; Strings with backticks
("`[^`]*`" . font-lock-string-face)
;; Function definitions
("\\_<fn\\>\\s-+\\(\\w+\\)(" (1 font-lock-function-name-face))
;; Function calls
("\\_<\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\s-*(" (1 font-lock-function-name-face))
)
"Font lock keywords for Ztl mode.")
(defvar ztl-mode-syntax-table
(let ((st (make-syntax-table)))
;; C++-style comments
(modify-syntax-entry ?/ ". 14b" st)
;; C-style comments
(modify-syntax-entry ?* ". 23" st)
;; Strings
(modify-syntax-entry ?\" "\"" st)
(modify-syntax-entry ?` "\"" st)
st)
"Syntax table for Ztl mode.")
(defun ztl-indent-line ()
"Indent current line as Ztl code."
(interactive)
(let ((indent (calculate-ztl-indent)))
(if (null indent)
(setq indent 0))
(indent-line-to indent)))
(defun calculate-ztl-indent ()
"Calculate the proper indentation for the current line."
(save-excursion
(beginning-of-line)
(let ((pos (point-marker))
(indent 0))
(skip-chars-forward " \t")
(if (looking-at "\\s)\\|\\s(")
(setq indent 0)
(condition-case nil
(progn
(backward-up-list 1)
(while (and (> (point) (point-min))
(progn
(forward-line -1)
(skip-chars-forward " \t")
(or (looking-at "\\s<") ; comment
(looking-at "\\s\"") ; string
(looking-at "\\s$")))) ; skip to previous line
nil)
(setq indent (current-indentation))
(forward-line 0)
(skip-chars-forward " \t")
(if (looking-at "\\s(") ; opening brace
(setq indent (+ indent tab-width))))
(error nil)))
indent)))
(define-derived-mode ztl-mode prog-mode "Ztl"
"Major mode for editing Ztl code."
:syntax-table ztl-mode-syntax-table
(setq-local font-lock-defaults '(ztl-font-lock-keywords))
(setq-local comment-start "// ")
(setq-local comment-end "")
(setq-local parse-sexp-ignore-comments t)
(setq-local indent-line-function 'ztl-indent-line)
(setq-local syntax-propertize-function
(syntax-propertize-rules
;; Line comments starting with //
("\\(//\\)\\(?:[^\n]*\\)" (1 "<")))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.ztl\\'" . ztl-mode))
(provide 'ztl-mode)
;;; ztl-mode.el ends here