diff options
| author | Yuan Fu | 2024-08-24 14:54:57 -0700 |
|---|---|---|
| committer | Yuan Fu | 2024-08-24 15:15:23 -0700 |
| commit | 4339e70a942770ce4e17d16a9708e4bdf5630514 (patch) | |
| tree | e42bd75c6b86434d9c5e3a9c501bddacf5104471 /src | |
| parent | 32afdcca8815331f1231fe9d8279ab9914197381 (diff) | |
| download | emacs-4339e70a942770ce4e17d16a9708e4bdf5630514.tar.gz emacs-4339e70a942770ce4e17d16a9708e4bdf5630514.zip | |
Make sure treesit-parse-string gc its temp buffer (bug#71012)
* doc/lispref/parsing.texi (Using Parser): Add notice.
* lisp/treesit.el (treesit-parse-string): Remove function.
* src/treesit.c (make_treesit_parser): Init the new filed.
(treesit_delete_parser): Collect the temp buffer.
(Ftreesit_parse_string): New function.
* src/treesit.h (Lisp_TS_Parser): New field.
Diffstat (limited to 'src')
| -rw-r--r-- | src/treesit.c | 48 | ||||
| -rw-r--r-- | src/treesit.h | 4 |
2 files changed, 51 insertions, 1 deletions
diff --git a/src/treesit.c b/src/treesit.c index 27779692923..a41892b1cac 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -1181,6 +1181,7 @@ make_treesit_parser (Lisp_Object buffer, TSParser *parser, | |||
| 1181 | lisp_parser->visible_end = BUF_ZV_BYTE (XBUFFER (buffer)); | 1181 | lisp_parser->visible_end = BUF_ZV_BYTE (XBUFFER (buffer)); |
| 1182 | lisp_parser->timestamp = 0; | 1182 | lisp_parser->timestamp = 0; |
| 1183 | lisp_parser->deleted = false; | 1183 | lisp_parser->deleted = false; |
| 1184 | lisp_parser->need_to_gc_buffer = false; | ||
| 1184 | eassert (lisp_parser->visible_beg <= lisp_parser->visible_end); | 1185 | eassert (lisp_parser->visible_beg <= lisp_parser->visible_end); |
| 1185 | return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); | 1186 | return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); |
| 1186 | } | 1187 | } |
| @@ -1220,6 +1221,8 @@ make_treesit_query (Lisp_Object query, Lisp_Object language) | |||
| 1220 | void | 1221 | void |
| 1221 | treesit_delete_parser (struct Lisp_TS_Parser *lisp_parser) | 1222 | treesit_delete_parser (struct Lisp_TS_Parser *lisp_parser) |
| 1222 | { | 1223 | { |
| 1224 | if (lisp_parser->need_to_gc_buffer) | ||
| 1225 | Fkill_buffer (lisp_parser->buffer); | ||
| 1223 | ts_tree_delete (lisp_parser->tree); | 1226 | ts_tree_delete (lisp_parser->tree); |
| 1224 | ts_parser_delete (lisp_parser->parser); | 1227 | ts_parser_delete (lisp_parser->parser); |
| 1225 | } | 1228 | } |
| @@ -1859,6 +1862,49 @@ positions. PARSER is the parser issuing the notification. */) | |||
| 1859 | return Qnil; | 1862 | return Qnil; |
| 1860 | } | 1863 | } |
| 1861 | 1864 | ||
| 1865 | // Why don't we use ts_parse_string? I tried, but it requires too much | ||
| 1866 | // change throughout treesit.c: we either return a root node that has no | ||
| 1867 | // associated parser, or one that has a parser but the parser doesn't | ||
| 1868 | // have associated buffer. Both route requires us to add checks and | ||
| 1869 | // branches everytime we use the parser of a node or the buffer of a | ||
| 1870 | // parser. I tried route 1, and found that on top of needing to add a | ||
| 1871 | // bunch of branches to handle the no-parser case, many functions | ||
| 1872 | // requires a parser alongside the node (getting the tree, or language | ||
| 1873 | // symbol, etc), and I would need to rewrite those as well. Overall | ||
| 1874 | // it's just not worth it--this is just a convenience function. --yuan | ||
| 1875 | DEFUN ("treesit-parse-string", | ||
| 1876 | Ftreesit_parse_string, Streesit_parse_string, | ||
| 1877 | 2, 2, 0, | ||
| 1878 | doc: /* Parse STRING using a parser for LANGUAGE. | ||
| 1879 | |||
| 1880 | Return the root node of the result parse tree. DO NOT use this function | ||
| 1881 | in a loop: this function is intended for one-off use and isn't | ||
| 1882 | optimized; for heavy workload, use a temporary buffer instead. */) | ||
| 1883 | (Lisp_Object string, Lisp_Object language) | ||
| 1884 | { | ||
| 1885 | CHECK_SYMBOL (language); | ||
| 1886 | CHECK_STRING (string); | ||
| 1887 | |||
| 1888 | Lisp_Object name_str = build_string (" *treesit-parse-string*"); | ||
| 1889 | Lisp_Object buffer_name = Fgenerate_new_buffer_name (name_str, Qnil); | ||
| 1890 | Lisp_Object buffer = Fget_buffer_create (buffer_name, Qnil); | ||
| 1891 | |||
| 1892 | struct buffer *old_buffer = current_buffer; | ||
| 1893 | set_buffer_internal (XBUFFER (buffer)); | ||
| 1894 | insert1 (string); | ||
| 1895 | set_buffer_internal (old_buffer); | ||
| 1896 | |||
| 1897 | Lisp_Object parser = Ftreesit_parser_create (language, buffer, Qt, Qnil); | ||
| 1898 | XTS_PARSER (parser)->need_to_gc_buffer = true; | ||
| 1899 | |||
| 1900 | /* Make sure the temp buffer doesn't reference the parser, otherwise | ||
| 1901 | the buffer and parser cross-reference each other and the parser is | ||
| 1902 | never garbage-collected. */ | ||
| 1903 | BVAR (XBUFFER (buffer), ts_parser_list) = Qnil; | ||
| 1904 | |||
| 1905 | return Ftreesit_parser_root_node (parser); | ||
| 1906 | } | ||
| 1907 | |||
| 1862 | 1908 | ||
| 1863 | /*** Node API */ | 1909 | /*** Node API */ |
| 1864 | 1910 | ||
| @@ -4245,7 +4291,7 @@ applies to LANGUAGE-A will be redirected to LANGUAGE-B instead. */); | |||
| 4245 | defsubr (&Streesit_parser_tag); | 4291 | defsubr (&Streesit_parser_tag); |
| 4246 | 4292 | ||
| 4247 | defsubr (&Streesit_parser_root_node); | 4293 | defsubr (&Streesit_parser_root_node); |
| 4248 | /* defsubr (&Streesit_parse_string); */ | 4294 | defsubr (&Streesit_parse_string); |
| 4249 | 4295 | ||
| 4250 | defsubr (&Streesit_parser_set_included_ranges); | 4296 | defsubr (&Streesit_parser_set_included_ranges); |
| 4251 | defsubr (&Streesit_parser_included_ranges); | 4297 | defsubr (&Streesit_parser_included_ranges); |
diff --git a/src/treesit.h b/src/treesit.h index 3da4cc155ea..cd84fa358c5 100644 --- a/src/treesit.h +++ b/src/treesit.h | |||
| @@ -82,6 +82,10 @@ struct Lisp_TS_Parser | |||
| 82 | /* If this field is true, parser functions raises | 82 | /* If this field is true, parser functions raises |
| 83 | treesit-parser-deleted signal. */ | 83 | treesit-parser-deleted signal. */ |
| 84 | bool deleted; | 84 | bool deleted; |
| 85 | /* If this field is true, deleting the parser should also delete the | ||
| 86 | associated buffer. This is for parsers created by | ||
| 87 | treesit-parse-string, which uses a hidden temp buffer. */ | ||
| 88 | bool need_to_gc_buffer; | ||
| 85 | }; | 89 | }; |
| 86 | 90 | ||
| 87 | /* A wrapper around a tree-sitter node. */ | 91 | /* A wrapper around a tree-sitter node. */ |