(defconst tremor-mode-keywords
'("match" "end" "let" "when" "case" "of" "merge" "patch" "erase" "emit" "drop" "once" "default" "or" "and" "not" "for" "null" "present" "absent" "event"))
(defconst tremor-special-types
'("false" "null" "true"))
(defvar tremor-mode-indent-offset 2
"*Indentation offset for `tremor-mode'.")
(defvar tremor-indent-basic 2
"*Indentation offset for `tremor-mode'.")
(defconst tremor-re-ident "[[:word:][:multibyte:]_][[:word:][:multibyte:]_[:digit:]]*")
(defconst tremor-re-lc-ident "$?[[:lower:][:multibyte:]_][[:word:][:multibyte:]_[:digit:]]*")
(defun tremor-re-word (inner) (concat "\\<" inner "\\>"))
(defun tremor-re-grab (inner) (concat "\\(" inner "\\)"))
(defun tremor-re-shy (inner) (concat "\\(?:" inner "\\)"))
(defconst tremor-re-generic
(concat "<[[:space:]]*'" tremor-re-ident "[[:space:]]*>"))
(defun tremor-re-item-def (itype)
(concat (tremor-re-word itype)
"[[:space:]]+" (tremor-re-grab tremor-re-ident)))
(setq tremor-mode-syntax-table
(let ( (table (make-syntax-table)))
(dolist (i '(?+ ?* ?/ ?% ?& ?| ?^ ?! ?< ?~ ?@ ?.))
(modify-syntax-entry i "." table))
(modify-syntax-entry ?\" "\"" table)
(modify-syntax-entry ?` "\"" table)
(modify-syntax-entry ?| "\"" table)
(modify-syntax-entry ?\\ "\\" table)
(modify-syntax-entry ?# "<" table)
(modify-syntax-entry ?\n ">" table)
table))
(defun tremor-path-font-lock-matcher (re-ident)
"Match occurrences of RE-IDENT followed by a double-colo-n.
Examples include to match names like \"foo::\" or \"Foo::\".
Does not match type annotations of the form \"foo::<\"."
`(lambda (limit)
(catch 'tremor-path-font-lock-matcher
(while t
(let* ((symbol-then-colons (rx-to-string '(seq (group (regexp ,re-ident)) "::")))
(match (re-search-forward symbol-then-colons limit t)))
(cond
((null match) (throw 'tremor-path-font-lock-matcher nil))
((not (looking-at (rx (0+ space) "<")))
(throw 'tremore-path-font-lock-matcher match))))))))
(defvar tremor-mode-font-lock-keywords
(append
`(
(,(regexp-opt tremor-mode-keywords 'symbols) . font-lock-keyword-face)
(,(regexp-opt tremor-special-types 'symbols) . font-lock-type-face)
(,(concat (tremor-re-grab tremor-re-ident) ":[^:]") 1 font-lock-variable-name-face)
(,(tremor-path-font-lock-matcher tremor-re-lc-ident) 1 font-lock-constant-face)
)
))
(defun tremor-mode-syntactic-face-function (state)
"Return face which distinguishes doc and normal comments in the given syntax STATE."
(if (nth 3 state) 'font-lock-string-face
(save-excursion
(goto-char (nth 8 state))
(if (looking-at "#[^#!]")
'font-lock-comment-face
'font-lock-doc-face
))))
(defun tremor--syntax-propertize-raw-string (end)
"A helper for tremor-syntax-propertize.
If point is already in a raw string, this will apply the
appropriate string syntax to the character up to the end of the
raw string, or to END, whichever comes first."
(let ((str-start (nth 8 (syntax-ppss))))
(when str-start
(when (save-excursion
(goto-char str-start)
(looking-at "r\\(#*\\)\\(\"\\)"))
(let ((hashes (match-string 1)))
(when (re-search-forward (concat "\\(\\\\*\\)\\(\"" hashes "\\)") end t)
(put-text-property (match-beginning 1) (match-end 1)
'syntax-table (string-to-syntax "_"))
(put-text-property (1- (match-end 2)) (match-end 2)
'syntax-table (string-to-syntax "|"))
(goto-char (match-end 0))))))))
(defun tremor-ordinary-lt-gt-p ()
"Test whether the `<' or `>' at point is an ordinary operator of some kind.
This returns t if the `<' or `>' is an ordinary operator (like
less-than) or part of one (like `->'); and nil if the character
should be considered a paired angle bracket."
nil)
(eval-and-compile
(defconst tremor--char-literal-rx
(rx (seq
(group "'")
(or
(seq
"\\"
(or
(: "u{" (** 1 6 xdigit) "}")
(: "x" (= 2 xdigit))
(any "'nrt0\"\\")))
(not (any "'\\"))
)
(group "'")))
"A regular expression matching a character literal."))
(defun tremor-syntax-propertize (start end)
"A `syntax-propertize-function' to apply properties from START to END."
(goto-char start)
(tremor--syntax-propertize-raw-string end)
(funcall
(syntax-propertize-rules
("[<>]"
(0 (ignore
(when (save-match-data
(save-excursion
(goto-char (match-beginning 0))
(tremor-ordinary-lt-gt-p)))
(put-text-property (match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax "."))
(goto-char (match-end 0)))))))
(point) end))
(defvar tremor-keywords-regexp
(regexp-opt '("+" "*" "," ";" ">" ">=" "<" "<=" ":=" "=" "++")))
(define-derived-mode tremor-mode prog-mode "Tremor"
"Major mode for Tremor code.
\\{tremor-mode-map}"
:group 'tremor-mode
:syntax-table tremor-mode-syntax-table
(setq-local syntax-propertize-function #'tremor-syntax-propertize)
(setq-local font-lock-defaults '(tremor-mode-font-lock-keywords
nil nil nil nil
(font-lock-syntactic-face-function . tremor-mode-syntactic-face-function)))
(setq-local comment-use-syntax t)
(setq-local comment-start "#")
(setq-local comment-end "")
(setq-local indent-tabs-mode nil)
)
(add-to-list 'auto-mode-alist '("\\.tremor\\'" . tremor-mode))
(provide 'tremor-mode)