Skip to content

Commit

Permalink
Merge pull request #91 from elixir-lang/lexeme-regex-updates
Browse files Browse the repository at this point in the history
Updates to regexes for various lexemes
  • Loading branch information
mattdeboard committed Aug 20, 2014
2 parents 5256ad2 + 6498fe3 commit 26c17f2
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 91 deletions.
186 changes: 108 additions & 78 deletions elixir-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -220,45 +220,49 @@
(((class color) (background dark))
(:foreground "#ff4500"))
(t nil))
"For use with escape characters."
"For use with standalone \"?\" to indicate code point."
:group 'font-lock-faces)

(defvar elixir-attribute-face 'elixir-attribute-face)
(defface elixir-attribute-face
'((((class color) (min-colors 88) (background light))
:foreground "MediumPurple4")
(((class color) (background dark))
(:foreground "thistle"))
(t nil))
"For use with module attribute tokens."
:group 'font-lock-faces)

(defvar elixir-atom-face 'elixir-atom-face)
(defface elixir-atom-face
'((((class color) (min-colors 88) (background light))
:foreground "RoyalBlue4")
(((class color) (background dark))
(:foreground "light sky blue"))
(t nil))
"For use with atoms & map keys."
:group 'font-lock-faces)


(eval-when-compile
(defconst elixir-rx-constituents
`(
;; Match `@doc' or `@moduledoc' syntax, with or without triple quotes.
(heredocs . ,(rx symbol-start
(or "@doc" "@moduledoc" "~s")
symbol-end))
(keywords . ,(rx symbol-start
(or "->" "bc" "lc" "in" "inbits" "inlist" "quote"
"unquote" "unquote_splicing" "var" "do" "after" "for"
"def" "defdelegate" "defimpl" "defmacro" "defmacrop"
"defmodule" "defoverridable" "defp" "defprotocol"
"defrecord" "defstruct" "destructure" "alias"
"require" "import" "use" "if" "unless" "when" "case"
"cond" "throw" "then" "else" "elsif" "try" "catch"
"rescue" "fn" "function" "receive" "end")
symbol-end))
(imports . ,(rx symbol-start
(or "use" "require" "import")
symbol-end))
(bool-and-nil . ,(rx symbol-start
(or "true" "false" "nil")
symbol-end))
(builtins . ,(rx symbol-start
(or "_" "Erlang" "__MODULE__" "__LINE__" "__FILE__"
"__ENV__" "__DIR__")
symbol-end))
(sigils . ,(rx "~" (or "B" "C" "R" "S" "b" "c" "r" "s" "w")))
(method-defines . ,(rx symbol-start
(or "def" "defdelegate" "defmacro" "defmacrop"
"defoverridable" "defp" "defmacrop")
(atoms . ,(rx ":"
(or
(one-or-more (any "a-z" "A-Z" "_" "\"" "'"))
(and "\"" (one-or-more (not (any "\""))) "\"")
(and "'" (one-or-more (not (any "'"))) "'"))))
(builtin . ,(rx symbol-start
(or "case" "cond" "for" "if" "unless" "try" "receive"
"raise" "quote" "unquote" "unquote_splicing" "throw"
"super")
symbol-end))
(module-defines . ,(rx symbol-start
(or "defmodule" "defprotocol" "defimpl"
"defrecord")
symbol-end))
(builtin-declaration . ,(rx symbol-start
(or "def" "defp" "defmodule" "defprotocol"
"defmacro" "defmacrop" "defdelegate"
"defexception" "defstruct" "defimpl"
"defcallback")
symbol-end))
(builtin-modules . ,(rx symbol-start
(or "Agent" "Application" "Atom" "Base"
"Behaviour" "Bitwise" "Builtin" "Code" "Dict"
Expand All @@ -278,10 +282,33 @@
"Task.Supervisor" "Tuple" "URI"
"UnboundMethod" "Version")
symbol-end))
(operators . ,(rx symbol-start
(or "+" "++" "<>" "-" "/" "*" "div" "rem" "==" "!=" "<="
"<" ">=" ">" "===" "!==" "and" "or" "not" "&&" "||"
"!" "." "#" "=" ":=" "<-")))
(builtin-namespace . ,(rx symbol-start
(or "import" "require" "use" "alias")
symbol-end))
;; Set aside code point syntax for `elixir-negation-face'.
(code-point . ,(rx symbol-start
"?"
anything
symbol-end))
(function-declaration . ,(rx symbol-start
(or "def" "defp")
symbol-end))
;; Match `@doc' or `@moduledoc' syntax, with or without triple quotes.
(heredocs . ,(rx symbol-start
(or "@doc" "@moduledoc" "~s")
symbol-end))
;; The first character of an identifier must be a letter or an underscore.
;; After that, they may contain any alphanumeric character + underscore.
;; Additionally, the final character may be either `?' or `!'.
(identifiers . ,(rx (one-or-more (any "A-Z" "a-z""_"))
(zero-or-more (any "A-Z" "a-z" "0-9" "_"))
(optional (or "?" "!"))))
(keyword . ,(rx symbol-start
(or "fn" "do" "end" "after" "else" "rescue" "catch")
symbol-end))
(keyword-operator . ,(rx symbol-start
(or "not" "and" "or" "when" "in")
symbol-end))
;; Module and submodule names start with upper case letter or `_'. This
;; can then be followed by any combination of alphanumeric chars + `_'.
;; In turn, this can be followed by a `.' which begins the notation of
Expand All @@ -297,23 +324,25 @@
(zero-or-more (any "A-Z" "a-z" "_" "0-9"))))
(optional (or "!" "?"))
symbol-end))
;; The first character of an identifier must be a letter or an underscore.
;; After that, they may contain any alphanumeric character + underscore.
;; Additionally, the final character may be either `?' or `!'.
(identifiers . ,(rx symbol-start
(one-or-more (any "A-Z" "a-z""_"))
(zero-or-more (any "A-Z" "a-z" "0-9" "_"))
(optional (or "?" "!"))
(operators1 . ,(rx symbol-start
(or "<" ">" "+" "-" "*" "/" "!" "^" "&")
symbol-end))
(operators2 . ,(rx symbol-start
(or
"==" "!=" "<=" ">=" "&&" "||" "<>" "++" "--" "|>" "=~"
"->" "<-" "|" "." "=")
symbol-end))
(operators3 . ,(rx symbol-start
(or "<<<" ">>>" "|||" "&&&" "^^^" "~~~" "===" "!==")
symbol-end))
(pseudo-var . ,(rx symbol-start
(or "_" "__MODULE__" "__DIR__" "__ENV__" "__CALLER__"
"__block__" "__aliases__")
symbol-end))
(punctuation . ,(rx symbol-start
(or "\\" "<<" ">>" "=>" "(" ")" ":" ";" "" "[" "]")
symbol-end))
(atoms . ,(rx ":"
(or
(one-or-more (any "a-z" "A-Z" "0-9" "_"))
(and "\"" (one-or-more (not (any "\""))) "\"")
(and "'" (one-or-more (not (any "'"))) "'"))))
(code-point . ,(rx symbol-start
"?"
anything
symbol-end))))
(sigils . ,(rx "~" (or "B" "C" "R" "S" "b" "c" "r" "s" "w")))))

(defmacro elixir-rx (&rest sexps)
(let ((rx-constituents (append elixir-rx-constituents rx-constituents)))
Expand All @@ -327,24 +356,26 @@
(defconst elixir-mode-font-lock-defaults
`(
;; Module-defining & namespace builtins
(,(elixir-rx (or module-defines imports)
(,(elixir-rx (or builtin-declaration builtin-namespace)
space
(group module-names))
1 font-lock-type-face)

;; Heredoc
(,(elixir-rx (group heredocs))
1 font-lock-builtin-face)
;; Module attributes
(,(elixir-rx (group (or heredocs
(and "@" (1+ identifiers)))))
1 elixir-attribute-face)

;; Keywords
(,(elixir-rx (group keywords))
(,(elixir-rx (group (or builtin builtin-declaration builtin-namespace
keyword keyword-operator)))
1 font-lock-keyword-face)

;; Method names, i.e. `def foo do'
(,(elixir-rx method-defines
;; Function names, i.e. `def foo do'.
(,(elixir-rx (group function-declaration)
space
(group identifiers))
1 font-lock-function-name-face)
2 font-lock-function-name-face)

;; Variable definitions
(,(elixir-rx (group identifiers)
Expand All @@ -353,10 +384,6 @@
(one-or-more space))
1 font-lock-variable-name-face)

;; Built-in constants
(,(elixir-rx (group builtins))
1 font-lock-builtin-face)

;; Sigils
(,(elixir-rx (group sigils))
1 font-lock-builtin-face)
Expand All @@ -367,38 +394,41 @@
(and "/" (group (one-or-more (not (any "/")))) "/"))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "[" (group (one-or-more (not (any "]")))) "]"))
(and "[" (group (one-or-more (not (any "]")))) "]"))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "{" (group (one-or-more (not (any "}")))) "}"))
(and "{" (group (one-or-more (not (any "}")))) "}"))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "(" (group (one-or-more (not (any ")")))) ")"))
(and "(" (group (one-or-more (not (any ")")))) ")"))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "|" (group (one-or-more (not (any "|")))) "|"))
(and "|" (group (one-or-more (not (any "|")))) "|"))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "\"" (group (one-or-more (not (any "\"")))) "\""))
(and "\"" (group (one-or-more (not (any "\"")))) "\""))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "'" (group (one-or-more (not (any "'")))) "'"))
(and "'" (group (one-or-more (not (any "'")))) "'"))
1 font-lock-string-face)
(,(elixir-rx "~r"
(and "<" (group (one-or-more (not (any ">")))) ">"))
(and "<" (group (one-or-more (not (any ">")))) ">"))
1 font-lock-string-face)

;; TODO: Figure out why atoms are not being colored with `reference-face'
;; Atoms and singleton-like words like true/false/nil.
(,(elixir-rx (or (group atoms) (group bool-and-nil)))
1 font-lock-reference-face)
(,(elixir-rx (group atoms))
1 elixir-atom-face)

;; Map keys
(,(elixir-rx (group (and (one-or-more identifiers) ":")))
1 elixir-atom-face)

;; Built-in modules
(,(elixir-rx (group builtin-modules))
;; Built-in modules and pseudovariables
(,(elixir-rx (group (or builtin-modules pseudo-var)))
1 font-lock-constant-face)

;; Operators
(,(elixir-rx (group operators))
(,(elixir-rx (group (or operators1 operators2 operators3)))
1 elixir-operator-face)

;; Code points
Expand Down
31 changes: 18 additions & 13 deletions test/elixir-mode-font-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -104,36 +104,41 @@ end"
:tags '(fontification heredoc syntax-table)
(elixir-test-with-temp-buffer
"@doc \"\"\""
(should (eq (elixir-test-face-at 1) 'font-lock-builtin-face))
(should (eq (elixir-test-face-at 2) 'font-lock-builtin-face))
(should (eq (elixir-test-face-at 1) 'elixir-attribute-face))
(should (eq (elixir-test-face-at 2) 'elixir-attribute-face))
(should (eq (elixir-test-face-at 6) 'font-lock-string-face))))

(ert-deftest elixir-mode-syntax-table/fontify-heredoc/2 ()
:tags '(fontification heredoc syntax-table)
(elixir-test-with-temp-buffer
"@moduledoc \"\"\""
(should (eq (elixir-test-face-at 1) 'font-lock-builtin-face))
(should (eq (elixir-test-face-at 2) 'font-lock-builtin-face))
(should (eq (elixir-test-face-at 1) 'elixir-attribute-face))
(should (eq (elixir-test-face-at 2) 'elixir-attribute-face))
(should (eq (elixir-test-face-at 12) 'font-lock-string-face))))

(ert-deftest elixir-mode-syntax-table/fontify-heredoc/3 ()
:tags '(fontification heredoc syntax-table)
(elixir-test-with-temp-buffer
"~s\"\"\""
(should (eq (elixir-test-face-at 1) 'font-lock-builtin-face))
(should (eq (elixir-test-face-at 2) 'font-lock-builtin-face))
(should (eq (elixir-test-face-at 1) 'elixir-attribute-face))
(should (eq (elixir-test-face-at 2) 'elixir-attribute-face))
(should (eq (elixir-test-face-at 3) 'font-lock-string-face))))

(ert-deftest elixir-mode-syntax-table/fontify-atoms ()
:tags '(fontification atom syntax-table)
(elixir-test-with-temp-buffer
":oriole
:andale"
;; This is actually the wrong face. I thought I had set these up
;; to use `font-lock-reference-face' but apparently not. See the
;; TODO in `elixir-mode.el' on this.
(should (eq (elixir-test-face-at 3) 'font-lock-constant-face))
(should (eq (elixir-test-face-at 5) 'font-lock-constant-face))
(should (eq (elixir-test-face-at 10) 'font-lock-constant-face))
(should (eq (elixir-test-face-at 13) 'font-lock-constant-face))))
(should (eq (elixir-test-face-at 3) 'elixir-atom-face))
(should (eq (elixir-test-face-at 5) 'elixir-atom-face))
(should (eq (elixir-test-face-at 10) 'elixir-atom-face))
(should (eq (elixir-test-face-at 13) 'elixir-atom-face))))

(ert-deftest elixir-mode-syntax-table/fontify-map-keys ()
:tags '(fontification map syntax-table)
(elixir-test-with-temp-buffer
"%{a: 1, b: 2}"
(should (eq (elixir-test-face-at 3) 'elixir-atom-face))
(should (eq (elixir-test-face-at 4) 'elixir-atom-face))
(should (eq (elixir-test-face-at 9) 'elixir-atom-face))
(should (eq (elixir-test-face-at 10) 'elixir-atom-face))))

0 comments on commit 26c17f2

Please sign in to comment.