2525#include " utils/ts_preconditions.h"
2626#include " utils/ts_log.h"
2727
28- static std::mutex cancellation_flag_mutex;
29- static std::atomic<size_t *> cancellation_flag (nullptr );
28+ /* *
29+ * `TSParserInternal` stores the actual tree sitter parser instance along
30+ * with the cancellation flag and the cancellation flag mutex.
31+ */
32+ class TSParserInternal {
33+ public:
3034
31- static size_t *get_cancellation_flag () {
32- std::lock_guard<std::mutex> get_lock (cancellation_flag_mutex);
33- return cancellation_flag.load ();
34- }
35+ TSParserInternal () {
36+ cancellation_flag_mutex = new std::mutex ();
37+ cancellation_flag = new std::atomic<size_t *>(nullptr );
38+ parser = ts_parser_new ();
39+ }
3540
36- static void set_cancellation_flag (size_t *flag) {
37- std::lock_guard<std::mutex> set_lock (cancellation_flag_mutex);
38- cancellation_flag.store (flag);
39- }
41+ ~TSParserInternal () {
42+ delete cancellation_flag_mutex;
43+ delete cancellation_flag;
44+
45+ ts_parser_delete (parser);
46+
47+ cancellation_flag_mutex = nullptr ;
48+ cancellation_flag = nullptr ;
49+ parser = nullptr ;
50+ }
51+
52+ TSParser *getParser (JNIEnv *env) {
53+ if (check_destroyed (env)) {
54+ return nullptr ;
55+ }
56+
57+ return this ->parser ;
58+ }
59+
60+ bool begin_round (JNIEnv *env) {
61+ auto flag = get_cancellation_flag (env);
62+
63+ if (flag) {
64+ throw_illegal_state (env,
65+ " Parser is already parsing another syntax tree! You must cancel the current parse first!" );
66+ return false ;
67+ }
68+
69+ // allocate a new cancellation flag
70+ flag = (size_t *) malloc (sizeof (int ));
71+ set_cancellation_flag (env, flag);
72+
73+ // set the cancellation flag to '0' to indicate that the parser should continue parsing
74+ *flag = 0 ;
75+ ts_parser_set_cancellation_flag (getParser (env), flag);
76+
77+ return true ;
78+ }
79+
80+ void end_round (JNIEnv *env) {
81+
82+ size_t *flag = get_cancellation_flag (env);
83+
84+ // release the cancellation flag
85+ free ((size_t *) flag);
86+ set_cancellation_flag (env, nullptr );
87+ ts_parser_set_cancellation_flag (getParser (env), nullptr );
88+ }
89+
90+ size_t *get_cancellation_flag (JNIEnv *env) {
91+ if (check_destroyed (env)) {
92+ return nullptr ;
93+ }
94+
95+ std::lock_guard<std::mutex> get_lock (*cancellation_flag_mutex);
96+ return cancellation_flag->load ();
97+ }
98+
99+ void set_cancellation_flag (JNIEnv *env, size_t *flag) {
100+ if (check_destroyed (env)) {
101+ return ;
102+ }
103+
104+ std::lock_guard<std::mutex> set_lock (*cancellation_flag_mutex);
105+ cancellation_flag->store (flag);
106+ }
107+
108+ private:
109+ std::mutex *cancellation_flag_mutex;
110+ std::atomic<size_t *> *cancellation_flag;
111+
112+ TSParser *parser;
113+
114+ bool check_destroyed (JNIEnv *env) {
115+ if (cancellation_flag_mutex == nullptr || cancellation_flag == nullptr || parser == nullptr ) {
116+ throw_illegal_state (env, " TSParserInternal has already been destroyed" );
117+ return true ;
118+ }
119+
120+ return false ;
121+ }
122+ };
40123
41124extern " C" JNIEXPORT jlong JNICALL
42125Java_com_itsaky_androidide_treesitter_TSParser_00024Native_newParser (
43126 JNIEnv *env, jclass self) {
44- return (jlong) ts_parser_new ();
127+ auto parser = new TSParserInternal;
128+ return (jlong) parser;
45129}
46130
47131extern " C" JNIEXPORT void JNICALL
48132Java_com_itsaky_androidide_treesitter_TSParser_00024Native_delete (
49- JNIEnv *env, jclass self, jlong parser) {
50- req_nnp (env, parser);
51- ts_parser_delete ((TSParser *) parser);
133+ JNIEnv *env, jclass self, jlong parser_ptr) {
134+ req_nnp (env, parser_ptr);
135+
136+ auto parser = (TSParserInternal *) parser_ptr;
137+ delete parser;
52138}
53139
54140extern " C" JNIEXPORT void JNICALL
55141Java_com_itsaky_androidide_treesitter_TSParser_00024Native_setLanguage (
56142 JNIEnv *env, jclass self, jlong parser, jlong language) {
57143 req_nnp (env, parser, " parser" );
58144 req_nnp (env, language, " language" );
59- ts_parser_set_language ((TSParser *) parser, (TSLanguage *) language);
145+ ts_parser_set_language (((TSParserInternal *) parser)-> getParser (env) , (TSLanguage *) language);
60146}
61147
62148extern " C" JNIEXPORT jlong JNICALL
63149Java_com_itsaky_androidide_treesitter_TSParser_00024Native_getLanguage (
64150 JNIEnv *env, jclass self, jlong parser) {
65151 req_nnp (env, parser);
66- return (jlong) ts_parser_language ((TSParser *) parser);
152+ return (jlong) ts_parser_language (((TSParserInternal *) parser)-> getParser (env) );
67153}
68154
69155extern " C" JNIEXPORT void JNICALL
70156Java_com_itsaky_androidide_treesitter_TSParser_00024Native_reset (JNIEnv *env,
71157 jclass self,
72158 jlong parser) {
73159 req_nnp (env, parser);
74- ts_parser_reset ((TSParser *) parser);
160+ ts_parser_reset (((TSParserInternal *) parser)-> getParser (env) );
75161}
76162
77163extern " C" JNIEXPORT void JNICALL
78164Java_com_itsaky_androidide_treesitter_TSParser_00024Native_setTimeout (
79165 JNIEnv *env, jclass self, jlong parser, jlong macros) {
80166 req_nnp (env, parser);
81- ts_parser_set_timeout_micros ((TSParser *) parser, macros);
167+ ts_parser_set_timeout_micros (((TSParserInternal *) parser)-> getParser (env) , macros);
82168}
83169
84170extern " C" JNIEXPORT jlong JNICALL
85171Java_com_itsaky_androidide_treesitter_TSParser_00024Native_getTimeout (
86172 JNIEnv *env, jclass self, jlong parser) {
87173 req_nnp (env, parser);
88- return (jlong) ts_parser_timeout_micros ((TSParser *) parser);
174+ return (jlong) ts_parser_timeout_micros (((TSParserInternal *) parser)-> getParser (env) );
89175}
90176
91177extern " C" JNIEXPORT jboolean JNICALL
@@ -102,7 +188,7 @@ Java_com_itsaky_androidide_treesitter_TSParser_00024Native_setIncludedRanges(
102188 }
103189
104190 const TSRange *r = tsRanges;
105- return (jboolean) ts_parser_set_included_ranges ((TSParser *) parser,
191+ return (jboolean) ts_parser_set_included_ranges (((TSParserInternal *) parser)-> getParser (env) ,
106192 r,
107193 count);
108194}
@@ -112,7 +198,7 @@ Java_com_itsaky_androidide_treesitter_TSParser_00024Native_getIncludedRanges(
112198 JNIEnv *env, jclass self, jlong parser) {
113199 req_nnp (env, parser);
114200 jint count;
115- const TSRange *ranges = ts_parser_included_ranges ((TSParser *) parser,
201+ const TSRange *ranges = ts_parser_included_ranges (((TSParserInternal *) parser)-> getParser (env) ,
116202 reinterpret_cast <uint32_t *>(&count));
117203 jobjectArray result = createRangeArr (env, count);
118204 req_nnp (env, result, " TSRange[] from factory" );
@@ -133,25 +219,12 @@ Java_com_itsaky_androidide_treesitter_TSParser_00024Native_parse(JNIEnv *env,
133219 jlong str_pointer) {
134220 req_nnp (env, parser);
135221 req_nnp (env, str_pointer, " string" );
136- auto *ts_parser = (TSParser *) parser;
222+ auto *ts_parser_internal = (TSParserInternal *) parser;
223+ TSParser *ts_parser = ts_parser_internal->getParser (env);
137224 TSTree *old_tree = tree_pointer == 0 ? nullptr : (TSTree *) tree_pointer;
138225 auto *source = as_str (str_pointer);
139226
140- auto flag = get_cancellation_flag ();
141-
142- if (flag) {
143- throw_illegal_state (env,
144- " Parser is already parsing another syntax tree! You must cancel the current parse first!" );
145- return 0 ;
146- }
147-
148- // allocate a new cancellation flag
149- flag = (size_t *) malloc (sizeof (int ));
150- set_cancellation_flag (flag);
151-
152- // set the cancellation flag to '0' to indicate that the parser should continue parsing
153- *flag = 0 ;
154- ts_parser_set_cancellation_flag (ts_parser, flag);
227+ ts_parser_internal->begin_round (env);
155228
156229 // start parsing
157230 // if the user cancels the parse while this method is being executed
@@ -163,10 +236,7 @@ Java_com_itsaky_androidide_treesitter_TSParser_00024Native_parse(JNIEnv *env,
163236 source->byte_length (),
164237 TSInputEncodingUTF16);
165238
166- // release the cancellation flag
167- free ((size_t *) flag);
168- set_cancellation_flag (nullptr );
169- ts_parser_set_cancellation_flag (ts_parser, nullptr );
239+ ts_parser_internal->end_round (env);
170240
171241 return (jlong) tree;
172242}
@@ -175,9 +245,11 @@ extern "C"
175245JNIEXPORT jboolean JNICALL
176246Java_com_itsaky_androidide_treesitter_TSParser_00024Native_requestCancellation (
177247 JNIEnv *env,
178- jclass clazz) {
248+ jclass clazz,
249+ jlong parser) {
179250
180- auto flag = get_cancellation_flag ();
251+ auto *parserInternal = (TSParserInternal *) parser;
252+ auto flag = parserInternal->get_cancellation_flag (env);
181253
182254 // no parse is in progress
183255 if (flag == nullptr ) {
0 commit comments