summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilfred Hughes <me@wilfred.me.uk>2023-08-08 23:26:49 -0700
committerWilfred Hughes <me@wilfred.me.uk>2023-08-08 23:26:49 -0700
commit20760558ff8a8895b49ce49304f9ade50561bceb (patch)
tree2caf8060cf55fc76baf4ee0f75bd457cd088f7e1
parent3612c472f5f62f6f95219f84c6c0c47bf4f81a4c (diff)
parent338db38330f0d25cba8e2c6428240ebc5e020264 (diff)
-rw-r--r--vendored_parsers/tree-sitter-commonlisp/package.json8
-rw-r--r--vendored_parsers/tree-sitter-commonlisp/queries/tags.scm122
-rw-r--r--vendored_parsers/tree-sitter-commonlisp/test/tags/tags-test.lisp116
3 files changed, 246 insertions, 0 deletions
diff --git a/vendored_parsers/tree-sitter-commonlisp/package.json b/vendored_parsers/tree-sitter-commonlisp/package.json
index d2f574875..7ceefd422 100644
--- a/vendored_parsers/tree-sitter-commonlisp/package.json
+++ b/vendored_parsers/tree-sitter-commonlisp/package.json
@@ -2,6 +2,14 @@
"name": "tree-sitter-commonlisp",
"version": "0.3.0",
"description": "Tree-sitter grammar for Common Lisp",
+ "tree-sitter": [
+ {
+ "scope": "source.lisp",
+ "file-types": [
+ "lisp"
+ ]
+ }
+ ],
"main": "bindings/node",
"scripts": {
"test": "tree-sitter generate && tree-sitter test"
diff --git a/vendored_parsers/tree-sitter-commonlisp/queries/tags.scm b/vendored_parsers/tree-sitter-commonlisp/queries/tags.scm
new file mode 100644
index 000000000..2341c9628
--- /dev/null
+++ b/vendored_parsers/tree-sitter-commonlisp/queries/tags.scm
@@ -0,0 +1,122 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Function Definitions ;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun_header
+ function_name: (sym_lit) @name) @definition.function
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Function Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Basically, we consider every list literal with symbol as the
+;;; first element to be a call to a function named by that element.
+;;; But we must exclude some cases. Note, tree-sitter @ignore
+;;; cases only work if they are declared before the cases
+;;; we want to include.
+
+;; Exclude lambda lists for function definitions
+;; For example:
+;;
+;; (defun my-func (arg1 arg2) ...)
+;;
+;; do not treat (arg1 arg2) as a call of function arg1
+;;
+(defun_header
+ lambda_list: (list_lit . [(sym_lit) (package_lit)] @ignore))
+
+;; Similar to the above, but for
+;;
+;; (defmethod m ((type1 param1) (type2 param2)) ...)
+;;
+;; where list literals having symbol as their first element
+;; are nested inside the lambda list.
+(defun_header
+ lambda_list: (list_lit (list_lit . [(sym_lit) (package_lit)] @ignore)))
+
+;;
+;; (let ((var ...) (var2 ...)) ...)
+;;
+;; - exclude var, var2
+;; - the same for let*, flet, labels, macrolet, symbol-macrolet
+(list_lit . [(sym_lit) (package_lit)] @name
+ . (list_lit (list_lit . [(sym_lit) (package_lit)] @ignore))
+ (#match? @name
+ "(?i)^(cl:)?(let|let\\*|flet|labels|macrolet|symbol-macrolet)$")
+ )
+
+;; TODO:
+;; - exclude also:
+;; - (defclass name (parent parent2)
+;; ((slot1 ...)
+;; (slot2 ...))
+;; exclude the parent, slot1, slot2
+;; - (flet ((func-1 (param1 param2))) ...)
+;; - we already exclude func-1, but param1 is still recognized
+;; as a function call - exclude it too
+;; - the same for labels
+;; - the same macrolet
+;; - what else?
+;; (that's a non-goal to completely support all macros
+;; and special operators, but every one we support
+;; makes the solution a little bit better)
+;; - (flet ((func-1 (param1 param2))) ...)
+;; - instead of simply excluding it, as we do today,
+;; tag func-1 as @local.definition.function (I suppose)
+;; - the same for labels, macrolet
+;; - @local.scope for let, let*, flet, labels, macrolet
+;; - I guess the whole span of the scope text,
+;; till the closing paren, should be tagged as @local.scope;
+;; Hopefully, combined with @local.definition.function
+;; withing the scope, the usual @reference.call within
+;; that scope will refer to the local definition,
+;; and there will be no need to use @local.reference.call
+;; (which is more difficult to implement).
+;; - When implementing, remeber the scope rules differences
+;; of let vs let*, flet vs labels.
+
+
+;; Inlclude all other cases - list literal with symbol as the
+;; first element
+(list_lit . [(sym_lit) (package_lit)] @name) @reference.call
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; classes
+
+(list_lit . [(sym_lit) (package_lit)] @ignore
+ . [(sym_lit) (package_lit)] @name
+ (#match? @ignore "(?i)^(cl:)?defclass$")
+ ) @definition.class
+
+(list_lit . [(sym_lit) (package_lit)] @ignore
+ . (quoting_lit [(sym_lit) (package_lit)] @name)
+ (#match? @ignore "(?i)^(cl:)?make-instance$")
+ ) @reference.class
+
+;;; TODO:
+;; - @reference.class for base classes
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; TODO:
+;; - Symbols referenced in defpackage
+;;
+;; (defpackage ...
+;; (:export (symbol-a :symbol-b #:symbol-c "SYMBOL-D")))
+;;
+;; The goal is to allow quick navigation from the API
+;; overview in the form of defpackage, to the definition
+;; where user can read parameters, docstring, ect.
+;; - The @name must not include the colon, or sharpsign colon, quotes,
+;; just symbol-a, symbol-b, symbol-c, sybmol-d
+;; - Downcase the names specified as stirng literals?
+;; ("SYMBOL-D" -> symbol-d)
+;; - We don't know if the exported symbol is a function, variable,
+;; class or something else. The oficial doc
+;; (https://tree-sitter.github.io/tree-sitter/code-navigation-systems)
+;; does not even suggest a tag for variable reference.
+;; (Although in practice, the `tree-sitter tags` command
+;; allows any @reference.* and @definition.* tags)
+;; Probably it's better to just use @reference.call for all
+;; the symbols in the :export clause.
+;;
+;; - The same for the export function call:
+;;
+;; (export '(symbol-a :symbol-b #:symbol-c "SYMBOL-D"))
diff --git a/vendored_parsers/tree-sitter-commonlisp/test/tags/tags-test.lisp b/vendored_parsers/tree-sitter-commonlisp/test/tags/tags-test.lisp
new file mode 100644
index 000000000..d1fb7a97f
--- /dev/null
+++ b/vendored_parsers/tree-sitter-commonlisp/test/tags/tags-test.lisp
@@ -0,0 +1,116 @@
+;;;; -*- buffer-auto-save-file-name: nil; Mode: LISP; Syntax: COMMON-LISP; indent-tabs-mode: nil; coding: utf-8; show-trailing-whitespace: t -*-
+;;;; Disabled Emacs auto save, by setting buffer-auto-save-file-name: nil
+;;;; because `tree-sitter tests` complains about
+;;;; the auto save file with tilda at the end of the name.
+
+;;;; Negative assertions are not supported,
+;;;; https://github.com/tree-sitter/tree-sitter/issues/2304
+;;;; But I use exclamation sign to mark the places that
+;;;; must not be tagged:
+;;;;
+;;;; ! tag.name
+;;;;
+;;;; They are not checked automatically, but we can check
+;;;; those places manually, by reviewing the output
+;;;; of `tree-sitter tags tags/tags-test.lisp`
+
+
+(defun test-fn (a b)
+ ;; ^ definition.function
+ (let ((x (+ a b))
+ ;; ^ reference.call
+ (y (- a b)))
+ ;; ^ reference.call
+ (* x y)))
+ ;; ^ reference.call
+
+
+(let ((a 1) (b 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+(cl:let ((a 1) (b 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+(let* ((a 1) (b 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+(cl:let* ((a 1) (b 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+
+(LET ((a 1) (bb 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+(lets ((a 1) (bb 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+(zlet ((a 1) (bb 2))
+ ;; ! reference.call
+ ;; ! reference.call
+ )
+
+(defun tst ()
+ ;; ^ definition.function
+ (CL:LET ((a 1)
+ ;; ! reference.call
+ (x 2)
+ ;; ! reference.call
+ (y (add 3 7)))
+ ;; ^ reference.call
+ ;; ! reference.call
+ ))
+
+(flet ((my-add (a b) (+ a b))
+ (my-mul (a b) (* a b)))
+ (my-add 1 (my-mul 7 3)))
+;; ^ reference.call
+;; ^ reference.call
+
+(defclass test-class (base-class)
+ ;; ^ reference.call
+ ;; ^ definition.class
+ ((slot-a)
+ (slot-b)))
+
+(dEFclass test-class (base-class)
+ ;; ^ definition.class
+ ((slot-a)
+ (slot-b)))
+
+(maKE-instance 'test-class)
+;; ^ reference.call
+;; ^ reference.class
+
+(make-instance 'test-class)
+;; ^ reference.call
+;; ^ reference.class
+
+(defclasses test-class2 (base-class)
+ ;; ! reference.class
+ ((slot-a)
+ (slot-b)))
+
+(make-instances 'test-class2)
+;; ! reference.class
+
+(ddddefclass test-class3 (base-class)
+ ;; ! definition.class
+ ((slot-a)
+ (slot-b)))
+
+(mmmmake-instance 'test-class3)
+;; ! reference.class
+
+