aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-03-26 14:09:56 +0800
committerPo Lu2023-03-26 14:09:56 +0800
commita1c5461edabb8b4c336a708c84aa65e28b2695b0 (patch)
treeb278cdfc6920e565543f7f58e869ec960a096bb9 /src
parentc0873f2382f575b08b5c9eb6663d7a7acf7ece65 (diff)
parenta27b0f7f307ccf54fd5910a0655bd72b23e69fcf (diff)
downloademacs-a1c5461edabb8b4c336a708c84aa65e28b2695b0.tar.gz
emacs-a1c5461edabb8b4c336a708c84aa65e28b2695b0.zip
Merge remote-tracking branch 'origin/master' into feature/android
Diffstat (limited to 'src')
-rw-r--r--src/treesit.c367
1 files changed, 229 insertions, 138 deletions
diff --git a/src/treesit.c b/src/treesit.c
index 5a4fe3e8803..36a297ec7da 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -2407,87 +2407,111 @@ treesit_predicates_for_pattern (TSQuery *query, uint32_t pattern_index)
2407 return Fnreverse (result); 2407 return Fnreverse (result);
2408} 2408}
2409 2409
2410/* Translate a capture NAME (symbol) to a node. 2410/* Translate a capture NAME (symbol) to a node. If everything goes
2411 Signals treesit-query-error if such node is not captured. */ 2411 fine, set NODE and return true; if error occurs (e.g., when there
2412static Lisp_Object 2412 is no node for the capture name), set NODE to Qnil, SIGNAL_DATA to
2413 a suitable signal data, and return false. */
2414static bool
2413treesit_predicate_capture_name_to_node (Lisp_Object name, 2415treesit_predicate_capture_name_to_node (Lisp_Object name,
2414 struct capture_range captures) 2416 struct capture_range captures,
2417 Lisp_Object *node,
2418 Lisp_Object *signal_data)
2415{ 2419{
2416 Lisp_Object node = Qnil; 2420 *node = Qnil;
2417 for (Lisp_Object tail = captures.start; !EQ (tail, captures.end); 2421 for (Lisp_Object tail = captures.start; !EQ (tail, captures.end);
2418 tail = XCDR (tail)) 2422 tail = XCDR (tail))
2419 { 2423 {
2420 if (EQ (XCAR (XCAR (tail)), name)) 2424 if (EQ (XCAR (XCAR (tail)), name))
2421 { 2425 {
2422 node = XCDR (XCAR (tail)); 2426 *node = XCDR (XCAR (tail));
2423 break; 2427 break;
2424 } 2428 }
2425 } 2429 }
2426 2430
2427 if (NILP (node)) 2431 if (NILP (*node))
2428 xsignal3 (Qtreesit_query_error, 2432 {
2429 build_string ("Cannot find captured node"), 2433 *signal_data = list3 (build_string ("Cannot find captured node"),
2430 name, build_string ("A predicate can only refer" 2434 name, build_string ("A predicate can only refer"
2431 " to captured nodes in the " 2435 " to captured nodes in the "
2432 "same pattern")); 2436 "same pattern"));
2433 return node; 2437 return false;
2438 }
2439 return true;
2434} 2440}
2435 2441
2436/* Translate a capture NAME (symbol) to the text of the captured node. 2442/* Translate a capture NAME (symbol) to the text of the captured node.
2437 Signals treesit-query-error if such node is not captured. */ 2443 If everything goes fine, set TEXT to the text and return true;
2438static Lisp_Object 2444 otherwise set TEXT to Qnil and set SIGNAL_DATA to a suitable signal
2445 data. */
2446static bool
2439treesit_predicate_capture_name_to_text (Lisp_Object name, 2447treesit_predicate_capture_name_to_text (Lisp_Object name,
2440 struct capture_range captures) 2448 struct capture_range captures,
2449 Lisp_Object *text,
2450 Lisp_Object *signal_data)
2441{ 2451{
2442 Lisp_Object node = treesit_predicate_capture_name_to_node (name, captures); 2452 Lisp_Object node = Qnil;
2453 if (!treesit_predicate_capture_name_to_node (name, captures, &node, signal_data))
2454 return false;
2443 2455
2444 struct buffer *old_buffer = current_buffer; 2456 struct buffer *old_buffer = current_buffer;
2445 set_buffer_internal (XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer)); 2457 set_buffer_internal (XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer));
2446 Lisp_Object text = Fbuffer_substring (Ftreesit_node_start (node), 2458 *text = Fbuffer_substring (Ftreesit_node_start (node),
2447 Ftreesit_node_end (node)); 2459 Ftreesit_node_end (node));
2448 set_buffer_internal (old_buffer); 2460 set_buffer_internal (old_buffer);
2449 return text; 2461 return true;
2450} 2462}
2451 2463
2452/* Handles predicate (#equal A B). Return true if A equals B; return 2464/* Handles predicate (#equal A B). Return true if A equals B; return
2453 false otherwise. A and B can be either string, or a capture name. 2465 false otherwise. A and B can be either string, or a capture name.
2454 The capture name evaluates to the text its captured node spans in 2466 The capture name evaluates to the text its captured node spans in
2455 the buffer. */ 2467 the buffer. If everything goes fine, don't touch SIGNAL_DATA; if
2468 error occurs, set it to a suitable signal data. */
2456static bool 2469static bool
2457treesit_predicate_equal (Lisp_Object args, struct capture_range captures) 2470treesit_predicate_equal (Lisp_Object args, struct capture_range captures,
2471 Lisp_Object *signal_data)
2458{ 2472{
2459 if (XFIXNUM (Flength (args)) != 2) 2473 if (XFIXNUM (Flength (args)) != 2)
2460 xsignal2 (Qtreesit_query_error, 2474 {
2461 build_string ("Predicate `equal' requires " 2475 *signal_data = list2 (build_string ("Predicate `equal' requires "
2462 "two arguments but only given"), 2476 "two arguments but only given"),
2463 Flength (args)); 2477 Flength (args));
2464 2478 return false;
2479 }
2465 Lisp_Object arg1 = XCAR (args); 2480 Lisp_Object arg1 = XCAR (args);
2466 Lisp_Object arg2 = XCAR (XCDR (args)); 2481 Lisp_Object arg2 = XCAR (XCDR (args));
2467 Lisp_Object text1 = (STRINGP (arg1) 2482 Lisp_Object text1 = arg1;
2468 ? arg1 2483 Lisp_Object text2 = arg2;
2469 : treesit_predicate_capture_name_to_text (arg1, 2484 if (SYMBOLP (arg1))
2470 captures)); 2485 {
2471 Lisp_Object text2 = (STRINGP (arg2) 2486 if (!treesit_predicate_capture_name_to_text (arg1, captures, &text1,
2472 ? arg2 2487 signal_data))
2473 : treesit_predicate_capture_name_to_text (arg2, 2488 return false;
2474 captures)); 2489 }
2490 if (SYMBOLP (arg2))
2491 {
2492 if (!treesit_predicate_capture_name_to_text (arg2, captures, &text2,
2493 signal_data))
2494 return false;
2495 }
2475 2496
2476 return !NILP (Fstring_equal (text1, text2)); 2497 return !NILP (Fstring_equal (text1, text2));
2477} 2498}
2478 2499
2479/* Handles predicate (#match "regexp" @node). Return true if "regexp" 2500/* Handles predicate (#match "regexp" @node). Return true if "regexp"
2480 matches the text spanned by @node; return false otherwise. Matching 2501 matches the text spanned by @node; return false otherwise.
2481 is case-sensitive. */ 2502 Matching is case-sensitive. If everything goes fine, don't touch
2503 SIGNAL_DATA; if error occurs, set it to a suitable signal data. */
2482static bool 2504static bool
2483treesit_predicate_match (Lisp_Object args, struct capture_range captures) 2505treesit_predicate_match (Lisp_Object args, struct capture_range captures,
2506 Lisp_Object *signal_data)
2484{ 2507{
2485 if (XFIXNUM (Flength (args)) != 2) 2508 if (XFIXNUM (Flength (args)) != 2)
2486 xsignal2 (Qtreesit_query_error, 2509 {
2487 build_string ("Predicate `match' requires two " 2510 *signal_data = list2 (build_string ("Predicate `match' requires two "
2488 "arguments but only given"), 2511 "arguments but only given"),
2489 Flength (args)); 2512 Flength (args));
2490 2513 return false;
2514 }
2491 Lisp_Object regexp = XCAR (args); 2515 Lisp_Object regexp = XCAR (args);
2492 Lisp_Object capture_name = XCAR (XCDR (args)); 2516 Lisp_Object capture_name = XCAR (XCDR (args));
2493 2517
@@ -2504,12 +2528,10 @@ treesit_predicate_match (Lisp_Object args, struct capture_range captures)
2504 build_string ("The second argument to `match' should " 2528 build_string ("The second argument to `match' should "
2505 "be a capture name, not a string")); 2529 "be a capture name, not a string"));
2506 2530
2507 Lisp_Object node = treesit_predicate_capture_name_to_node (capture_name, 2531 Lisp_Object node = Qnil;
2508 captures); 2532 if (!treesit_predicate_capture_name_to_node (capture_name, captures, &node,
2509 2533 signal_data))
2510 struct buffer *old_buffer = current_buffer; 2534 return false;
2511 struct buffer *buffer = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer);
2512 set_buffer_internal (buffer);
2513 2535
2514 TSNode treesit_node = XTS_NODE (node)->node; 2536 TSNode treesit_node = XTS_NODE (node)->node;
2515 ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; 2537 ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
@@ -2537,61 +2559,71 @@ treesit_predicate_match (Lisp_Object args, struct capture_range captures)
2537 ZV = old_zv; 2559 ZV = old_zv;
2538 ZV_BYTE = old_zv_byte; 2560 ZV_BYTE = old_zv_byte;
2539 2561
2540 set_buffer_internal (old_buffer);
2541
2542 return (val > 0); 2562 return (val > 0);
2543} 2563}
2544 2564
2545/* Handles predicate (#pred FN ARG...). Return true if FN returns 2565/* Handles predicate (#pred FN ARG...). Return true if FN returns
2546 non-nil; return false otherwise. The arity of FN must match the 2566 non-nil; return false otherwise. The arity of FN must match the
2547 number of ARGs */ 2567 number of ARGs. If everything goes fine, don't touch SIGNAL_DATA;
2568 if error occurs, set it to a suitable signal data. */
2548static bool 2569static bool
2549treesit_predicate_pred (Lisp_Object args, struct capture_range captures) 2570treesit_predicate_pred (Lisp_Object args, struct capture_range captures,
2571 Lisp_Object *signal_data)
2550{ 2572{
2551 if (XFIXNUM (Flength (args)) < 2) 2573 if (XFIXNUM (Flength (args)) < 2)
2552 xsignal2 (Qtreesit_query_error, 2574 {
2553 build_string ("Predicate `pred' requires " 2575 *signal_data = list2 (build_string ("Predicate `pred' requires "
2554 "at least two arguments, " 2576 "at least two arguments, "
2555 "but was only given"), 2577 "but was only given"),
2556 Flength (args)); 2578 Flength (args));
2579 return false;
2580 }
2557 2581
2558 Lisp_Object fn = Fintern (XCAR (args), Qnil); 2582 Lisp_Object fn = Fintern (XCAR (args), Qnil);
2559 Lisp_Object nodes = Qnil; 2583 Lisp_Object nodes = Qnil;
2560 Lisp_Object tail = XCDR (args); 2584 Lisp_Object tail = XCDR (args);
2561 FOR_EACH_TAIL (tail) 2585 FOR_EACH_TAIL (tail)
2562 nodes = Fcons (treesit_predicate_capture_name_to_node (XCAR (tail), 2586 {
2563 captures), 2587 Lisp_Object node = Qnil;
2564 nodes); 2588 if (!treesit_predicate_capture_name_to_node (XCAR (tail), captures, &node,
2589 signal_data))
2590 return false;
2591 nodes = Fcons (node, nodes);
2592 }
2565 nodes = Fnreverse (nodes); 2593 nodes = Fnreverse (nodes);
2566 2594
2567 return !NILP (CALLN (Fapply, fn, nodes)); 2595 return !NILP (CALLN (Fapply, fn, nodes));
2568} 2596}
2569 2597
2570/* If all predicates in PREDICATES passes, return true; otherwise 2598/* If all predicates in PREDICATES passes, return true; otherwise
2571 return false. */ 2599 return false. If everything goes fine, don't touch SIGNAL_DATA; if
2600 error occurs, set it to a suitable signal data. */
2572static bool 2601static bool
2573treesit_eval_predicates (struct capture_range captures, Lisp_Object predicates) 2602treesit_eval_predicates (struct capture_range captures, Lisp_Object predicates,
2603 Lisp_Object *signal_data)
2574{ 2604{
2575 bool pass = true; 2605 bool pass = true;
2576 /* Evaluate each predicates. */ 2606 /* Evaluate each predicates. */
2577 for (Lisp_Object tail = predicates; 2607 for (Lisp_Object tail = predicates;
2578 !NILP (tail); tail = XCDR (tail)) 2608 pass && !NILP (tail); tail = XCDR (tail))
2579 { 2609 {
2580 Lisp_Object predicate = XCAR (tail); 2610 Lisp_Object predicate = XCAR (tail);
2581 Lisp_Object fn = XCAR (predicate); 2611 Lisp_Object fn = XCAR (predicate);
2582 Lisp_Object args = XCDR (predicate); 2612 Lisp_Object args = XCDR (predicate);
2583 if (!NILP (Fstring_equal (fn, Vtreesit_str_equal))) 2613 if (!NILP (Fstring_equal (fn, Vtreesit_str_equal)))
2584 pass &= treesit_predicate_equal (args, captures); 2614 pass &= treesit_predicate_equal (args, captures, signal_data);
2585 else if (!NILP (Fstring_equal (fn, Vtreesit_str_match))) 2615 else if (!NILP (Fstring_equal (fn, Vtreesit_str_match)))
2586 pass &= treesit_predicate_match (args, captures); 2616 pass &= treesit_predicate_match (args, captures, signal_data);
2587 else if (!NILP (Fstring_equal (fn, Vtreesit_str_pred))) 2617 else if (!NILP (Fstring_equal (fn, Vtreesit_str_pred)))
2588 pass &= treesit_predicate_pred (args, captures); 2618 pass &= treesit_predicate_pred (args, captures, signal_data);
2589 else 2619 else
2590 xsignal3 (Qtreesit_query_error, 2620 {
2591 build_string ("Invalid predicate"), 2621 *signal_data = list3 (build_string ("Invalid predicate"),
2592 fn, build_string ("Currently Emacs only supports" 2622 fn, build_string ("Currently Emacs only supports"
2593 " equal, match, and pred" 2623 " equal, match, and pred"
2594 " predicate")); 2624 " predicates"));
2625 pass = false;
2626 }
2595 } 2627 }
2596 /* If all predicates passed, add captures to result list. */ 2628 /* If all predicates passed, add captures to result list. */
2597 return pass; 2629 return pass;
@@ -2631,8 +2663,8 @@ You can use `treesit-query-validate' to validate and debug a query. */)
2631 Lisp_Object signal_symbol = Qnil; 2663 Lisp_Object signal_symbol = Qnil;
2632 Lisp_Object signal_data = Qnil; 2664 Lisp_Object signal_data = Qnil;
2633 TSQuery *treesit_query = treesit_ensure_query_compiled (lisp_query, 2665 TSQuery *treesit_query = treesit_ensure_query_compiled (lisp_query,
2634 &signal_symbol, 2666 &signal_symbol,
2635 &signal_data); 2667 &signal_data);
2636 2668
2637 if (treesit_query == NULL) 2669 if (treesit_query == NULL)
2638 xsignal (signal_symbol, signal_data); 2670 xsignal (signal_symbol, signal_data);
@@ -2641,6 +2673,92 @@ You can use `treesit-query-validate' to validate and debug a query. */)
2641 } 2673 }
2642} 2674}
2643 2675
2676/* Resolve OBJ into a tree-sitter node Lisp_Object. OBJ can be a
2677 node, a parser, or a language symbol. Note that this function can
2678 signal. */
2679static Lisp_Object treesit_resolve_node (Lisp_Object obj)
2680{
2681 if (TS_NODEP (obj))
2682 {
2683 treesit_check_node (obj); /* Check if up-to-date. */
2684 return obj;
2685 }
2686 else if (TS_PARSERP (obj))
2687 {
2688 treesit_check_parser (obj); /* Check if deleted. */
2689 return Ftreesit_parser_root_node (obj);
2690 }
2691 else if (SYMBOLP (obj))
2692 {
2693 Lisp_Object parser
2694 = Ftreesit_parser_create (obj, Fcurrent_buffer (), Qnil);
2695 return Ftreesit_parser_root_node (parser);
2696 }
2697 else
2698 xsignal2 (Qwrong_type_argument,
2699 list4 (Qor, Qtreesit_node_p, Qtreesit_parser_p, Qsymbolp),
2700 obj);
2701}
2702
2703/* Create and initialize QUERY. When success, initialize TS_QUERY,
2704 CURSOR, and NEED_FREE, and return true; if failed, initialize
2705 SIGNAL_SYMBOL and SIGNAL_DATA, and return false. If NEED_FREE is
2706 initialized to true, the TS_QUERY and CURSOR needs to be freed
2707 after use; otherwise they shouldn't be freed by hand.
2708
2709 Basically this function looks at QUERY and check its type, if QUERY
2710 is a compiled query, this function takes out its query and cursor;
2711 if QUERY is a string or a cons, this function creates a new query
2712 and cursor (so they need to be manually freed).
2713
2714 This function assumes QUERY is either a compiled query, a string or
2715 a cons, the caller should make sure QUERY is valid.
2716
2717 LANG is the language to use if we need to create the query and
2718 cursor. */
2719static bool
2720treesit_initialize_query (Lisp_Object query, const TSLanguage *lang,
2721 TSQuery **ts_query, TSQueryCursor **cursor,
2722 bool *need_free, Lisp_Object *signal_symbol,
2723 Lisp_Object *signal_data)
2724{
2725 if (TS_COMPILED_QUERY_P (query))
2726 {
2727 *ts_query = treesit_ensure_query_compiled (query, signal_symbol,
2728 signal_data);
2729 *cursor = XTS_COMPILED_QUERY (query)->cursor;
2730 /* We don't need to free ts_query and cursor because they
2731 are stored in a lisp object, which is tracked by gc. */
2732 *need_free = false;
2733 return (*ts_query != NULL);
2734 }
2735 else
2736 {
2737 /* Since query is not TS_COMPILED_QUERY, it can only be a string
2738 or a cons. */
2739 if (CONSP (query))
2740 query = Ftreesit_query_expand (query);
2741 char *query_string = SSDATA (query);
2742 uint32_t error_offset;
2743 TSQueryError error_type;
2744 *ts_query = ts_query_new (lang, query_string, strlen (query_string),
2745 &error_offset, &error_type);
2746 if (*ts_query == NULL)
2747 {
2748 *signal_symbol = Qtreesit_query_error;
2749 *signal_data = treesit_compose_query_signal_data (error_offset,
2750 error_type, query);
2751 return false;
2752 }
2753 else
2754 {
2755 *cursor = ts_query_cursor_new ();
2756 *need_free = true;
2757 return true;
2758 }
2759 }
2760}
2761
2644DEFUN ("treesit-query-capture", 2762DEFUN ("treesit-query-capture",
2645 Ftreesit_query_capture, 2763 Ftreesit_query_capture,
2646 Streesit_query_capture, 2, 5, 0, 2764 Streesit_query_capture, 2, 5, 0,
@@ -2681,35 +2799,12 @@ the query. */)
2681 treesit_initialize (); 2799 treesit_initialize ();
2682 2800
2683 /* Resolve NODE into an actual node. */ 2801 /* Resolve NODE into an actual node. */
2684 Lisp_Object lisp_node; 2802 Lisp_Object lisp_node = treesit_resolve_node (node);
2685 if (TS_NODEP (node))
2686 {
2687 treesit_check_node (node); /* Check if up-to-date. */
2688 lisp_node = node;
2689 }
2690 else if (TS_PARSERP (node))
2691 {
2692 treesit_check_parser (node); /* Check if deleted. */
2693 lisp_node = Ftreesit_parser_root_node (node);
2694 }
2695 else if (SYMBOLP (node))
2696 {
2697 Lisp_Object parser
2698 = Ftreesit_parser_create (node, Fcurrent_buffer (), Qnil);
2699 lisp_node = Ftreesit_parser_root_node (parser);
2700 }
2701 else
2702 xsignal2 (Qwrong_type_argument,
2703 list4 (Qor, Qtreesit_node_p, Qtreesit_parser_p, Qsymbolp),
2704 node);
2705 2803
2706 /* Extract C values from Lisp objects. */ 2804 /* Extract C values from Lisp objects. */
2707 TSNode treesit_node 2805 TSNode treesit_node = XTS_NODE (lisp_node)->node;
2708 = XTS_NODE (lisp_node)->node; 2806 Lisp_Object lisp_parser = XTS_NODE (lisp_node)->parser;
2709 Lisp_Object lisp_parser 2807
2710 = XTS_NODE (lisp_node)->parser;
2711 ptrdiff_t visible_beg
2712 = XTS_PARSER (XTS_NODE (lisp_node)->parser)->visible_beg;
2713 const TSLanguage *lang 2808 const TSLanguage *lang
2714 = ts_parser_language (XTS_PARSER (lisp_parser)->parser); 2809 = ts_parser_language (XTS_PARSER (lisp_parser)->parser);
2715 2810
@@ -2725,44 +2820,21 @@ the query. */)
2725 TSQuery *treesit_query; 2820 TSQuery *treesit_query;
2726 TSQueryCursor *cursor; 2821 TSQueryCursor *cursor;
2727 bool needs_to_free_query_and_cursor; 2822 bool needs_to_free_query_and_cursor;
2728 if (TS_COMPILED_QUERY_P (query)) 2823 Lisp_Object signal_symbol;
2729 { 2824 Lisp_Object signal_data;
2730 Lisp_Object signal_symbol = Qnil; 2825 if (!treesit_initialize_query (query, lang, &treesit_query, &cursor,
2731 Lisp_Object signal_data = Qnil; 2826 &needs_to_free_query_and_cursor,
2732 treesit_query = treesit_ensure_query_compiled (query, &signal_symbol, 2827 &signal_symbol, &signal_data))
2733 &signal_data); 2828 xsignal (signal_symbol, signal_data);
2734 cursor = XTS_COMPILED_QUERY (query)->cursor;
2735 /* We don't need to free ts_query and cursor because they
2736 are stored in a lisp object, which is tracked by gc. */
2737 needs_to_free_query_and_cursor = false;
2738 if (treesit_query == NULL)
2739 xsignal (signal_symbol, signal_data);
2740 }
2741 else
2742 {
2743 /* Since query is not TS_COMPILED_QUERY, it can only be a string
2744 or a cons. */
2745 if (CONSP (query))
2746 query = Ftreesit_query_expand (query);
2747 char *query_string = SSDATA (query);
2748 uint32_t error_offset;
2749 TSQueryError error_type;
2750 treesit_query = ts_query_new (lang, query_string, strlen (query_string),
2751 &error_offset, &error_type);
2752 if (treesit_query == NULL)
2753 xsignal (Qtreesit_query_error,
2754 treesit_compose_query_signal_data (error_offset,
2755 error_type, query));
2756 cursor = ts_query_cursor_new ();
2757 needs_to_free_query_and_cursor = true;
2758 }
2759 2829
2760 /* WARN: After this point, free treesit_query and cursor before every 2830 /* WARN: After this point, free TREESIT_QUERY and CURSOR before every
2761 signal and return. */ 2831 signal and return if NEEDS_TO_FREE_QUERY_AND_CURSOR is true. */
2762 2832
2763 /* Set query range. */ 2833 /* Set query range. */
2764 if (!NILP (beg) && !NILP (end)) 2834 if (!NILP (beg) && !NILP (end))
2765 { 2835 {
2836 ptrdiff_t visible_beg
2837 = XTS_PARSER (XTS_NODE (lisp_node)->parser)->visible_beg;
2766 ptrdiff_t beg_byte = CHAR_TO_BYTE (XFIXNUM (beg)); 2838 ptrdiff_t beg_byte = CHAR_TO_BYTE (XFIXNUM (beg));
2767 ptrdiff_t end_byte = CHAR_TO_BYTE (XFIXNUM (end)); 2839 ptrdiff_t end_byte = CHAR_TO_BYTE (XFIXNUM (end));
2768 /* We never let tree-sitter run on buffers too large, so these 2840 /* We never let tree-sitter run on buffers too large, so these
@@ -2791,11 +2863,16 @@ the query. */)
2791 Lisp_Object result = Qnil; 2863 Lisp_Object result = Qnil;
2792 Lisp_Object prev_result = result; 2864 Lisp_Object prev_result = result;
2793 Lisp_Object predicates_table = make_vector (patterns_count, Qt); 2865 Lisp_Object predicates_table = make_vector (patterns_count, Qt);
2866 Lisp_Object predicate_signal_data = Qnil;
2867
2868 struct buffer *old_buf = current_buffer;
2869 set_buffer_internal (buf);
2870
2794 while (ts_query_cursor_next_match (cursor, &match)) 2871 while (ts_query_cursor_next_match (cursor, &match))
2795 { 2872 {
2796 /* Record the checkpoint that we may roll back to. */ 2873 /* Record the checkpoint that we may roll back to. */
2797 prev_result = result; 2874 prev_result = result;
2798 /* Get captured nodes. */ 2875 /* 1. Get captured nodes. */
2799 const TSQueryCapture *captures = match.captures; 2876 const TSQueryCapture *captures = match.captures;
2800 for (int idx = 0; idx < match.capture_count; idx++) 2877 for (int idx = 0; idx < match.capture_count; idx++)
2801 { 2878 {
@@ -2818,7 +2895,8 @@ the query. */)
2818 2895
2819 result = Fcons (cap, result); 2896 result = Fcons (cap, result);
2820 } 2897 }
2821 /* Get predicates. */ 2898 /* 2. Get predicates and check whether this match can be
2899 included in the result list. */
2822 Lisp_Object predicates = AREF (predicates_table, match.pattern_index); 2900 Lisp_Object predicates = AREF (predicates_table, match.pattern_index);
2823 if (EQ (predicates, Qt)) 2901 if (EQ (predicates, Qt))
2824 { 2902 {
@@ -2829,15 +2907,28 @@ the query. */)
2829 2907
2830 /* captures_lisp = Fnreverse (captures_lisp); */ 2908 /* captures_lisp = Fnreverse (captures_lisp); */
2831 struct capture_range captures_range = { result, prev_result }; 2909 struct capture_range captures_range = { result, prev_result };
2832 if (!treesit_eval_predicates (captures_range, predicates)) 2910 bool match = treesit_eval_predicates (captures_range, predicates,
2833 /* Predicates didn't pass, roll back. */ 2911 &predicate_signal_data);
2912 if (!NILP (predicate_signal_data))
2913 break;
2914
2915 /* Predicates didn't pass, roll back. */
2916 if (!match)
2834 result = prev_result; 2917 result = prev_result;
2835 } 2918 }
2919
2920 /* Final clean up. */
2836 if (needs_to_free_query_and_cursor) 2921 if (needs_to_free_query_and_cursor)
2837 { 2922 {
2838 ts_query_delete (treesit_query); 2923 ts_query_delete (treesit_query);
2839 ts_query_cursor_delete (cursor); 2924 ts_query_cursor_delete (cursor);
2840 } 2925 }
2926 set_buffer_internal (old_buf);
2927
2928 /* Some capture predicate signaled an error. */
2929 if (!NILP (predicate_signal_data))
2930 xsignal (Qtreesit_query_error, predicate_signal_data);
2931
2841 return Fnreverse (result); 2932 return Fnreverse (result);
2842} 2933}
2843 2934