Skip to content

Commit

Permalink
Better regexp position accuracy for treesit queries
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiase committed Jun 16, 2023
1 parent a37c060 commit ae7b790
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 37 deletions.
59 changes: 34 additions & 25 deletions relint.el
Original file line number Diff line number Diff line change
Expand Up @@ -1232,35 +1232,47 @@ or in the car of an element."
(relint--check-re-string (car elem) ident pos p)))))
form path))

(defun relint--check-treesit-query (form name pos path)
"Recursively check tree-sitter :match regexps in EXPR.
FORM is assumed a non-literal in the source."
(defun relint--check-treesit-query (form name pos path literal)
"Recursively check tree-sitter :match regexps in the value FORM.
If LITERAL, then PATH is exact."
(pcase form
(`(,_ . ,(or `((:match ,(and (pred stringp) re) . ,_))
;; Optional capture name.
`(,(pred symbolp)
(:match ,(and (pred stringp) re) . ,_))))
(relint--check-re-string re name pos path))
(`(,_ (:match ,(and (pred stringp) re) . ,_))
(relint--check-re-string re name
pos (if literal (cons 1 (cons 1 path)) path)))
(`(,_ ,(pred symbolp) (:match ,(and (pred stringp) re) . ,_))
(relint--check-re-string re name
pos (if literal (cons 1 (cons 2 path)) path)))
((pred consp)
(while (consp form)
(relint--check-treesit-query (car form) name pos path)
(setq form (cdr form))))
(let ((i 0))
(while (consp form)
(relint--check-treesit-query
(car form) name pos (if literal (cons i path) path) literal)
(setq form (cdr form))
(setq i (1+ i)))))
((pred vectorp)
(dotimes (i (length form))
(relint--check-treesit-query (aref form i) name pos path)))))
(relint--check-treesit-query (aref form i) name pos path nil)))))

(defun relint--check-treesit-queries (form name pos path)
"Evaluate and validate FORM as a list of tree-sitter queries."
(relint--eval-list-iter
(lambda (elem elem-path literal)
(relint--check-treesit-query
elem name pos elem-path literal))
form path))

(defun relint--check-treesit-font-lock-rules (form name pos path)
"Check tree-sitter font lock queries.
Evaluate and validate FORM as an arglist for
`treesit-font-lock-rules'."
(relint--eval-list-iter
(let (skip-next)
(lambda (elem elem-path _literal)
(lambda (elem elem-path literal)
(let ((skip skip-next))
;; Skip leading plists.
(setq skip-next (keywordp elem))
(unless (or skip skip-next)
(relint--check-treesit-query elem name pos elem-path)))))
(relint--check-treesit-query elem name pos elem-path literal)))))
form path))

(defun relint--check-treesit-indent-rule (form name pos path literal)
Expand All @@ -1287,8 +1299,7 @@ Evaluate and validate FORM as an arglist for

(defun relint--check-treesit-indent-rules (form name pos path)
"Check tree-sitter indentation rules.
Evaluate and validate FORM as a value for
`treesit-simple-indent-rules'."
Evaluate and validate FORM as a value for `treesit-simple-indent-rules'."
(relint--eval-list-iter
(lambda (lang lang-path literal)
(let ((lang-name (if (consp lang) (format "%s (%s)" name (car lang)) name))
Expand Down Expand Up @@ -2245,25 +2256,23 @@ directly."
(while (consp items)
(if (not (and (keywordp (car items))
(consp (cdr items))))
(relint--check-treesit-query (relint--eval-list (car items))
(format "call to %s" (car form))
pos (cons i path))
(relint--check-treesit-queries
(car items) (format "call to %s" (car form))
pos (cons i path))
;; Skip leading plists.
(setq items (cdr items))
(setq i (1+ i)))
(setq items (cdr items))
(setq i (1+ i)))))
(`(treesit-query-expand ,query . ,_)
(relint--check-treesit-query (relint--eval-list query)
(format "call to %s" (car form))
pos (cons 1 path)))
(relint--check-treesit-queries query (format "call to %s" (car form))
pos (cons 1 path)))
(`(,(or 'treesit-node-top-level 'treesit-query-capture
'treesit-query-compile 'treesit-query-range
'treesit-query-string)
,_ ,query . ,_)
(relint--check-treesit-query (relint--eval-list query)
(format "call to %s" (car form))
pos (cons 2 path)))
(relint--check-treesit-queries query (format "call to %s" (car form))
pos (cons 2 path)))
(`(set (make-local-variable ',(and (pred symbolp) name)) ,expr)
(cond ((memq name relint--known-regexp-variables)
(relint--check-re expr name pos (cons 2 path)))
Expand Down
4 changes: 2 additions & 2 deletions test/1.expected
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@
1.elisp:114:8: In call to syntax-propertize-precompile-rules: Unescaped literal `^' (pos 2)
"^4^"
..^
1.elisp:116:34: In my-ts--font-lock-rules: Duplicated `5' inside character alternative (pos 2)
1.elisp:116:50: In my-ts--font-lock-rules: Duplicated `5' inside character alternative (pos 2)
"[55]"
..^
1.elisp:117:38: In my-ts-mode-font-lock-rules: Duplicated `6' inside character alternative (pos 2)
1.elisp:117:54: In my-ts-mode-font-lock-rules: Duplicated `6' inside character alternative (pos 2)
"[66]"
..^
20 changes: 10 additions & 10 deletions test/14.expected
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
14.elisp:13:4: In call to treesit-font-lock-rules: Unescaped literal `+' (pos 0)
14.elisp:13:23: In call to treesit-font-lock-rules: Unescaped literal `+' (pos 0)
"+f+"
^
14.elisp:13:4: In call to treesit-font-lock-rules: Unescaped literal `+' (pos 0)
14.elisp:14:6: In call to treesit-font-lock-rules: Unescaped literal `+' (pos 0)
"+g+"
^
14.elisp:29:4: In call to treesit-range-rules: Unescaped literal `+' (pos 0)
14.elisp:29:32: In call to treesit-range-rules: Unescaped literal `+' (pos 0)
"+o+"
^
14.elisp:29:4: In call to treesit-range-rules: Unescaped literal `+' (pos 0)
14.elisp:30:6: In call to treesit-range-rules: Unescaped literal `+' (pos 0)
"+p+"
^
14.elisp:33:23: In call to treesit-query-expand: Unescaped literal `+' (pos 0)
14.elisp:33:39: In call to treesit-query-expand: Unescaped literal `+' (pos 0)
"+r+"
^
14.elisp:36:2: In call to treesit-query-compile: Unescaped literal `+' (pos 0)
14.elisp:37:4: In call to treesit-query-compile: Unescaped literal `+' (pos 0)
"+t+"
^
14.elisp:39:29: In call to treesit-node-top-level: Unescaped literal `+' (pos 0)
14.elisp:39:45: In call to treesit-node-top-level: Unescaped literal `+' (pos 0)
"+u+"
^
14.elisp:40:28: In call to treesit-query-capture: Unescaped literal `+' (pos 0)
14.elisp:40:44: In call to treesit-query-capture: Unescaped literal `+' (pos 0)
"+v+"
^
14.elisp:41:26: In call to treesit-query-range: Unescaped literal `+' (pos 0)
14.elisp:41:42: In call to treesit-query-range: Unescaped literal `+' (pos 0)
"+w+"
^
14.elisp:42:27: In call to treesit-query-string: Unescaped literal `+' (pos 0)
14.elisp:42:43: In call to treesit-query-string: Unescaped literal `+' (pos 0)
"+x+"
^

0 comments on commit ae7b790

Please sign in to comment.