From: Yuan Fu Date: Mon, 13 Jan 2025 07:41:47 +0000 (-0800) Subject: Add 'and', 'named', and 'anonymous' predicate for tree-sitter X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=5bc9cd6a818b1a041977b0e0bf9a2c7489cd307d;p=emacs.git Add 'and', 'named', and 'anonymous' predicate for tree-sitter * doc/lispref/parsing.texi (User-defined Things): Mention the new predicate. * src/treesit.c (treesit_traverse_validate_predicate): Recognize named, anonymous, and and predicates. (treesit_traverse_match_predicate): Handle named, anonymous, and and predicates. (cherry picked from commit f0e63558bd3dfd9e57cacfba8690f9dd29774947) --- diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index e16aea6a38d..3e44f31c12c 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -1596,6 +1596,8 @@ the thing. @var{pred} can also be recursively defined. It can be @w{@code{(or @var{pred}@dots{})}}, meaning that satisfying any one of the @var{pred}s +qualifies the node as the thing. It can be @w{@code{(and +@var{pred}@dots{})}}, meaning that satisfying all of the @var{pred}s qualifies the node as the thing. It can be @w{@code{(not @var{pred})}}, meaning that not satisfying @var{pred} qualifies the node. @@ -1604,6 +1606,10 @@ list. For example, @w{@code{(or sexp sentence)}} defines something that's either a @code{sexp} thing or a @code{sentence} thing, as defined by some other rule in the alist. +There are two pre-defined predicates: @code{named} and @code{anonymous}, +that qualifies named and anonymous nodes, respectively. They can be +combined with @code{and} to narrow down the match. + Here's an example @code{treesit-thing-settings} for C and C++: @example @@ -1662,7 +1668,6 @@ signals @code{treesit-invalid-predicate} error. If @var{ignore-missing} is @code{t}, this function doesn't signal the error when @var{thing} is undefined and just returns @code{nil}; but it still signals the error if @var{thing} is a malformed predicate. - @end defun @defun treesit-thing-prev position thing @@ -2179,8 +2184,6 @@ navigation commands that move, respectively, by sexps and sentences by defining variables such as @code{forward-sexp-function} and @code{forward-sentence-function}. @end itemize - -@c TODO: Add treesit-thing-settings stuff once we finalize it. @end defun For more information on these built-in tree-sitter features, diff --git a/src/treesit.c b/src/treesit.c index 878c1f0b340..918b1a510ea 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -3623,6 +3623,9 @@ treesit_traverse_validate_predicate (Lisp_Object pred, return true; else if (SYMBOLP (pred)) { + if (BASE_EQ (pred, Qnamed) || BASE_EQ (pred, Qanonymous)) + return true; + Lisp_Object definition = treesit_traverse_get_predicate (pred, language); if (NILP (definition)) @@ -3667,13 +3670,13 @@ treesit_traverse_validate_predicate (Lisp_Object pred, signal_data, recursion_level + 1); } - else if (BASE_EQ (car, Qor)) + else if (BASE_EQ (car, Qor) || BASE_EQ (car, Qand)) { if (!CONSP (cdr) || NILP (cdr)) { *signal_data = list3 (Qtreesit_invalid_predicate, - build_string ("`or' must have a list " - "of patterns as " + build_string ("`or' or `and' must have " + "a list of patterns as " "arguments "), pred); return false; @@ -3729,6 +3732,14 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred, Lisp_Object lisp_node = make_treesit_node (parser, node); return !NILP (CALLN (Ffuncall, pred, lisp_node)); } + else if (SYMBOLP (pred) && BASE_EQ (pred, Qnamed)) + { + return ts_node_is_named (node); + } + else if (SYMBOLP (pred) && BASE_EQ (pred, Qanonymous)) + { + return !ts_node_is_named (node); + } else if (SYMBOLP (pred)) { Lisp_Object language = XTS_PARSER (parser)->language_symbol; @@ -3755,6 +3766,16 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred, } return false; } + else if (BASE_EQ (car, Qand)) + { + FOR_EACH_TAIL (cdr) + { + if (!treesit_traverse_match_predicate (cursor, XCAR (cdr), + parser, named)) + return false; + } + return true; + } else if (STRINGP (car) && FUNCTIONP (cdr)) { /* A bit of code duplication here, but should be fine. */ @@ -4297,6 +4318,7 @@ syms_of_treesit (void) DEFSYM (Qtreesit_compiled_query_p, "treesit-compiled-query-p"); DEFSYM (Qtreesit_query_p, "treesit-query-p"); DEFSYM (Qnamed, "named"); + DEFSYM (Qanonymous, "anonymous"); DEFSYM (Qmissing, "missing"); DEFSYM (Qextra, "extra"); DEFSYM (Qoutdated, "outdated"); @@ -4338,6 +4360,7 @@ syms_of_treesit (void) DEFSYM (Qtreesit_thing_symbol, "treesit-thing-symbol"); DEFSYM (Qor, "or"); + DEFSYM (Qand, "and"); #ifdef WINDOWSNT DEFSYM (Qtree_sitter, "tree-sitter"); @@ -4420,8 +4443,12 @@ cons (REGEXP . FN), which is a combination of a regexp and a predicate function, and the node has to match both to qualify as the thing. PRED can also be recursively defined. It can be (or PRED...), meaning -satisfying anyone of the inner PREDs qualifies the node; or (not -PRED), meaning not satisfying the inner PRED qualifies the node. +satisfying anyone of the inner PREDs qualifies the node; or (and +PRED...) meaning satisfying all of the inner PREDs qualifies the node; +or (not PRED), meaning not satisfying the inner PRED qualifies the node. + +There are two pre-defined predicates, `named' and `anonymous`. They +match named nodes and anonymous nodes, respectively. Finally, PRED can refer to other THINGs defined in this list by using the symbol of that THING. For example, (or sexp sentence). */);