aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYuan Fu2024-08-24 14:54:57 -0700
committerYuan Fu2024-08-24 15:15:23 -0700
commit4339e70a942770ce4e17d16a9708e4bdf5630514 (patch)
treee42bd75c6b86434d9c5e3a9c501bddacf5104471 /src
parent32afdcca8815331f1231fe9d8279ab9914197381 (diff)
downloademacs-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.c48
-rw-r--r--src/treesit.h4
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)
1220void 1221void
1221treesit_delete_parser (struct Lisp_TS_Parser *lisp_parser) 1222treesit_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
1875DEFUN ("treesit-parse-string",
1876 Ftreesit_parse_string, Streesit_parse_string,
1877 2, 2, 0,
1878 doc: /* Parse STRING using a parser for LANGUAGE.
1879
1880Return the root node of the result parse tree. DO NOT use this function
1881in a loop: this function is intended for one-off use and isn't
1882optimized; 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. */