aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/data.c5
-rw-r--r--src/eval.c3
-rw-r--r--src/treesit.c201
3 files changed, 178 insertions, 31 deletions
diff --git a/src/data.c b/src/data.c
index 8dc5000424e..4ab37e86ce5 100644
--- a/src/data.c
+++ b/src/data.c
@@ -4217,10 +4217,11 @@ syms_of_data (void)
4217 Fput (Qrecursion_error, Qerror_message, build_pure_c_string 4217 Fput (Qrecursion_error, Qerror_message, build_pure_c_string
4218 ("Excessive recursive calling error")); 4218 ("Excessive recursive calling error"));
4219 4219
4220 PUT_ERROR (Qexcessive_variable_binding, recursion_tail,
4221 "Variable binding depth exceeds max-specpdl-size");
4222 PUT_ERROR (Qexcessive_lisp_nesting, recursion_tail, 4220 PUT_ERROR (Qexcessive_lisp_nesting, recursion_tail,
4223 "Lisp nesting exceeds `max-lisp-eval-depth'"); 4221 "Lisp nesting exceeds `max-lisp-eval-depth'");
4222 /* Error obsolete (from 29.1), kept for compatibility. */
4223 PUT_ERROR (Qexcessive_variable_binding, recursion_tail,
4224 "Variable binding depth exceeds max-specpdl-size");
4224 4225
4225 /* Types that type-of returns. */ 4226 /* Types that type-of returns. */
4226 DEFSYM (Qinteger, "integer"); 4227 DEFSYM (Qinteger, "integer");
diff --git a/src/eval.c b/src/eval.c
index 1a4d3ad0307..545a280ae91 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2373,8 +2373,7 @@ grow_specpdl_allocation (void)
2373 union specbinding *pdlvec = specpdl - 1; 2373 union specbinding *pdlvec = specpdl - 1;
2374 ptrdiff_t size = specpdl_end - specpdl; 2374 ptrdiff_t size = specpdl_end - specpdl;
2375 ptrdiff_t pdlvecsize = size + 1; 2375 ptrdiff_t pdlvecsize = size + 1;
2376 if (max_size <= size) 2376 eassert (max_size > size);
2377 xsignal0 (Qexcessive_variable_binding); /* Can't happen, essentially. */
2378 pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl); 2377 pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl);
2379 specpdl = pdlvec + 1; 2378 specpdl = pdlvec + 1;
2380 specpdl_end = specpdl + pdlvecsize - 1; 2379 specpdl_end = specpdl + pdlvecsize - 1;
diff --git a/src/treesit.c b/src/treesit.c
index fd5fda78133..45b5ab15390 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -3139,10 +3139,84 @@ treesit_traverse_child_helper (TSTreeCursor *cursor,
3139 } 3139 }
3140} 3140}
3141 3141
3142/* Return true if the node at CURSOR matches PRED. PRED can be a 3142/* Validate the PRED passed to treesit_traverse_match_predicate. If
3143 string or a function. This function assumes PRED is either a 3143 there's an error, set SIGNAL_DATA to something signal accepts, and
3144 string or a function. If NAMED is true, also check that the node 3144 return false, otherwise return true. */
3145 is named. */ 3145static bool
3146treesit_traverse_validate_predicate (Lisp_Object pred,
3147 Lisp_Object *signal_data)
3148{
3149 if (STRINGP (pred))
3150 return true;
3151 /* We want to allow cl-labels-defined functions, so we allow
3152 symbols. */
3153 else if (FUNCTIONP (pred) || SYMBOLP (pred))
3154 return true;
3155 else if (CONSP (pred))
3156 {
3157 Lisp_Object car = XCAR (pred);
3158 Lisp_Object cdr = XCDR (pred);
3159 if (EQ (car, Qnot))
3160 {
3161 if (!CONSP (cdr))
3162 {
3163 *signal_data = list2 (build_string ("Invalide `not' "
3164 "predicate"),
3165 pred);
3166 return false;
3167 }
3168 /* At this point CDR must be a cons. */
3169 if (XFIXNUM (Flength (cdr)) != 1)
3170 {
3171 *signal_data = list2 (build_string ("`not' can only "
3172 "have one argument"),
3173 pred);
3174 return false;
3175 }
3176 return treesit_traverse_validate_predicate (XCAR (cdr),
3177 signal_data);
3178 }
3179 else if (EQ (car, Qor))
3180 {
3181 if (!CONSP (cdr) || NILP (cdr))
3182 {
3183 *signal_data = list2 (build_string ("`or' must have a list "
3184 "of patterns as "
3185 "arguments "),
3186 pred);
3187 return false;
3188 }
3189 FOR_EACH_TAIL (cdr)
3190 {
3191 if (!treesit_traverse_validate_predicate (XCAR (cdr),
3192 signal_data))
3193 return false;
3194 }
3195 return true;
3196 }
3197 /* We allow the function to be a symbol to support cl-label. */
3198 else if (STRINGP (car) && (FUNCTIONP (cdr) || SYMBOLP (cdr)))
3199 return true;
3200 }
3201 *signal_data = list2 (build_string ("Invalid predicate, see TODO for "
3202 "valid forms of predicate"),
3203 pred);
3204 return false;
3205}
3206
3207/* Return true if the node at CURSOR matches PRED. PRED can be a lot
3208 of things:
3209
3210 PRED := string | function | (string . function)
3211 | (or PRED...) | (not PRED)
3212
3213 See docstring of treesit-search-forward and friends for the meaning
3214 of each shape.
3215
3216 This function assumes PRED is in one of its valid forms. If NAMED
3217 is true, also check that the node is named.
3218
3219 This function may signal if the predicate function signals. */
3146static bool 3220static bool
3147treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred, 3221treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
3148 Lisp_Object parser, bool named) 3222 Lisp_Object parser, bool named)
@@ -3156,24 +3230,62 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
3156 const char *type = ts_node_type (node); 3230 const char *type = ts_node_type (node);
3157 return fast_c_string_match (pred, type, strlen (type)) >= 0; 3231 return fast_c_string_match (pred, type, strlen (type)) >= 0;
3158 } 3232 }
3159 else 3233 /* We want to allow cl-labels-defined functions, so we allow
3234 symbols. */
3235 else if (FUNCTIONP (pred) || SYMBOLP (pred))
3160 { 3236 {
3161 Lisp_Object lisp_node = make_treesit_node (parser, node); 3237 Lisp_Object lisp_node = make_treesit_node (parser, node);
3162 return !NILP (CALLN (Ffuncall, pred, lisp_node)); 3238 return !NILP (CALLN (Ffuncall, pred, lisp_node));
3163 } 3239 }
3240 else if (CONSP (pred))
3241 {
3242 Lisp_Object car = XCAR (pred);
3243 Lisp_Object cdr = XCDR (pred);
3244
3245 if (EQ (car, Qnot))
3246 return !treesit_traverse_match_predicate (cursor, XCAR (cdr),
3247 parser, named);
3248 else if (EQ (car, Qor))
3249 {
3250 FOR_EACH_TAIL (cdr)
3251 {
3252 if (treesit_traverse_match_predicate (cursor, XCAR (cdr),
3253 parser, named))
3254 return true;
3255 }
3256 return false;
3257 }
3258 /* We want to allow cl-labels-defined functions, so we allow
3259 symbols. */
3260 else if (STRINGP (car) && (FUNCTIONP (cdr) || SYMBOLP (cdr)))
3261 {
3262 /* A bit of code duplication here, but should be fine. */
3263 const char *type = ts_node_type (node);
3264 if (!(fast_c_string_match (pred, type, strlen (type)) >= 0))
3265 return false;
3266
3267 Lisp_Object lisp_node = make_treesit_node (parser, node);
3268 if (NILP (CALLN (Ffuncall, pred, lisp_node)))
3269 return false;
3270
3271 return true;
3272 }
3273 }
3274 /* Returning false is better than UB. */
3275 return false;
3164} 3276}
3165 3277
3166/* Traverse the parse tree starting from CURSOR. PRED can be a 3278/* Traverse the parse tree starting from CURSOR. See TODO for the
3167 function (takes a node and returns nil/non-nil), or a string 3279 shapes PRED can have. If the node satisfies PRED, leave CURSOR on
3168 (treated as regexp matching the node's type, must be all single 3280 that node and return true. If no node satisfies PRED, move CURSOR
3169 byte characters). If the node satisfies PRED, leave CURSOR on that 3281 back to starting position and return false.
3170 node and return true. If no node satisfies PRED, move CURSOR back
3171 to starting position and return false.
3172 3282
3173 LIMIT is the number of levels we descend in the tree. FORWARD 3283 LIMIT is the number of levels we descend in the tree. FORWARD
3174 controls the direction in which we traverse the tree, true means 3284 controls the direction in which we traverse the tree, true means
3175 forward, false backward. If SKIP_ROOT is true, don't match ROOT. 3285 forward, false backward. If SKIP_ROOT is true, don't match ROOT.
3176 */ 3286
3287 This function may signal if the predicate function signals. */
3288
3177static bool 3289static bool
3178treesit_search_dfs (TSTreeCursor *cursor, 3290treesit_search_dfs (TSTreeCursor *cursor,
3179 Lisp_Object pred, Lisp_Object parser, 3291 Lisp_Object pred, Lisp_Object parser,
@@ -3209,7 +3321,10 @@ treesit_search_dfs (TSTreeCursor *cursor,
3209 START. PRED, PARSER, NAMED, FORWARD are the same as in 3321 START. PRED, PARSER, NAMED, FORWARD are the same as in
3210 ts_search_subtree. If a match is found, leave CURSOR at that node, 3322 ts_search_subtree. If a match is found, leave CURSOR at that node,
3211 and return true, if no match is found, return false, and CURSOR's 3323 and return true, if no match is found, return false, and CURSOR's
3212 position is undefined. */ 3324 position is undefined.
3325
3326 This function may signal if the predicate function signals. */
3327
3213static bool 3328static bool
3214treesit_search_forward (TSTreeCursor *cursor, 3329treesit_search_forward (TSTreeCursor *cursor,
3215 Lisp_Object pred, Lisp_Object parser, 3330 Lisp_Object pred, Lisp_Object parser,
@@ -3219,8 +3334,7 @@ treesit_search_forward (TSTreeCursor *cursor,
3219 nodes. This way repeated call of this function traverses each 3334 nodes. This way repeated call of this function traverses each
3220 node in the tree once and only once: 3335 node in the tree once and only once:
3221 3336
3222 (while node (setq node (treesit-search-forward node))) 3337 (while node (setq node (treesit-search-forward node))) */
3223 */
3224 bool initial = true; 3338 bool initial = true;
3225 while (true) 3339 while (true)
3226 { 3340 {
@@ -3247,6 +3361,14 @@ treesit_search_forward (TSTreeCursor *cursor,
3247 } 3361 }
3248} 3362}
3249 3363
3364/* Clean up the given tree cursor CURSOR. */
3365
3366static void
3367treesit_traverse_cleanup_cursor (void *cursor)
3368{
3369 ts_tree_cursor_delete (cursor);
3370}
3371
3250DEFUN ("treesit-search-subtree", 3372DEFUN ("treesit-search-subtree",
3251 Ftreesit_search_subtree, 3373 Ftreesit_search_subtree,
3252 Streesit_search_subtree, 2, 5, 0, 3374 Streesit_search_subtree, 2, 5, 0,
@@ -3266,11 +3388,13 @@ Return the first matched node, or nil if none matches. */)
3266 Lisp_Object all, Lisp_Object depth) 3388 Lisp_Object all, Lisp_Object depth)
3267{ 3389{
3268 CHECK_TS_NODE (node); 3390 CHECK_TS_NODE (node);
3269 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate),
3270 list3 (Qor, Qstringp, Qfunctionp), predicate);
3271 CHECK_SYMBOL (all); 3391 CHECK_SYMBOL (all);
3272 CHECK_SYMBOL (backward); 3392 CHECK_SYMBOL (backward);
3273 3393
3394 Lisp_Object signal_data = Qnil;
3395 if (!treesit_traverse_validate_predicate (predicate, &signal_data))
3396 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3397
3274 /* We use a default limit of 1000. See bug#59426 for the 3398 /* We use a default limit of 1000. See bug#59426 for the
3275 discussion. */ 3399 discussion. */
3276 ptrdiff_t the_limit = treesit_recursion_limit; 3400 ptrdiff_t the_limit = treesit_recursion_limit;
@@ -3288,14 +3412,17 @@ Return the first matched node, or nil if none matches. */)
3288 if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser)) 3412 if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser))
3289 return return_value; 3413 return return_value;
3290 3414
3415 specpdl_ref count = SPECPDL_INDEX ();
3416 record_unwind_protect_ptr (treesit_traverse_cleanup_cursor, &cursor);
3417
3291 if (treesit_search_dfs (&cursor, predicate, parser, NILP (backward), 3418 if (treesit_search_dfs (&cursor, predicate, parser, NILP (backward),
3292 NILP (all), the_limit, false)) 3419 NILP (all), the_limit, false))
3293 { 3420 {
3294 TSNode node = ts_tree_cursor_current_node (&cursor); 3421 TSNode node = ts_tree_cursor_current_node (&cursor);
3295 return_value = make_treesit_node (parser, node); 3422 return_value = make_treesit_node (parser, node);
3296 } 3423 }
3297 ts_tree_cursor_delete (&cursor); 3424
3298 return return_value; 3425 return unbind_to (count, return_value);
3299} 3426}
3300 3427
3301DEFUN ("treesit-search-forward", 3428DEFUN ("treesit-search-forward",
@@ -3332,11 +3459,13 @@ always traverse leaf nodes first, then upwards. */)
3332 Lisp_Object all) 3459 Lisp_Object all)
3333{ 3460{
3334 CHECK_TS_NODE (start); 3461 CHECK_TS_NODE (start);
3335 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate),
3336 list3 (Qor, Qstringp, Qfunctionp), predicate);
3337 CHECK_SYMBOL (all); 3462 CHECK_SYMBOL (all);
3338 CHECK_SYMBOL (backward); 3463 CHECK_SYMBOL (backward);
3339 3464
3465 Lisp_Object signal_data = Qnil;
3466 if (!treesit_traverse_validate_predicate (predicate, &signal_data))
3467 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3468
3340 treesit_initialize (); 3469 treesit_initialize ();
3341 3470
3342 Lisp_Object parser = XTS_NODE (start)->parser; 3471 Lisp_Object parser = XTS_NODE (start)->parser;
@@ -3345,20 +3474,25 @@ always traverse leaf nodes first, then upwards. */)
3345 if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser)) 3474 if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser))
3346 return return_value; 3475 return return_value;
3347 3476
3477 specpdl_ref count = SPECPDL_INDEX ();
3478 record_unwind_protect_ptr (treesit_traverse_cleanup_cursor, &cursor);
3479
3348 if (treesit_search_forward (&cursor, predicate, parser, 3480 if (treesit_search_forward (&cursor, predicate, parser,
3349 NILP (backward), NILP (all))) 3481 NILP (backward), NILP (all)))
3350 { 3482 {
3351 TSNode node = ts_tree_cursor_current_node (&cursor); 3483 TSNode node = ts_tree_cursor_current_node (&cursor);
3352 return_value = make_treesit_node (parser, node); 3484 return_value = make_treesit_node (parser, node);
3353 } 3485 }
3354 ts_tree_cursor_delete (&cursor); 3486
3355 return return_value; 3487 return unbind_to (count, return_value);
3356} 3488}
3357 3489
3358/* Recursively traverse the tree under CURSOR, and append the result 3490/* Recursively traverse the tree under CURSOR, and append the result
3359 subtree to PARENT's cdr. See more in Ftreesit_induce_sparse_tree. 3491 subtree to PARENT's cdr. See more in Ftreesit_induce_sparse_tree.
3360 Note that the top-level children list is reversed, because 3492 Note that the top-level children list is reversed, because
3361 reasons. */ 3493 reasons.
3494
3495 This function may signal if the predicate function signals. */
3362static void 3496static void
3363treesit_build_sparse_tree (TSTreeCursor *cursor, Lisp_Object parent, 3497treesit_build_sparse_tree (TSTreeCursor *cursor, Lisp_Object parent,
3364 Lisp_Object pred, Lisp_Object process_fn, 3498 Lisp_Object pred, Lisp_Object process_fn,
@@ -3444,8 +3578,10 @@ a regexp. */)
3444 Lisp_Object depth) 3578 Lisp_Object depth)
3445{ 3579{
3446 CHECK_TS_NODE (root); 3580 CHECK_TS_NODE (root);
3447 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), 3581
3448 list3 (Qor, Qstringp, Qfunctionp), predicate); 3582 Lisp_Object signal_data = Qnil;
3583 if (!treesit_traverse_validate_predicate (predicate, &signal_data))
3584 xsignal1 (Qtreesit_invalid_predicate, signal_data);
3449 3585
3450 if (!NILP (process_fn)) 3586 if (!NILP (process_fn))
3451 CHECK_TYPE (FUNCTIONP (process_fn), Qfunctionp, process_fn); 3587 CHECK_TYPE (FUNCTIONP (process_fn), Qfunctionp, process_fn);
@@ -3467,10 +3603,16 @@ a regexp. */)
3467 to use treesit_cursor_helper. */ 3603 to use treesit_cursor_helper. */
3468 TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node); 3604 TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node);
3469 3605
3606 specpdl_ref count = SPECPDL_INDEX ();
3607 record_unwind_protect_ptr (treesit_traverse_cleanup_cursor, &cursor);
3608
3470 treesit_build_sparse_tree (&cursor, parent, predicate, process_fn, 3609 treesit_build_sparse_tree (&cursor, parent, predicate, process_fn,
3471 the_limit, parser); 3610 the_limit, parser);
3472 ts_tree_cursor_delete (&cursor); 3611
3612 unbind_to (count, Qnil);
3613
3473 Fsetcdr (parent, Fnreverse (Fcdr (parent))); 3614 Fsetcdr (parent, Fnreverse (Fcdr (parent)));
3615
3474 if (NILP (Fcdr (parent))) 3616 if (NILP (Fcdr (parent)))
3475 return Qnil; 3617 return Qnil;
3476 else 3618 else
@@ -3571,6 +3713,7 @@ syms_of_treesit (void)
3571 DEFSYM (Qoutdated, "outdated"); 3713 DEFSYM (Qoutdated, "outdated");
3572 DEFSYM (Qhas_error, "has-error"); 3714 DEFSYM (Qhas_error, "has-error");
3573 DEFSYM (Qlive, "live"); 3715 DEFSYM (Qlive, "live");
3716 DEFSYM (Qnot, "not");
3574 3717
3575 DEFSYM (QCanchor, ":anchor"); 3718 DEFSYM (QCanchor, ":anchor");
3576 DEFSYM (QCequal, ":equal"); 3719 DEFSYM (QCequal, ":equal");
@@ -3595,6 +3738,7 @@ syms_of_treesit (void)
3595 "user-emacs-directory"); 3738 "user-emacs-directory");
3596 DEFSYM (Qtreesit_parser_deleted, "treesit-parser-deleted"); 3739 DEFSYM (Qtreesit_parser_deleted, "treesit-parser-deleted");
3597 DEFSYM (Qtreesit_pattern_expand, "treesit-pattern-expand"); 3740 DEFSYM (Qtreesit_pattern_expand, "treesit-pattern-expand");
3741 DEFSYM (Qtreesit_invalid_predicate, "treesit-invalid-predicate");
3598 3742
3599 DEFSYM (Qor, "or"); 3743 DEFSYM (Qor, "or");
3600 3744
@@ -3622,6 +3766,9 @@ syms_of_treesit (void)
3622 define_error (Qtreesit_parser_deleted, 3766 define_error (Qtreesit_parser_deleted,
3623 "This parser is deleted and cannot be used", 3767 "This parser is deleted and cannot be used",
3624 Qtreesit_error); 3768 Qtreesit_error);
3769 define_error (Qtreesit_invalid_predicate,
3770 "Invalid predicate, see TODO for valid forms for a predicate",
3771 Qtreesit_error);
3625 3772
3626 DEFVAR_LISP ("treesit-load-name-override-list", 3773 DEFVAR_LISP ("treesit-load-name-override-list",
3627 Vtreesit_load_name_override_list, 3774 Vtreesit_load_name_override_list,