diff options
| author | Yuan Fu | 2023-04-14 15:13:11 -0700 |
|---|---|---|
| committer | Yuan Fu | 2023-04-14 16:58:12 -0700 |
| commit | 67ab357cdccbe6e04eb0b5cff1d6265d668116ce (patch) | |
| tree | 2772232122f5da7dbe0afd52ff13f52c731bf8b4 /src | |
| parent | 00fba2a4d54cb117ad3176e6633cf2137d52223a (diff) | |
| download | emacs-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')
| -rw-r--r-- | src/treesit.c | 103 |
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. */ | ||
| 3157 | static Lisp_Object | ||
| 3158 | safe_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. */ | ||
| 3172 | static Lisp_Object | ||
| 3173 | treesit_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. */ |
| 3163 | static bool | 3196 | static bool |
| 3164 | treesit_traverse_validate_predicate (Lisp_Object pred, | 3197 | treesit_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 (); |