diff options
| author | Po Lu | 2023-03-26 14:09:56 +0800 |
|---|---|---|
| committer | Po Lu | 2023-03-26 14:09:56 +0800 |
| commit | a1c5461edabb8b4c336a708c84aa65e28b2695b0 (patch) | |
| tree | b278cdfc6920e565543f7f58e869ec960a096bb9 /src | |
| parent | c0873f2382f575b08b5c9eb6663d7a7acf7ece65 (diff) | |
| parent | a27b0f7f307ccf54fd5910a0655bd72b23e69fcf (diff) | |
| download | emacs-a1c5461edabb8b4c336a708c84aa65e28b2695b0.tar.gz emacs-a1c5461edabb8b4c336a708c84aa65e28b2695b0.zip | |
Merge remote-tracking branch 'origin/master' into feature/android
Diffstat (limited to 'src')
| -rw-r--r-- | src/treesit.c | 367 |
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 |
| 2412 | static 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. */ | ||
| 2414 | static bool | ||
| 2413 | treesit_predicate_capture_name_to_node (Lisp_Object name, | 2415 | treesit_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; |
| 2438 | static Lisp_Object | 2444 | otherwise set TEXT to Qnil and set SIGNAL_DATA to a suitable signal |
| 2445 | data. */ | ||
| 2446 | static bool | ||
| 2439 | treesit_predicate_capture_name_to_text (Lisp_Object name, | 2447 | treesit_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. */ | ||
| 2456 | static bool | 2469 | static bool |
| 2457 | treesit_predicate_equal (Lisp_Object args, struct capture_range captures) | 2470 | treesit_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. */ | ||
| 2482 | static bool | 2504 | static bool |
| 2483 | treesit_predicate_match (Lisp_Object args, struct capture_range captures) | 2505 | treesit_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. */ | ||
| 2548 | static bool | 2569 | static bool |
| 2549 | treesit_predicate_pred (Lisp_Object args, struct capture_range captures) | 2570 | treesit_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. */ | ||
| 2572 | static bool | 2601 | static bool |
| 2573 | treesit_eval_predicates (struct capture_range captures, Lisp_Object predicates) | 2602 | treesit_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. */ | ||
| 2679 | static 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. */ | ||
| 2719 | static bool | ||
| 2720 | treesit_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 | |||
| 2644 | DEFUN ("treesit-query-capture", | 2762 | DEFUN ("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 | ||