Skip to content

Commit

Permalink
Keyword and Symbol prefix matching (#27)
Browse files Browse the repository at this point in the history
Co-authored-by: Martynas M <[email protected]>
  • Loading branch information
axvr and Invertisment committed Jan 7, 2023
2 parents b21188c + 7d46e29 commit 06196d8
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 25 deletions.
127 changes: 111 additions & 16 deletions clj/test/vim/syntax_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,54 @@
;; Joel Holdbrooks <[email protected]>

(ns vim.syntax-test
(:require [vim.test :refer [defpredicates defsyntaxtest]]))
(:require [vim.test :refer [defpredicates defsyntaxtest def-eq-predicates]]))

;; defpredicates also register not-equal vars, this is just for clj-kondo
(declare !number !regexp-escape !regexp-posix-char-class !regexp-quantifier)

(defpredicates number :clojureNumber)
(defpredicates kw :clojureKeyword)
(def-eq-predicates kw [:clojureKeywordNsColon :clojureKeyword])
(def-eq-predicates kwCurrentNs [:clojureKeywordNsColon :clojureKeywordNsColon :clojureKeyword])
(def-eq-predicates kwWithNs [:clojureKeywordNsColon :clojureKeywordNs :clojureKeywordNsSeparator :clojureKeyword])
(def-eq-predicates kwWithNs3_4 [:clojureKeywordNsColon
:clojureKeywordNs
:clojureKeywordNs
:clojureKeywordNs
:clojureKeywordNsSeparator
:clojureKeyword
:clojureKeyword
:clojureKeyword
:clojureKeyword])
(def-eq-predicates sym [:clojureSymbol])
(def-eq-predicates symWithNs [:clojureSymbol])
(def-eq-predicates symWithNs_tripleBody [:clojureKeywordNsColon
:clojureKeywordNs :clojureKeywordNsSeparator
:clojureKeywordNs :clojureKeywordNsSeparator
:clojureKeywordNs :clojureKeywordNsSeparator
:clojureKeyword])
(def-eq-predicates kwWithNamedNs [:clojureKeywordNsColon :clojureKeywordNsColon
:clojureKeywordNs :clojureKeywordNsSeparator :clojureKeyword])
(def-eq-predicates dispatchWithSymbolInside [:clojureDispatch
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureParen
:clojureSymbolNs
:clojureSymbolNs
:clojureSymbolNs
:clojureSymbolNs
:clojureSymbolNsSeparator
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureParen])
(defpredicates character :clojureCharacter)
(defpredicates regexp :clojureRegexp)
(defpredicates regexp-delimiter :clojureRegexpDelimiter)
Expand Down Expand Up @@ -108,23 +149,78 @@

(comment (test #'test-character-literals))

(def emptyKeyword (keyword ""))

(defsyntaxtest keywords-test
["%s"
[":1" kw
":A" kw
":a" kw
":αβγ" kw
"::a" kw
":a/b" kw
":a:b" kw
":a:b/:c:b" kw
":a/b/c/d" kw
"::a/b" kw
"::" !kw
":a:" !kw
":a/" !kw
; ":/" !kw ; This is legal, but for simplicity we do not match it
":" !kw]])
":αβγ" (partial = [:clojureKeywordNsColon :clojureKeyword :clojureKeyword :clojureKeyword])
"::a" kwCurrentNs
":a/b" kwWithNs
":a:b/:c:b" kwWithNs3_4
":a/b/c/d" symWithNs_tripleBody
"::a/b" kwWithNamedNs
"::" (partial = [emptyKeyword emptyKeyword])
":a:" (partial = [emptyKeyword :clojureSymbol emptyKeyword])
":a/" (partial = [:clojureKeywordNsColon :clojureKeywordNs :clojureKeywordNsSeparator])
":/" (partial = [:clojureKeywordNsColon :clojureKeywordNsSeparator])
":" (partial = [emptyKeyword])
"a[:b/c]" (partial = [:clojureSymbol
:clojureParen
:clojureKeywordNsColon
:clojureKeywordNs
:clojureKeywordNsSeparator
:clojureKeyword
:clojureParen])
":a[:b/c]" (partial = [:clojureKeywordNsColon
:clojureKeyword
:clojureParen
:clojureKeywordNsColon
:clojureKeywordNs
:clojureKeywordNsSeparator
:clojureKeyword
:clojureParen])]])

