diff --git a/grammar.js b/grammar.js index 83a5170..0e38673 100644 --- a/grammar.js +++ b/grammar.js @@ -812,10 +812,6 @@ function sep1(rule, separator) { return seq(rule, repeat(seq(separator, rule))); } -function sep(rule, separator) { - return optional(sep1(rule, separator)); -} - function unaryOp($, assoc, precedence, operator, right = null) { // Expression such as `x + y` falls under the "expression vs local call" // conflict that we already have. By using dynamic precedence we penalize diff --git a/package-lock.json b/package-lock.json index cc7ebad..42945fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ }, "devDependencies": { "prettier": "^2.3.2", - "tree-sitter-cli": "^0.20.0" + "tree-sitter-cli": "^0.19.5" } }, "node_modules/nan": { @@ -33,9 +33,9 @@ } }, "node_modules/tree-sitter-cli": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.0.tgz", - "integrity": "sha512-4D1qapWbJXZ5rrSUGM5rcw5Vuq/smzn9KbiFRhlON6KeuuXjra+KAtDYVrDgAoLIG4ku+jbEEGrJxCptUGi3dg==", + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.19.5.tgz", + "integrity": "sha512-kRzKrUAwpDN9AjA3b0tPBwT1hd8N2oQvvvHup2OEsX6mdsSMLmAvR+NSqK9fe05JrRbVvG8mbteNUQsxlMQohQ==", "dev": true, "hasInstallScript": true, "bin": { @@ -56,9 +56,9 @@ "dev": true }, "tree-sitter-cli": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.0.tgz", - "integrity": "sha512-4D1qapWbJXZ5rrSUGM5rcw5Vuq/smzn9KbiFRhlON6KeuuXjra+KAtDYVrDgAoLIG4ku+jbEEGrJxCptUGi3dg==", + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.19.5.tgz", + "integrity": "sha512-kRzKrUAwpDN9AjA3b0tPBwT1hd8N2oQvvvHup2OEsX6mdsSMLmAvR+NSqK9fe05JrRbVvG8mbteNUQsxlMQohQ==", "dev": true } } diff --git a/package.json b/package.json index 7c419fa..ebc7500 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,12 @@ "version": "0.19.0", "description": "Elixir grammar for tree-sitter", "main": "bindings/node", - "keywords": ["parser", "lexer", "elixir", "tree-sitter"], + "keywords": [ + "parser", + "lexer", + "elixir", + "tree-sitter" + ], "scripts": { "test": "tree-sitter test", "format": "prettier --trailing-comma es5 --write grammar.js", @@ -16,6 +21,16 @@ }, "devDependencies": { "prettier": "^2.3.2", - "tree-sitter-cli": "^0.20.0" - } + "tree-sitter-cli": "^0.19.5" + }, + "tree-sitter": [ + { + "scope": "source.elixir", + "file-types": [ + "ex", + "exs" + ], + "injection-regex": "^(ex|elixir)$" + } + ] } diff --git a/queries/highlights.scm b/queries/highlights.scm new file mode 100644 index 0000000..bb88e45 --- /dev/null +++ b/queries/highlights.scm @@ -0,0 +1,195 @@ +; Reserved keywords + +["when" "and" "or" "not" "in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword + +; Operators + +; * doc string +(unary_operator + operator: "@" @comment.doc + operand: (call + target: (identifier) @comment.doc.__attribute__ + (arguments + [ + (string) @comment.doc + (charlist) @comment.doc + (sigil + quoted_start: _ @comment.doc + quoted_end: _ @comment.doc) @comment.doc + (boolean) @comment.doc + ])) + (#match? @comment.doc.__attribute__ "^(moduledoc|typedoc|doc)$")) + +; * module attribute +(unary_operator + operator: "@" @attribute + operand: [ + (identifier) @attribute + (call + target: (identifier) @attribute) + (boolean) @attribute + (nil) @attribute + ]) + +; * capture operand +(unary_operator + operator: "&" + operand: (integer) @operator) + +(operator_identifier) @operator + +(unary_operator + operator: _ @operator) + +(binary_operator + operator: _ @operator) + +(dot + operator: _ @operator) + +(stab_clause + operator: _ @operator) + +; Literals + +[ + (boolean) + (nil) +] @constant + +[ + (integer) + (float) +] @number + +(alias) @type + +(char) @constant + +; Quoted content + +(interpolation "#{" @punctuation.special "}" @punctuation.special) @embedded + +(escape_sequence) @string.escape + +[ + (atom) + (quoted_atom) + (keyword) + (quoted_keyword) +] @string.special.symbol + +[ + (string) + (charlist) +] @string + +; Note that we explicitly target sigil quoted start/end, so they are not overridden by delimiters + +(sigil + (sigil_name) @__name__ + quoted_start: _ @string + quoted_end: _ @string + (#match? @__name__ "^[sS]$")) @string + +(sigil + (sigil_name) @__name__ + quoted_start: _ @string.regex + quoted_end: _ @string.regex + (#match? @__name__ "^[rR]$")) @string.regex + +(sigil + (sigil_name) @__name__ + quoted_start: _ @string.special + quoted_end: _ @string.special) @string.special + +; Calls + +; * definition keyword +(call + target: (identifier) @keyword + (#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$")) + +; * kernel or special forms keyword +(call + target: (identifier) @keyword + (#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$")) + +; * function call +(call + target: [ + ; local + (identifier) @function + ; remote + (dot + right: (identifier) @function) + ]) + +; * just identifier in function definition +(call + target: (identifier) @keyword + (arguments + [ + (identifier) @function + (binary_operator + left: (identifier) @function + operator: "when") + ]) + (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) + +; * pipe into identifier (definition) +(call + target: (identifier) @keyword + (arguments + (binary_operator + operator: "|>" + right: (identifier) @variable)) + (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) + +; * pipe into identifier (function call) +(binary_operator + operator: "|>" + right: (identifier) @function) + +; Identifiers + +; * special +( + (identifier) @constant.builtin + (#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$") +) + +; * unused +( + (identifier) @comment.unused + (#match? @comment.unused "^_") +) + +; * regular +(identifier) @variable + +; Comment + +(comment) @comment + +; Punctuation + +[ + "%" +] @punctuation + +[ + "," + ";" +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" + "<<" + ">>" +] @punctuation.bracket