diff options
| author | Yuan Fu | 2023-03-21 16:03:08 -0700 |
|---|---|---|
| committer | Yuan Fu | 2023-03-24 12:29:33 -0700 |
| commit | c3a25bfb75c1cd41a1d2c613ec944a490cf8aff7 (patch) | |
| tree | d42358aeb1be9469c8f10749044fe36f4c86300a | |
| parent | 4a2dccd6a68625914ae6fa4b0bbb002f5ea079db (diff) | |
| download | emacs-c3a25bfb75c1cd41a1d2c613ec944a490cf8aff7.tar.gz emacs-c3a25bfb75c1cd41a1d2c613ec944a490cf8aff7.zip | |
Refactor Ftreesit_query_capture
Refactor some part of Ftreesit_query_capture out into separate
functions, to pave the way for other query-based functions.
* src/treesit.c (treesit_resolve_node): New function.
(treesit_initialize_query): New function.
(Ftreesit_query_capture): Refactor some part into new functions.
| -rw-r--r-- | src/treesit.c | 153 |
1 files changed, 97 insertions, 56 deletions
diff --git a/src/treesit.c b/src/treesit.c index 5a4fe3e8803..e728d697c9d 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -2631,8 +2631,8 @@ You can use `treesit-query-validate' to validate and debug a query. */) | |||
| 2631 | Lisp_Object signal_symbol = Qnil; | 2631 | Lisp_Object signal_symbol = Qnil; |
| 2632 | Lisp_Object signal_data = Qnil; | 2632 | Lisp_Object signal_data = Qnil; |
| 2633 | TSQuery *treesit_query = treesit_ensure_query_compiled (lisp_query, | 2633 | TSQuery *treesit_query = treesit_ensure_query_compiled (lisp_query, |
| 2634 | &signal_symbol, | 2634 | &signal_symbol, |
| 2635 | &signal_data); | 2635 | &signal_data); |
| 2636 | 2636 | ||
| 2637 | if (treesit_query == NULL) | 2637 | if (treesit_query == NULL) |
| 2638 | xsignal (signal_symbol, signal_data); | 2638 | xsignal (signal_symbol, signal_data); |
| @@ -2641,6 +2641,92 @@ You can use `treesit-query-validate' to validate and debug a query. */) | |||
| 2641 | } | 2641 | } |
| 2642 | } | 2642 | } |
| 2643 | 2643 | ||
| 2644 | /* Resolve OBJ into a tree-sitter node Lisp_Object. OBJ can be a | ||
| 2645 | node, a parser, or a language symbol. Note that this function can | ||
| 2646 | signal. */ | ||
| 2647 | static Lisp_Object treesit_resolve_node (Lisp_Object obj) | ||
| 2648 | { | ||
| 2649 | if (TS_NODEP (obj)) | ||
| 2650 | { | ||
| 2651 | treesit_check_node (obj); /* Check if up-to-date. */ | ||
| 2652 | return obj; | ||
| 2653 | } | ||
| 2654 | else if (TS_PARSERP (obj)) | ||
| 2655 | { | ||
| 2656 | treesit_check_parser (obj); /* Check if deleted. */ | ||
| 2657 | return Ftreesit_parser_root_node (obj); | ||
| 2658 | } | ||
| 2659 | else if (SYMBOLP (obj)) | ||
| 2660 | { | ||
| 2661 | Lisp_Object parser | ||
| 2662 | = Ftreesit_parser_create (obj, Fcurrent_buffer (), Qnil); | ||
| 2663 | return Ftreesit_parser_root_node (parser); | ||
| 2664 | } | ||
| 2665 | else | ||
| 2666 | xsignal2 (Qwrong_type_argument, | ||
| 2667 | list4 (Qor, Qtreesit_node_p, Qtreesit_parser_p, Qsymbolp), | ||
| 2668 | obj); | ||
| 2669 | } | ||
| 2670 | |||
| 2671 | /* Create and initialize QUERY. When success, initialize TS_QUERY, | ||
| 2672 | CURSOR, and NEED_FREE, and return true; if failed, initialize | ||
| 2673 | SIGNAL_SYMBOL and SIGNAL_DATA, and return false. If NEED_FREE is | ||
| 2674 | initialized to true, the TS_QUERY and CURSOR needs to be freed | ||
| 2675 | after use; otherwise they shouldn't be freed by hand. | ||
| 2676 | |||
| 2677 | Basically this function looks at QUERY and check its type, if QUERY | ||
| 2678 | is a compiled query, this function takes out its query and cursor; | ||
| 2679 | if QUERY is a string or a cons, this function creates a new query | ||
| 2680 | and cursor (so they need to be manually freed). | ||
| 2681 | |||
| 2682 | This function assumes QUERY is either a compiled query, a string or | ||
| 2683 | a cons, the caller should make sure QUERY is valid. | ||
| 2684 | |||
| 2685 | LANG is the language to use if we need to create the query and | ||
| 2686 | cursor. */ | ||
| 2687 | static bool | ||
| 2688 | treesit_initialize_query (Lisp_Object query, const TSLanguage *lang, | ||
| 2689 | TSQuery **ts_query, TSQueryCursor **cursor, | ||
| 2690 | bool *need_free, Lisp_Object *signal_symbol, | ||
| 2691 | Lisp_Object *signal_data) | ||
| 2692 | { | ||
| 2693 | if (TS_COMPILED_QUERY_P (query)) | ||
| 2694 | { | ||
| 2695 | *ts_query = treesit_ensure_query_compiled (query, signal_symbol, | ||
| 2696 | signal_data); | ||
| 2697 | *cursor = XTS_COMPILED_QUERY (query)->cursor; | ||
| 2698 | /* We don't need to free ts_query and cursor because they | ||
| 2699 | are stored in a lisp object, which is tracked by gc. */ | ||
| 2700 | *need_free = false; | ||
| 2701 | return (*ts_query != NULL); | ||
| 2702 | } | ||
| 2703 | else | ||
| 2704 | { | ||
| 2705 | /* Since query is not TS_COMPILED_QUERY, it can only be a string | ||
| 2706 | or a cons. */ | ||
| 2707 | if (CONSP (query)) | ||
| 2708 | query = Ftreesit_query_expand (query); | ||
| 2709 | char *query_string = SSDATA (query); | ||
| 2710 | uint32_t error_offset; | ||
| 2711 | TSQueryError error_type; | ||
| 2712 | *ts_query = ts_query_new (lang, query_string, strlen (query_string), | ||
| 2713 | &error_offset, &error_type); | ||
| 2714 | if (*ts_query == NULL) | ||
| 2715 | { | ||
| 2716 | *signal_symbol = Qtreesit_query_error; | ||
| 2717 | *signal_data = treesit_compose_query_signal_data (error_offset, | ||
| 2718 | error_type, query); | ||
| 2719 | return false; | ||
| 2720 | } | ||
| 2721 | else | ||
| 2722 | { | ||
| 2723 | *cursor = ts_query_cursor_new (); | ||
| 2724 | *need_free = true; | ||
| 2725 | return true; | ||
| 2726 | } | ||
| 2727 | } | ||
| 2728 | } | ||
| 2729 | |||
| 2644 | DEFUN ("treesit-query-capture", | 2730 | DEFUN ("treesit-query-capture", |
| 2645 | Ftreesit_query_capture, | 2731 | Ftreesit_query_capture, |
| 2646 | Streesit_query_capture, 2, 5, 0, | 2732 | Streesit_query_capture, 2, 5, 0, |
| @@ -2681,27 +2767,7 @@ the query. */) | |||
| 2681 | treesit_initialize (); | 2767 | treesit_initialize (); |
| 2682 | 2768 | ||
| 2683 | /* Resolve NODE into an actual node. */ | 2769 | /* Resolve NODE into an actual node. */ |
| 2684 | Lisp_Object lisp_node; | 2770 | 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 | 2771 | ||
| 2706 | /* Extract C values from Lisp objects. */ | 2772 | /* Extract C values from Lisp objects. */ |
| 2707 | TSNode treesit_node | 2773 | TSNode treesit_node |
| @@ -2725,40 +2791,15 @@ the query. */) | |||
| 2725 | TSQuery *treesit_query; | 2791 | TSQuery *treesit_query; |
| 2726 | TSQueryCursor *cursor; | 2792 | TSQueryCursor *cursor; |
| 2727 | bool needs_to_free_query_and_cursor; | 2793 | bool needs_to_free_query_and_cursor; |
| 2728 | if (TS_COMPILED_QUERY_P (query)) | 2794 | Lisp_Object signal_symbol; |
| 2729 | { | 2795 | Lisp_Object signal_data; |
| 2730 | Lisp_Object signal_symbol = Qnil; | 2796 | if (!treesit_initialize_query (query, lang, &treesit_query, &cursor, |
| 2731 | Lisp_Object signal_data = Qnil; | 2797 | &needs_to_free_query_and_cursor, |
| 2732 | treesit_query = treesit_ensure_query_compiled (query, &signal_symbol, | 2798 | &signal_symbol, &signal_data)) |
| 2733 | &signal_data); | 2799 | 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 | 2800 | ||
| 2760 | /* WARN: After this point, free treesit_query and cursor before every | 2801 | /* WARN: After this point, free TREESIT_QUERY and CURSOR before every |
| 2761 | signal and return. */ | 2802 | signal and return if NEEDS_TO_FREE_QUERY_AND_CURSOR is true. */ |
| 2762 | 2803 | ||
| 2763 | /* Set query range. */ | 2804 | /* Set query range. */ |
| 2764 | if (!NILP (beg) && !NILP (end)) | 2805 | if (!NILP (beg) && !NILP (end)) |