aboutsummaryrefslogtreecommitdiffstats
path: root/src/treesit.c
diff options
context:
space:
mode:
authorYuan Fu2023-04-14 15:13:11 -0700
committerYuan Fu2023-04-14 16:58:12 -0700
commit67ab357cdccbe6e04eb0b5cff1d6265d668116ce (patch)
tree2772232122f5da7dbe0afd52ff13f52c731bf8b4 /src/treesit.c
parent00fba2a4d54cb117ad3176e6633cf2137d52223a (diff)
downloademacs-67ab357cdccbe6e04eb0b5cff1d6265d668116ce.tar.gz
emacs-67ab357cdccbe6e04eb0b5cff1d6265d668116ce.zip
Support treesit-thing-settings in search functions
* src/treesit.c (safe_assq) (treesit_traverse_get_predicate): New functions. (treesit_traverse_validate_predicate) (treesit_traverse_match_predicate): Support symbols. (Ftreesit_search_subtree) (Ftreesit_search_forward) (Ftreesit_induce_sparse_tree) (Ftreesit_node_match_p): Move validation down so we can pass LANGUAGE to it.
Diffstat (limited to 'src/treesit.c')
-rw-r--r--src/treesit.c103
1 files changed, 88 insertions, 15 deletions
diff --git a/src/treesit.c b/src/treesit.c
index 0a289800a0f..d2dd83b29fe 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -3153,15 +3153,49 @@ treesit_traverse_child_helper (TSTreeCursor *cursor,
3153 } 3153 }
3154} 3154}
3155 3155
3156/* Assq but doesn't signal. */
3157static Lisp_Object
3158safe_assq (Lisp_Object key, Lisp_Object alist)
3159{
3160 Lisp_Object tail = alist;
3161 FOR_EACH_TAIL_SAFE (tail)
3162 if (CONSP (XCAR (tail)) && EQ (XCAR (XCAR (tail)), key))
3163 return XCAR (tail);
3164 return Qnil;
3165}
3166
3167/* Given a symbol THING, and a language symbol LANGUAGE, find the
3168 corresponding predicate definition in treesit-things-settings.
3169 Don't check for the type of THING and LANGUAGE.
3170
3171 If there isn't one, return Qnil. */
3172static Lisp_Object
3173treesit_traverse_get_predicate (Lisp_Object thing, Lisp_Object language)
3174{
3175 Lisp_Object cons = safe_assq (language, Vtreesit_thing_settings);
3176 if (NILP (cons))
3177 return Qnil;
3178 Lisp_Object definitions = XCDR (cons);
3179 Lisp_Object entry = safe_assq (thing, definitions);
3180 if (NILP (entry))
3181 return Qnil;
3182 /* ENTRY looks like (THING PRED). */
3183 Lisp_Object cdr = XCDR (entry);
3184 if (!CONSP (cdr))
3185 return Qnil;
3186 return XCAR (cdr);
3187}
3188
3156/* Validate the PRED passed to treesit_traverse_match_predicate. If 3189/* Validate the PRED passed to treesit_traverse_match_predicate. If
3157 there's an error, set SIGNAL_DATA to something signal accepts, and 3190 there's an error, set SIGNAL_DATA to something signal accepts, and
3158 return false, otherwise return true. This function also check for 3191 return false, otherwise return true. This function also check for
3159 recusion levels: we place a arbitrary 100 level limit on recursive 3192 recusion levels: we place a arbitrary 100 level limit on recursive
3160 predicates. RECURSION_LEVEL is the current recursion level (that 3193 predicates. RECURSION_LEVEL is the current recursion level (that
3161 starts at 0), if it goes over 99, return false and set 3194 starts at 0), if it goes over 99, return false and set
3162 SIGNAL_DATA. */ 3195 SIGNAL_DATA. LANGUAGE is a LANGUAGE symbol. */
3163static bool 3196static bool
3164treesit_traverse_validate_predicate (Lisp_Object pred, 3197treesit_traverse_validate_predicate (Lisp_Object pred,
3198 Lisp_Object language,
3165 Lisp_Object *signal_data, 3199 Lisp_Object *signal_data,
3166 ptrdiff_t recursion_level) 3200 ptrdiff_t recursion_level)
3167{ 3201{
@@ -3176,6 +3210,23 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
3176 return true; 3210 return true;
3177 else if (FUNCTIONP (pred)) 3211 else if (FUNCTIONP (pred))
3178 return true; 3212 return true;
3213 else if (SYMBOLP (pred))
3214 {
3215 Lisp_Object definition = treesit_traverse_get_predicate (pred,
3216 language);
3217 if (NILP (definition))
3218 {
3219 *signal_data = list2 (build_string ("Cannot find the definition "
3220 "of the predicate in "
3221 "`treesit-things-settings'"),
3222 pred);
3223 return false;
3224 }
3225 return treesit_traverse_validate_predicate (definition,
3226 language,
3227 signal_data,
3228 recursion_level + 1);
3229 }
3179 else if (CONSP (pred)) 3230 else if (CONSP (pred))
3180 { 3231 {
3181 Lisp_Object car = XCAR (pred); 3232 Lisp_Object car = XCAR (pred);
@@ -3198,6 +3249,7 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
3198 return false; 3249 return false;
3199 } 3250 }
3200 return treesit_traverse_validate_predicate (XCAR (cdr), 3251 return treesit_traverse_validate_predicate (XCAR (cdr),
3252 language,
3201 signal_data, 3253 signal_data,
3202 recursion_level + 1); 3254 recursion_level + 1);
3203 } 3255 }
@@ -3214,6 +3266,7 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
3214 FOR_EACH_TAIL (cdr) 3266 FOR_EACH_TAIL (cdr)
3215 { 3267 {
3216 if (!treesit_traverse_validate_predicate (XCAR (cdr), 3268 if (!treesit_traverse_validate_predicate (XCAR (cdr),
3269 language,
3217 signal_data, 3270 signal_data,
3218 recursion_level + 1)) 3271 recursion_level + 1))
3219 return false; 3272 return false;
@@ -3259,6 +3312,14 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
3259 Lisp_Object lisp_node = make_treesit_node (parser, node); 3312 Lisp_Object lisp_node = make_treesit_node (parser, node);
3260 return !NILP (CALLN (Ffuncall, pred, lisp_node)); 3313 return !NILP (CALLN (Ffuncall, pred, lisp_node));
3261 } 3314 }
3315 else if (SYMBOLP (pred))
3316 {
3317 Lisp_Object language = XTS_PARSER (parser)->language_symbol;
3318 Lisp_Object definition = treesit_traverse_get_predicate (pred,
3319 language);
3320 return treesit_traverse_match_predicate (cursor, definition,
3321 parser, named);
3322 }
3262 else if (CONSP (pred)) 3323 else if (CONSP (pred))
3263 { 3324 {
3264 Lisp_Object car = XCAR (pred); 3325 Lisp_Object car = XCAR (pred);
@@ -3412,10 +3473,6 @@ Return the first matched node, or nil if none matches. */)
3412 CHECK_SYMBOL (all); 3473 CHECK_SYMBOL (all);
3413 CHECK_SYMBOL (backward); 3474 CHECK_SYMBOL (backward);
3414 3475
3415 Lisp_Object signal_data = Qnil;
3416 if (!treesit_traverse_validate_predicate (predicate, &signal_data, 0))
3417 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3418
3419 /* We use a default limit of 1000. See bug#59426 for the 3476 /* We use a default limit of 1000. See bug#59426 for the
3420 discussion. */ 3477 discussion. */
3421 ptrdiff_t the_limit = TREESIT_RECURSION_LIMIT; 3478 ptrdiff_t the_limit = TREESIT_RECURSION_LIMIT;
@@ -3428,6 +3485,13 @@ Return the first matched node, or nil if none matches. */)
3428 treesit_initialize (); 3485 treesit_initialize ();
3429 3486
3430 Lisp_Object parser = XTS_NODE (node)->parser; 3487 Lisp_Object parser = XTS_NODE (node)->parser;
3488 Lisp_Object language = XTS_PARSER (parser)->language_symbol;
3489
3490 Lisp_Object signal_data = Qnil;
3491 if (!treesit_traverse_validate_predicate (predicate, language,
3492 &signal_data, 0))
3493 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3494
3431 Lisp_Object return_value = Qnil; 3495 Lisp_Object return_value = Qnil;
3432 TSTreeCursor cursor; 3496 TSTreeCursor cursor;
3433 if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser)) 3497 if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser))
@@ -3483,13 +3547,16 @@ always traverse leaf nodes first, then upwards. */)
3483 CHECK_SYMBOL (all); 3547 CHECK_SYMBOL (all);
3484 CHECK_SYMBOL (backward); 3548 CHECK_SYMBOL (backward);
3485 3549
3486 Lisp_Object signal_data = Qnil;
3487 if (!treesit_traverse_validate_predicate (predicate, &signal_data, 0))
3488 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3489
3490 treesit_initialize (); 3550 treesit_initialize ();
3491 3551
3492 Lisp_Object parser = XTS_NODE (start)->parser; 3552 Lisp_Object parser = XTS_NODE (start)->parser;
3553 Lisp_Object language = XTS_PARSER (parser)->language_symbol;
3554
3555 Lisp_Object signal_data = Qnil;
3556 if (!treesit_traverse_validate_predicate (predicate, language,
3557 &signal_data, 0))
3558 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3559
3493 Lisp_Object return_value = Qnil; 3560 Lisp_Object return_value = Qnil;
3494 TSTreeCursor cursor; 3561 TSTreeCursor cursor;
3495 if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser)) 3562 if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser))
@@ -3600,10 +3667,6 @@ a regexp. */)
3600{ 3667{
3601 CHECK_TS_NODE (root); 3668 CHECK_TS_NODE (root);
3602 3669
3603 Lisp_Object signal_data = Qnil;
3604 if (!treesit_traverse_validate_predicate (predicate, &signal_data, 0))
3605 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3606
3607 if (!NILP (process_fn)) 3670 if (!NILP (process_fn))
3608 CHECK_TYPE (FUNCTIONP (process_fn), Qfunctionp, process_fn); 3671 CHECK_TYPE (FUNCTIONP (process_fn), Qfunctionp, process_fn);
3609 3672
@@ -3619,6 +3682,13 @@ a regexp. */)
3619 treesit_initialize (); 3682 treesit_initialize ();
3620 3683
3621 Lisp_Object parser = XTS_NODE (root)->parser; 3684 Lisp_Object parser = XTS_NODE (root)->parser;
3685 Lisp_Object language = XTS_PARSER (parser)->language_symbol;
3686
3687 Lisp_Object signal_data = Qnil;
3688 if (!treesit_traverse_validate_predicate (predicate, language,
3689 &signal_data, 0))
3690 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3691
3622 Lisp_Object parent = Fcons (Qnil, Qnil); 3692 Lisp_Object parent = Fcons (Qnil, Qnil);
3623 /* In this function we never traverse above NODE, so we don't need 3693 /* In this function we never traverse above NODE, so we don't need
3624 to use treesit_cursor_helper. */ 3694 to use treesit_cursor_helper. */
@@ -3652,11 +3722,14 @@ if NODE matches PRED, nil otherwise. */)
3652{ 3722{
3653 CHECK_TS_NODE (node); 3723 CHECK_TS_NODE (node);
3654 3724
3725 Lisp_Object parser = XTS_NODE (node)->parser;
3726 Lisp_Object language = XTS_PARSER (parser)->language_symbol;
3727
3655 Lisp_Object signal_data = Qnil; 3728 Lisp_Object signal_data = Qnil;
3656 if (!treesit_traverse_validate_predicate (predicate, &signal_data, 0)) 3729 if (!treesit_traverse_validate_predicate (predicate, language,
3730 &signal_data, 0))
3657 xsignal1 (Qtreesit_invalid_predicate, signal_data); 3731 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3658 3732
3659 Lisp_Object parser = XTS_NODE (node)->parser;
3660 TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (node)->node); 3733 TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (node)->node);
3661 3734
3662 specpdl_ref count = SPECPDL_INDEX (); 3735 specpdl_ref count = SPECPDL_INDEX ();