(defsyntaxtest symbols-test
["%s"
["1" !sym
"1" !symWithNs
"A" sym
"a" sym
"αβγ" (partial = [:clojureSymbol :clojureSymbol :clojureSymbol])
"a/b" (partial = [:clojureSymbolNs :clojureSymbolNsSeparator :clojureSymbol])
"a:b" (partial = [:clojureSymbol :clojureSymbol :clojureSymbol])
"a:b/:c:b" (partial = [:clojureSymbolNs
:clojureSymbolNs
:clojureSymbolNs
:clojureSymbolNsSeparator
:clojureSymbol
:clojureSymbol
:clojureSymbol
:clojureSymbol])
"a/b/c/d" (partial = [:clojureSymbolNs :clojureSymbolNsSeparator
:clojureSymbolNs :clojureSymbolNsSeparator
:clojureSymbolNs :clojureSymbolNsSeparator
:clojureSymbol])
"a:" !sym
"a:" !symWithNs
"a/" !sym
"a/" !symWithNs
"/" !sym
"#function[test/hello]" dispatchWithSymbolInside
"a[b/c]" (partial = [:clojureSymbol
:clojureParen
:clojureSymbolNs
:clojureSymbolNsSeparator
:clojureSymbol
:clojureParen])
"#'a/b" (partial = [:clojureDispatch
:clojureDispatch
:clojureSymbolNs
:clojureSymbolNsSeparator
:clojureSymbol])]])

(comment (test #'keywords-test))

Expand Down Expand Up @@ -403,8 +499,7 @@
;; (?>X) X, as an independent, non-capturing group
"(?>X)" regexp-mod

"(?X)" !regexp-mod
]]
"(?X)" !regexp-mod]]
["#%s"
[;; Backslashes with character classes
"\"[\\\\]\"" (partial = [:clojureRegexpDelimiter :clojureRegexpCharClass :clojureRegexpCharClass :clojureRegexpCharClass :clojureRegexpCharClass :clojureRegexpDelimiter])
Expand Down
26 changes: 20 additions & 6 deletions clj/test/vim/test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,35 @@
ss λs)))
contexts)))))

(defmacro defpredicates
(defmacro defpredicates-general
"Create two complementary predicate vars, `sym` and `!sym`, which test if
all members of a passed collection are equal to `kw`"
[sym kw]
[pred-eq pred-neq sym kw]
`(do
(defn ~sym
~(str "Returns true if all elements of coll equal " kw)
{:arglists '~'[coll]}
{:arglists (list '~'[coll])}
[coll#]
(every? (partial = ~kw) coll#))
(~pred-eq ~kw coll#))
(defn ~(symbol (str \! sym))
~(str "Returns true if any elements of coll do not equal " kw)
{:arglists '~'[coll]}
{:arglists (list '~'[coll])}
[coll#]
(boolean (some (partial not= ~kw) coll#)))))
(~pred-neq ~kw coll#))))

(defmacro defpredicates
"Create two complementary predicate vars, `sym` and `!sym`, which test if
all members of a passed collection are equal to `kw`"
[sym kw]
(let [pred-eq (fn [expected results] (every? (partial = expected) results))
pred-neq (fn [expected results] (boolean (some (partial not= expected) results)))]
`(defpredicates-general ~pred-eq ~pred-neq ~sym ~kw)))

