From: Eli Zaretskii Date: Sun, 16 Oct 2022 13:22:09 +0000 (+0300) Subject: Support MinGW build on MS-Windows X-Git-Tag: emacs-29.0.90~1829 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=9d3f8912b431ed5540d9d06d85b7e338732268c9;p=emacs.git Support MinGW build on MS-Windows * src/treesit.c [WINDOWSNT]: Add MS-Windows boilerplate for dynamically-loaded optional libraries. (init_treesit_functions) [WINDOWSNT]: New function. (load_tree_sitter_if_necessary): New function. (ts_initialize): Call 'load_tree_sitter_if_necessary'. (ts_delete_parser, ts_delete_query, ts_named_node_p): Wrapper functions for TS calls from outside treesit.c. (Ftreesit_parser_root_node, Ftreesit_parser_set_included_ranges) (Ftreesit_parser_included_ranges, Ftreesit_node_type) (Ftreesit_node_start, Ftreesit_node_end, Ftreesit_node_string) (Ftreesit_node_parent, Ftreesit_node_child, Ftreesit_node_check) (Ftreesit_node_field_name_for_child, Ftreesit_node_child_count) (Ftreesit_node_next_sibling, Ftreesit_node_prev_sibling) (Ftreesit_node_first_child_for_pos) (Ftreesit_node_descendant_for_range, Ftreesit_node_eq) (Ftreesit_query_compile, Ftreesit_query_capture) (Ftreesit_search_subtree, Ftreesit_search_forward) (Ftreesit_induce_sparse_tree): Call 'ts_initialize' before any other TS functions. (Ftreesit_available_p): 'treesit-available-p' implemented in C, so that on WINDOWSNT the library could be loaded dynamically. * src/treesit.h (ts_delete_parser, ts_delete_query) (ts_named_node_p): Add prototypes. * src/print.c (print_vectorlike): * src/alloc.c (cleanup_vector): Call tree-sitter function via wrappers defined in treesit.c, not directly, because WINDOWSNT redefines the TS functions to be called via function pointers. * src/Makefile.in (base_obj): Add treesit.o (TREE_SITTER_OBJ): Remove. * lisp/treesit.el (treesit-available-p): Remove: now implemented in C. * lisp/term/w32-win.el (dynamic-library-alist): Add libtree-sitter DLLs. * configure.ac (TREE_SITTER): Support the MinGW build. (TREE_SITTER_OBJ): Remove. --- diff --git a/configure.ac b/configure.ac index 7d751fd6a81..4ce7e8b8ce9 100644 --- a/configure.ac +++ b/configure.ac @@ -3223,13 +3223,16 @@ if test "${with_tree_sitter}" != "no"; then [HAVE_TREE_SITTER=yes], [HAVE_TREE_SITTER=no]) if test "${HAVE_TREE_SITTER}" = yes; then AC_DEFINE(HAVE_TREE_SITTER, 1, [Define if using tree-sitter.]) - TREE_SITTER_OBJ="treesit.o" + fi + + # Windows loads tree-sitter dynamically + if test "${opsys}" = "mingw32"; then + TREE_SITTER_LIBS= fi fi AC_SUBST(TREE_SITTER_LIBS) AC_SUBST(TREE_SITTER_CFLAGS) -AC_SUBST(TREE_SITTER_OBJ) NOTIFY_OBJ= NOTIFY_SUMMARY=no diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index 993f1d43208..34f899ecaaa 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -287,7 +287,10 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.") '(zlib "zlib1.dll" "libz-1.dll") '(lcms2 "liblcms2-2.dll") '(json "libjansson-4.dll") - '(gccjit "libgccjit-0.dll"))) + '(gccjit "libgccjit-0.dll") + ;; MSYS2 distributes libtree-sitter.dll, without API version + ;; number... + '(tree-sitter "libtree-sitter.dll" "libtree-sitter-0.dll"))) ;;; multi-tty support (defvar w32-initialized nil diff --git a/lisp/treesit.el b/lisp/treesit.el index c8ba3e84e62..004e79b40ea 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -45,9 +45,7 @@ :type 'integer :version "29.1") -(defun treesit-available-p () - "Return non-nil if tree-sitter features are available." - (fboundp 'treesit-parser-create)) +(declare-function treesit-available-p "treesit.c") (defun treesit-can-enable-p () "Return non-nil if current buffer can activate tree-sitter. diff --git a/src/Makefile.in b/src/Makefile.in index 0d27f3e6db0..4ee2843287d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -345,7 +345,6 @@ JSON_OBJ = @JSON_OBJ@ TREE_SITTER_LIBS = @TREE_SITTER_LIBS@ TREE_SITTER_CFLAGS = @TREE_SITTER_CFLAGS@ -TREE_SITTER_OBJ = @TREE_SITTER_OBJ@ INTERVALS_H = dispextern.h intervals.h composite.h @@ -445,11 +444,11 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ doprnt.o intervals.o textprop.o composite.o xml.o lcms.o $(NOTIFY_OBJ) \ $(XWIDGETS_OBJ) \ profiler.o decompress.o \ - thread.o systhread.o sqlite.o \ + thread.o systhread.o sqlite.o treesit.o \ $(if $(HYBRID_MALLOC),sheap.o) \ $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \ - $(TREE_SITTER_OBJ) $(HAIKU_OBJ) $(PGTK_OBJ) + $(HAIKU_OBJ) $(PGTK_OBJ) doc_obj = $(base_obj) $(NS_OBJC_OBJ) obj = $(doc_obj) $(HAIKU_CXX_OBJ) diff --git a/src/alloc.c b/src/alloc.c index a8b57add60e..7197c183beb 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -3171,19 +3171,9 @@ cleanup_vector (struct Lisp_Vector *vector) } #ifdef HAVE_TREE_SITTER else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_TS_PARSER)) - { - struct Lisp_TS_Parser *lisp_parser - = PSEUDOVEC_STRUCT (vector, Lisp_TS_Parser); - ts_tree_delete(lisp_parser->tree); - ts_parser_delete(lisp_parser->parser); - } + ts_delete_parser (PSEUDOVEC_STRUCT (vector, Lisp_TS_Parser)); else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_TS_COMPILED_QUERY)) - { - struct Lisp_TS_Query *lisp_query - = PSEUDOVEC_STRUCT (vector, Lisp_TS_Query); - ts_query_delete (lisp_query->query); - ts_query_cursor_delete (lisp_query->cursor); - } + ts_delete_query (PSEUDOVEC_STRUCT (vector, Lisp_TS_Query)); #endif #ifdef HAVE_MODULES else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_MODULE_FUNCTION)) diff --git a/src/print.c b/src/print.c index 4f41448d861..a9afe1dd2b6 100644 --- a/src/print.c +++ b/src/print.c @@ -2027,7 +2027,7 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, /* Prints #> or #>. */ print_c_string ("#node); + bool named = ts_named_node_p (XTS_NODE (obj)->node); const char *delim1 = named ? "(" : "\""; const char *delim2 = named ? ")" : "\""; print_c_string (delim1, printcharfun); diff --git a/src/treesit.c b/src/treesit.c index 7cfcc715f9b..b21019c56e3 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -20,8 +20,261 @@ along with GNU Emacs. If not, see . */ #include #include "lisp.h" #include "buffer.h" + +#if HAVE_TREE_SITTER + #include "treesit.h" + +/* Dynamic loading of libtree-sitter. */ + +#ifdef WINDOWSNT +# include "w32common.h" + +/* In alphabetical order. */ +#undef ts_language_version +#undef ts_node_child +#undef ts_node_child_by_field_name +#undef ts_node_child_count +#undef ts_node_descendant_for_byte_range +#undef ts_node_end_byte +#undef ts_node_eq +#undef ts_node_field_name_for_child +#undef ts_node_first_child_for_byte +#undef ts_node_first_named_child_for_byte +#undef ts_node_has_changes +#undef ts_node_has_error +#undef ts_node_is_extra +#undef ts_node_is_missing +#undef ts_node_is_named +#undef ts_node_is_null +#undef ts_node_named_child +#undef ts_node_named_child_count +#undef ts_node_named_descendant_for_byte_range +#undef ts_node_next_named_sibling +#undef ts_node_next_sibling +#undef ts_node_parent +#undef ts_node_prev_named_sibling +#undef ts_node_prev_sibling +#undef ts_node_start_byte +#undef ts_node_string +#undef ts_node_type +#undef ts_parser_delete +#undef ts_parser_included_ranges +#undef ts_parser_language +#undef ts_parser_new +#undef ts_parser_parse +#undef ts_parser_set_included_ranges +#undef ts_parser_set_language +#undef ts_query_capture_name_for_id +#undef ts_query_cursor_delete +#undef ts_query_cursor_exec +#undef ts_query_cursor_new +#undef ts_query_cursor_next_match +#undef ts_query_cursor_set_byte_range +#undef ts_query_delete +#undef ts_query_new +#undef ts_query_predicates_for_pattern +#undef ts_query_string_value_for_id +#undef ts_set_allocator +#undef ts_tree_cursor_current_node +#undef ts_tree_cursor_goto_first_child +#undef ts_tree_cursor_goto_next_sibling +#undef ts_tree_cursor_goto_parent +#undef ts_tree_cursor_new +#undef ts_tree_delete +#undef ts_tree_edit +#undef ts_tree_root_node + +DEF_DLL_FN (uint32_t, ts_language_version, (const TSLanguage *)); +DEF_DLL_FN (TSNode, ts_node_child, (TSNode, uint32_t)); +DEF_DLL_FN (TSNode, ts_node_child_by_field_name, + (TSNode, const char *, uint32_t)); +DEF_DLL_FN (uint32_t, ts_node_child_count, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_descendant_for_byte_range, + (TSNode, uint32_t, uint32_t)); +DEF_DLL_FN (uint32_t, ts_node_end_byte, (TSNode)); +DEF_DLL_FN (bool, ts_node_eq, (TSNode, TSNode)); +DEF_DLL_FN (const char *, ts_node_field_name_for_child, (TSNode, uint32_t)); +DEF_DLL_FN (TSNode, ts_node_first_child_for_byte, (TSNode, uint32_t)); +DEF_DLL_FN (TSNode, ts_node_first_named_child_for_byte, (TSNode, uint32_t)); +DEF_DLL_FN (bool, ts_node_has_changes, (TSNode)); +DEF_DLL_FN (bool, ts_node_has_error, (TSNode)); +DEF_DLL_FN (bool, ts_node_is_extra, (TSNode)); +DEF_DLL_FN (bool, ts_node_is_missing, (TSNode)); +DEF_DLL_FN (bool, ts_node_is_named, (TSNode)); +DEF_DLL_FN (bool, ts_node_is_null, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_named_child, (TSNode, uint32_t)); +DEF_DLL_FN (uint32_t, ts_node_named_child_count, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_named_descendant_for_byte_range, + (TSNode, uint32_t, uint32_t)); +DEF_DLL_FN (TSNode, ts_node_next_named_sibling, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_next_sibling, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_parent, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_prev_named_sibling, (TSNode)); +DEF_DLL_FN (TSNode, ts_node_prev_sibling, (TSNode)); +DEF_DLL_FN (uint32_t, ts_node_start_byte, (TSNode)); +DEF_DLL_FN (char *, ts_node_string, (TSNode)); +DEF_DLL_FN (const char *, ts_node_type, (TSNode)); +DEF_DLL_FN (void, ts_parser_delete, (TSParser *)); +DEF_DLL_FN (const TSRange *, ts_parser_included_ranges, + (const TSParser *, uint32_t *)); +DEF_DLL_FN (const TSLanguage *, ts_parser_language, (const TSParser *)); +DEF_DLL_FN (TSParser *, ts_parser_new, (void)); +DEF_DLL_FN (TSTree *, ts_parser_parse, (TSParser *, const TSTree *, TSInput)); +DEF_DLL_FN (bool, ts_parser_set_included_ranges, + (TSParser *, const TSRange *, uint32_t)); +DEF_DLL_FN (bool, ts_parser_set_language, (TSParser *, const TSLanguage *)); +DEF_DLL_FN (const char *, ts_query_capture_name_for_id, + (const TSQuery *, uint32_t, uint32_t *)); +DEF_DLL_FN (void, ts_query_cursor_delete, (TSQueryCursor *)); +DEF_DLL_FN (void, ts_query_cursor_exec, + (TSQueryCursor *, const TSQuery *, TSNode)); +DEF_DLL_FN (TSQueryCursor *, ts_query_cursor_new, (void)); +DEF_DLL_FN (bool, ts_query_cursor_next_match, + (TSQueryCursor *, TSQueryMatch *)); +DEF_DLL_FN (void, ts_query_cursor_set_byte_range, + (TSQueryCursor *, uint32_t, uint32_t)); +DEF_DLL_FN (void, ts_query_delete, (TSQuery *)); +DEF_DLL_FN (TSQuery *, ts_query_new, + (const TSLanguage *, const char *, uint32_t, uint32_t *, TSQueryError *)); +DEF_DLL_FN (const TSQueryPredicateStep *, ts_query_predicates_for_pattern, + ( const TSQuery *, uint32_t, uint32_t *)); +DEF_DLL_FN (const char *, ts_query_string_value_for_id, + (const TSQuery *, uint32_t, uint32_t *)); +DEF_DLL_FN (void, ts_set_allocator, + (void *(*)(size_t), void *(*)(size_t, size_t), void *(*)(void *, size_t), void (*)(void *))); +DEF_DLL_FN (TSNode, ts_tree_cursor_current_node, (const TSTreeCursor *)); +DEF_DLL_FN (bool, ts_tree_cursor_goto_first_child, (TSTreeCursor *)); +DEF_DLL_FN (bool, ts_tree_cursor_goto_next_sibling, (TSTreeCursor *)); +DEF_DLL_FN (bool, ts_tree_cursor_goto_parent, (TSTreeCursor *)); +DEF_DLL_FN (TSTreeCursor, ts_tree_cursor_new, (TSNode)); +DEF_DLL_FN (void, ts_tree_delete, (TSTree *)); +DEF_DLL_FN (void, ts_tree_edit, (TSTree *, const TSInputEdit *)); +DEF_DLL_FN (TSNode, ts_tree_root_node, (const TSTree *)); + +static bool +init_treesit_functions (void) +{ + HMODULE library = w32_delayed_load (Qtree_sitter); + + if (!library) + return false; + + LOAD_DLL_FN (library, ts_language_version); + LOAD_DLL_FN (library, ts_node_child); + LOAD_DLL_FN (library, ts_node_child_by_field_name); + LOAD_DLL_FN (library, ts_node_child_count); + LOAD_DLL_FN (library, ts_node_descendant_for_byte_range); + LOAD_DLL_FN (library, ts_node_end_byte); + LOAD_DLL_FN (library, ts_node_eq); + LOAD_DLL_FN (library, ts_node_field_name_for_child); + LOAD_DLL_FN (library, ts_node_first_child_for_byte); + LOAD_DLL_FN (library, ts_node_first_named_child_for_byte); + LOAD_DLL_FN (library, ts_node_has_changes); + LOAD_DLL_FN (library, ts_node_has_error); + LOAD_DLL_FN (library, ts_node_is_extra); + LOAD_DLL_FN (library, ts_node_is_missing); + LOAD_DLL_FN (library, ts_node_is_named); + LOAD_DLL_FN (library, ts_node_is_null); + LOAD_DLL_FN (library, ts_node_named_child); + LOAD_DLL_FN (library, ts_node_named_child_count); + LOAD_DLL_FN (library, ts_node_named_descendant_for_byte_range); + LOAD_DLL_FN (library, ts_node_next_named_sibling); + LOAD_DLL_FN (library, ts_node_next_sibling); + LOAD_DLL_FN (library, ts_node_parent); + LOAD_DLL_FN (library, ts_node_prev_named_sibling); + LOAD_DLL_FN (library, ts_node_prev_sibling); + LOAD_DLL_FN (library, ts_node_start_byte); + LOAD_DLL_FN (library, ts_node_string); + LOAD_DLL_FN (library, ts_node_type); + LOAD_DLL_FN (library, ts_parser_delete); + LOAD_DLL_FN (library, ts_parser_included_ranges); + LOAD_DLL_FN (library, ts_parser_language); + LOAD_DLL_FN (library, ts_parser_new); + LOAD_DLL_FN (library, ts_parser_parse); + LOAD_DLL_FN (library, ts_parser_set_included_ranges); + LOAD_DLL_FN (library, ts_parser_set_language); + LOAD_DLL_FN (library, ts_query_capture_name_for_id); + LOAD_DLL_FN (library, ts_query_cursor_delete); + LOAD_DLL_FN (library, ts_query_cursor_exec); + LOAD_DLL_FN (library, ts_query_cursor_new); + LOAD_DLL_FN (library, ts_query_cursor_next_match); + LOAD_DLL_FN (library, ts_query_cursor_set_byte_range); + LOAD_DLL_FN (library, ts_query_delete); + LOAD_DLL_FN (library, ts_query_new); + LOAD_DLL_FN (library, ts_query_predicates_for_pattern); + LOAD_DLL_FN (library, ts_query_string_value_for_id); + LOAD_DLL_FN (library, ts_set_allocator); + LOAD_DLL_FN (library, ts_tree_cursor_current_node); + LOAD_DLL_FN (library, ts_tree_cursor_goto_first_child); + LOAD_DLL_FN (library, ts_tree_cursor_goto_next_sibling); + LOAD_DLL_FN (library, ts_tree_cursor_goto_parent); + LOAD_DLL_FN (library, ts_tree_cursor_new); + LOAD_DLL_FN (library, ts_tree_delete); + LOAD_DLL_FN (library, ts_tree_edit); + LOAD_DLL_FN (library, ts_tree_root_node); + + return true; +} + +#define ts_language_version fn_ts_language_version +#define ts_node_child fn_ts_node_child +#define ts_node_child_by_field_name fn_ts_node_child_by_field_name +#define ts_node_child_count fn_ts_node_child_count +#define ts_node_descendant_for_byte_range fn_ts_node_descendant_for_byte_range +#define ts_node_end_byte fn_ts_node_end_byte +#define ts_node_eq fn_ts_node_eq +#define ts_node_field_name_for_child fn_ts_node_field_name_for_child +#define ts_node_first_child_for_byte fn_ts_node_first_child_for_byte +#define ts_node_first_named_child_for_byte fn_ts_node_first_named_child_for_byte +#define ts_node_has_changes fn_ts_node_has_changes +#define ts_node_has_error fn_ts_node_has_error +#define ts_node_is_extra fn_ts_node_is_extra +#define ts_node_is_missing fn_ts_node_is_missing +#define ts_node_is_named fn_ts_node_is_named +#define ts_node_is_null fn_ts_node_is_null +#define ts_node_named_child fn_ts_node_named_child +#define ts_node_named_child_count fn_ts_node_named_child_count +#define ts_node_named_descendant_for_byte_range fn_ts_node_named_descendant_for_byte_range +#define ts_node_next_named_sibling fn_ts_node_next_named_sibling +#define ts_node_next_sibling fn_ts_node_next_sibling +#define ts_node_parent fn_ts_node_parent +#define ts_node_prev_named_sibling fn_ts_node_prev_named_sibling +#define ts_node_prev_sibling fn_ts_node_prev_sibling +#define ts_node_start_byte fn_ts_node_start_byte +#define ts_node_string fn_ts_node_string +#define ts_node_type fn_ts_node_type +#define ts_parser_delete fn_ts_parser_delete +#define ts_parser_included_ranges fn_ts_parser_included_ranges +#define ts_parser_language fn_ts_parser_language +#define ts_parser_new fn_ts_parser_new +#define ts_parser_parse fn_ts_parser_parse +#define ts_parser_set_included_ranges fn_ts_parser_set_included_ranges +#define ts_parser_set_language fn_ts_parser_set_language +#define ts_query_capture_name_for_id fn_ts_query_capture_name_for_id +#define ts_query_cursor_delete fn_ts_query_cursor_delete +#define ts_query_cursor_exec fn_ts_query_cursor_exec +#define ts_query_cursor_new fn_ts_query_cursor_new +#define ts_query_cursor_next_match fn_ts_query_cursor_next_match +#define ts_query_cursor_set_byte_range fn_ts_query_cursor_set_byte_range +#define ts_query_delete fn_ts_query_delete +#define ts_query_new fn_ts_query_new +#define ts_query_predicates_for_pattern fn_ts_query_predicates_for_pattern +#define ts_query_string_value_for_id fn_ts_query_string_value_for_id +#define ts_set_allocator fn_ts_set_allocator +#define ts_tree_cursor_current_node fn_ts_tree_cursor_current_node +#define ts_tree_cursor_goto_first_child fn_ts_tree_cursor_goto_first_child +#define ts_tree_cursor_goto_next_sibling fn_ts_tree_cursor_goto_next_sibling +#define ts_tree_cursor_goto_parent fn_ts_tree_cursor_goto_parent +#define ts_tree_cursor_new fn_ts_tree_cursor_new +#define ts_tree_delete fn_ts_tree_delete +#define ts_tree_edit fn_ts_tree_edit +#define ts_tree_root_node fn_ts_tree_root_node + +#endif /* WINDOWSNT */ + + /* Commentary The Emacs wrapper of tree-sitter does not expose everything the C @@ -126,6 +379,33 @@ along with GNU Emacs. If not, see . */ bool ts_initialized = false; +static bool +load_tree_sitter_if_necessary (bool required) +{ +#ifdef WINDOWSNT + static bool tried_to_initialize_once; + static bool tree_sitter_initialized; + + if (!tried_to_initialize_once) + { + Lisp_Object status; + + tried_to_initialize_once = true; + tree_sitter_initialized = init_treesit_functions (); + status = tree_sitter_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qtree_sitter, status), Vlibrary_cache); + } + + if (required && !tree_sitter_initialized) + xsignal1 (Qtreesit_error, + build_string ("tree-sitter library not found or failed to load")); + + return tree_sitter_initialized; +#else + return true; +#endif +} + static void * ts_calloc_wrapper (size_t n, size_t size) { @@ -137,6 +417,7 @@ ts_initialize (void) { if (!ts_initialized) { + load_tree_sitter_if_necessary (true); ts_set_allocator (xmalloc, ts_calloc_wrapper, xrealloc, xfree); ts_initialized = true; } @@ -536,7 +817,7 @@ ts_ensure_parsed (Lisp_Object parser) /* Before we parse, catch up with the narrowing situation. */ ts_ensure_position_synced (parser); - TSTree *new_tree = ts_parser_parse(ts_parser, tree, input); + TSTree *new_tree = ts_parser_parse (ts_parser, tree, input); /* This should be very rare (impossible, really): it only happens when 1) language is not set (impossible in Emacs because the user has to supply a language to create a parser), 2) parse canceled @@ -661,6 +942,28 @@ make_ts_query (Lisp_Object query, Lisp_Object language) return make_lisp_ptr (lisp_query, Lisp_Vectorlike); } +/* The following two functions are called from alloc.c:cleanup_vector. */ +void +ts_delete_parser (struct Lisp_TS_Parser *lisp_parser) +{ + ts_tree_delete(lisp_parser->tree); + ts_parser_delete(lisp_parser->parser); +} + +void +ts_delete_query (struct Lisp_TS_Query *lisp_query) +{ + ts_query_delete (lisp_query->query); + ts_query_cursor_delete (lisp_query->cursor); +} + +/* The following function is called from print.c:print_vectorlike. */ +bool +ts_named_node_p (TSNode node) +{ + return ts_node_is_named (node); +} + static const char* ts_query_error_to_string (TSQueryError error) { @@ -936,6 +1239,7 @@ DEFUN ("treesit-parser-root-node", (Lisp_Object parser) { ts_check_parser (parser); + ts_initialize (); ts_ensure_parsed (parser); TSNode root_node = ts_tree_root_node (XTS_PARSER (parser)->tree); return make_ts_node (parser, root_node); @@ -987,6 +1291,7 @@ is nil, set PARSER to parse the whole buffer. */) CHECK_CONS (ranges); ts_check_range_argument (ranges); + ts_initialize (); /* Before we parse, catch up with narrowing/widening. */ ts_ensure_position_synced (parser); @@ -1049,6 +1354,7 @@ nil. */) (Lisp_Object parser) { ts_check_parser (parser); + ts_initialize (); uint32_t len; const TSRange *ranges = ts_parser_included_ranges (XTS_PARSER (parser)->parser, &len); @@ -1109,6 +1415,8 @@ If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; const char *type = ts_node_type (ts_node); return build_string (type); @@ -1122,6 +1430,8 @@ If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; @@ -1141,6 +1451,8 @@ If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; @@ -1160,6 +1472,8 @@ If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; char *string = ts_node_string (ts_node); return build_string (string); @@ -1173,6 +1487,8 @@ Return nil if there isn't any. If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; TSNode parent = ts_node_parent (ts_node); @@ -1195,6 +1511,8 @@ child only. NAMED defaults to nil. If NODE is nil, return nil. */) ts_check_positive_integer (n); EMACS_INT idx = XFIXNUM (n); if (idx > UINT32_MAX) xsignal1 (Qargs_out_of_range, n); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; TSNode child; if (NILP (named)) @@ -1233,6 +1551,8 @@ errors. */) if (NILP (node)) return Qnil; ts_check_node (node); CHECK_SYMBOL (property); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; bool result; if (EQ (property, Qnamed)) @@ -1265,6 +1585,8 @@ If NODE is nil, return nil. */) ts_check_positive_integer (n); EMACS_INT idx = XFIXNUM (n); if (idx > UINT32_MAX) xsignal1 (Qargs_out_of_range, n); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; const char *name = ts_node_field_name_for_child (ts_node, (uint32_t) idx); @@ -1286,6 +1608,8 @@ nil. If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; uint32_t count; if (NILP (named)) @@ -1305,6 +1629,8 @@ Return nil if there isn't any. If NODE is nil, return nil. */) if (NILP (node)) return Qnil; ts_check_node (node); CHECK_STRING (field_name); + ts_initialize (); + char *name_str = SSDATA (field_name); TSNode ts_node = XTS_NODE (node)->node; TSNode child @@ -1327,6 +1653,8 @@ child only. NAMED defaults to nil. If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; TSNode sibling; if (NILP (named)) @@ -1351,6 +1679,8 @@ child only. NAMED defaults to nil. If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; ts_check_node (node); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; TSNode sibling; @@ -1390,6 +1720,8 @@ this function returns an immediate child, not the smallest if (byte_pos < BUF_BEGV_BYTE (buf) || byte_pos > BUF_ZV_BYTE (buf)) xsignal1 (Qargs_out_of_range, pos); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; TSNode child; if (NILP (named)) @@ -1433,6 +1765,8 @@ only. NAMED defaults to nil. If NODE is nil, return nil. */) && byte_end <= BUF_ZV_BYTE (buf))) xsignal2 (Qargs_out_of_range, beg, end); + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; TSNode child; if (NILP (named)) @@ -1460,6 +1794,8 @@ If any one of NODE1 and NODE2 is nil, return nil. */) CHECK_TS_NODE (node1); CHECK_TS_NODE (node2); + ts_initialize (); + TSNode ts_node_1 = XTS_NODE (node1)->node; TSNode ts_node_2 = XTS_NODE (node2)->node; @@ -1749,6 +2085,8 @@ You can use `treesit-query-validate' to debug the query. */) if (TS_COMPILED_QUERY_P (query)) return query; + ts_initialize (); + Lisp_Object lisp_query = make_ts_query (query, language); /* Maybe actually compile. */ @@ -1823,6 +2161,8 @@ query. */) Qtreesit_parser_p, Qsymbolp), node); + ts_initialize (); + /* Extract C values from Lisp objects. */ TSNode ts_node = XTS_NODE (lisp_node)->node; Lisp_Object lisp_parser = XTS_NODE (lisp_node)->parser; @@ -2113,13 +2453,15 @@ Return the first matched node, or nil if none matches. */) ptrdiff_t the_limit = 0; bool no_limit = false; if (NILP (limit)) - no_limit = true; + no_limit = true; else { CHECK_FIXNUM (limit); the_limit = XFIXNUM (limit); } + ts_initialize (); + TSNode ts_node = XTS_NODE (node)->node; Lisp_Object parser = XTS_NODE (node)->parser; if (ts_search_dfs @@ -2171,6 +2513,8 @@ case, only 1 3 4 8 16 would be traversed. */) CHECK_SYMBOL (backward); CHECK_SYMBOL (up); + ts_initialize (); + TSNode ts_start = XTS_NODE (start)->node; Lisp_Object parser = XTS_NODE (start)->parser; if (ts_search_forward @@ -2284,13 +2628,15 @@ regexp. */) ptrdiff_t the_limit = 0; bool no_limit = false; if (NILP (limit)) - no_limit = true; + no_limit = true; else { CHECK_FIXNUM (limit); the_limit = XFIXNUM (limit); } + ts_initialize (); + TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node); Lisp_Object parser = XTS_NODE (root)->parser; Lisp_Object parent = Fcons (Qnil, Qnil); @@ -2304,12 +2650,28 @@ regexp. */) return parent; } +#endif /* HAVE_TREE_SITTER */ + +DEFUN ("treesit-available-p", Ftreesit_available_p, + Streesit_available_p, 0, 0, 0, + doc: /* Return non-nil if tree-sitter support is built-in and available. */) + (void) +{ +#if HAVE_TREE_SITTER + return load_tree_sitter_if_necessary (false) ? Qt : Qnil; +#else + return Qnil; +#endif +} + + /*** Initialization */ /* Initialize the tree-sitter routines. */ void syms_of_treesit (void) { +#if HAVE_TREE_SITTER DEFSYM (Qtreesit_parser_p, "treesit-parser-p"); DEFSYM (Qtreesit_node_p, "treesit-node-p"); DEFSYM (Qtreesit_compiled_query_p, "treesit-compiled-query-p"); @@ -2340,6 +2702,10 @@ syms_of_treesit (void) DEFSYM (Qor, "or"); +#ifdef WINDOWSNT + DEFSYM (Qtree_sitter, "tree-sitter"); +#endif + define_error (Qtreesit_error, "Generic tree-sitter error", Qerror); define_error (Qtreesit_query_error, "Query pattern is malformed", Qtreesit_error); @@ -2436,4 +2802,6 @@ dynamic libraries, in that order. */); defsubr (&Streesit_search_subtree); defsubr (&Streesit_search_forward); defsubr (&Streesit_induce_sparse_tree); +#endif /* HAVE_TREE_SITTER */ + defsubr (&Streesit_available_p); } diff --git a/src/treesit.h b/src/treesit.h index 20e7cd4107c..ebde6ccf673 100644 --- a/src/treesit.h +++ b/src/treesit.h @@ -180,6 +180,10 @@ make_ts_parser (Lisp_Object buffer, TSParser *parser, Lisp_Object make_ts_node (Lisp_Object parser, TSNode node); +extern void ts_delete_parser (struct Lisp_TS_Parser *); +extern void ts_delete_query (struct Lisp_TS_Query *); +extern bool ts_named_node_p (TSNode); + extern void syms_of_treesit (void); INLINE_HEADER_END