(defmacro def-eq-predicates
"Create two complementary predicate vars, `sym` and `!sym`, which test if
input and result are equal"
[sym kw]
`(defpredicates-general = not= ~sym ~kw))

(defn benchmark [n file buf & exprs]
(vim-exec file buf (format "Benchmark(%d, %s)"
Expand Down
16 changes: 13 additions & 3 deletions syntax/clojure.vim
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,26 @@ endif
unlet! s:key
delfunction s:syntax_keyword

syntax match clojureKeywordNs contained "\v[^ \n\r\t()\[\]{}";@^`~\\\/'#]+\ze\/"
syntax match clojureKeywordNsSeparator contained "/"
syntax match clojureKeywordNsColon contained "\v<:{1,2}"
" Keywords are symbols:
" static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^/]].*/)?([\\D&&[^/]][^/]*)");
" But they:
" * Must not end in a : or /
" * Must not have two adjacent colons except at the beginning
" * Must not contain any reader metacharacters except for ' and #
syntax match clojureKeyword "\v<:{1,2}([^ \n\r\t()\[\]{}";@^`~\\/]+/)*[^ \n\r\t()\[\]{}";@^`~\\/]+:@1<!>"
syntax match clojureKeyword "\v<:{1,2}([^ \n\r\t()\[\]{}";@^`~\\/]*/)*[^ \n\r\t()\[\]{}";@^`~\\/]*:@1<!>" contains=clojureKeywordNs,clojureKeywordNsSeparator,clojureKeywordNsColon

syntax match clojureStringEscape "\v\\%([\\btnfr"]|u\x{4}|[0-3]\o{2}|\o{1,2})" contained

syntax region clojureString matchgroup=clojureStringDelimiter start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=clojureStringEscape,@Spell

syntax match clojureCharacter "\v\\%(o%([0-3]\o{2}|\o{1,2})|u\x{4}|newline|tab|space|return|backspace|formfeed|.)"

syntax match clojureSymbol "\v%([a-zA-Z!$&*_+=|<.>?-]|[^\x00-\x7F])+%(:?%([a-zA-Z0-9!#$%&*_+=|'<.>/?-]|[^\x00-\x7F]))*[#:]@1<!"
syntax match clojureSymbolNs contained "\v[^ \n\r\t()\[\]{}";@^`~\\\/'#]+\ze\/"
syntax match clojureSymbolNsSeparator contained "/"
syntax match clojureSymbol "\v%([a-zA-Z!$&*_+=|<.>?-]|[^\x00-\x7F])+%(:?%([a-zA-Z0-9!#$%&*_+=|'<.>/?-]|[^\x00-\x7F]))*[#:]@1<!" contains=clojureSymbolNs,clojureSymbolNsSeparator

" NB. Correct matching of radix literals was removed for better performance.
syntax match clojureNumber "\v<[-+]?%(%([2-9]|[12]\d|3[0-6])[rR][[:alnum:]]+|%(0\o*|0x\x+|[1-9]\d*)N?|%(0|[1-9]\d*|%(0|[1-9]\d*)\.\d*)%(M|[eE][-+]?\d+)?|%(0|[1-9]\d*)/%(0|[1-9]\d*))>"
Expand Down Expand Up @@ -162,12 +167,17 @@ syntax sync fromstart
highlight default link clojureConstant Constant
highlight default link clojureBoolean Boolean
highlight default link clojureCharacter Character
highlight default link clojureKeyword Keyword
highlight default link clojureNumber Number
highlight default link clojureString String
highlight default link clojureStringDelimiter String
highlight default link clojureStringEscape Character

highlight default link clojureKeyword Keyword
highlight default link clojureKeywordNsColon clojureKeyword
highlight default link clojureKeywordNs clojureKeyword

highlight default link clojureSymbolNs clojureSymbol

highlight default link clojureRegexp Constant
highlight default link clojureRegexpDelimiter Constant
highlight default link clojureRegexpEscape Character
Expand Down

0 comments on commit 06196d8

Please sign in to comment.