1use std::fmt;
2use std::sync::{Arc, Mutex};
3
4use crate::errors::{ConsoleErrorListener, ErrorListener, SyntaxErrorEvent};
5use crate::vocabulary::Vocabulary;
6
7#[derive(Clone)]
8struct ErrorListenerSlot(Arc<Mutex<dyn for<'a> ErrorListener<dyn Recognizer + 'a> + Send>>);
9
10impl ErrorListenerSlot {
11 fn new<L>(listener: L) -> Self
12 where
13 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
14 {
15 Self(Arc::new(Mutex::new(listener)))
16 }
17
18 fn syntax_error(&self, recognizer: &(dyn Recognizer + '_), event: &SyntaxErrorEvent<'_>) {
19 self.0
20 .lock()
21 .expect("error listener lock poisoned")
22 .syntax_error(recognizer, event);
23 }
24}
25
26impl fmt::Debug for ErrorListenerSlot {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.write_str("ErrorListener")
29 }
30}
31
32#[derive(Clone, Debug)]
33pub(crate) struct RecognizerMetadata {
34 grammar_file_name: String,
35 rule_names: Vec<String>,
36 channel_names: Vec<String>,
37 mode_names: Vec<String>,
38 vocabulary: Vocabulary,
39}
40
41impl RecognizerMetadata {
42 pub(crate) fn from_static(
43 grammar_file_name: &'static str,
44 rule_names: &'static [&'static str],
45 channel_names: &'static [&'static str],
46 mode_names: &'static [&'static str],
47 vocabulary: Vocabulary,
48 ) -> Self {
49 Self {
50 grammar_file_name: grammar_file_name.to_owned(),
51 rule_names: rule_names.iter().map(|name| (*name).to_owned()).collect(),
52 channel_names: channel_names
53 .iter()
54 .map(|name| (*name).to_owned())
55 .collect(),
56 mode_names: mode_names.iter().map(|name| (*name).to_owned()).collect(),
57 vocabulary,
58 }
59 }
60}
61
62#[derive(Clone, Debug)]
63pub struct RecognizerData {
64 metadata: Arc<RecognizerMetadata>,
65 state: isize,
66 console_error_listener: bool,
67 error_listeners: Vec<ErrorListenerSlot>,
68}
69
70impl RecognizerData {
71 pub fn new(grammar_file_name: impl Into<String>, vocabulary: Vocabulary) -> Self {
72 Self {
73 metadata: Arc::new(RecognizerMetadata {
74 grammar_file_name: grammar_file_name.into(),
75 rule_names: Vec::new(),
76 channel_names: Vec::new(),
77 mode_names: Vec::new(),
78 vocabulary,
79 }),
80 state: -1,
81 console_error_listener: true,
82 error_listeners: Vec::new(),
83 }
84 }
85
86 pub(crate) const fn from_shared(metadata: Arc<RecognizerMetadata>) -> Self {
87 Self {
88 metadata,
89 state: -1,
90 console_error_listener: true,
91 error_listeners: Vec::new(),
92 }
93 }
94
95 #[must_use]
96 pub fn with_rule_names(
97 mut self,
98 rule_names: impl IntoIterator<Item = impl Into<String>>,
99 ) -> Self {
100 Arc::make_mut(&mut self.metadata).rule_names =
101 rule_names.into_iter().map(Into::into).collect();
102 self
103 }
104
105 #[must_use]
106 pub fn with_channel_names(
107 mut self,
108 channel_names: impl IntoIterator<Item = impl Into<String>>,
109 ) -> Self {
110 Arc::make_mut(&mut self.metadata).channel_names =
111 channel_names.into_iter().map(Into::into).collect();
112 self
113 }
114
115 #[must_use]
116 pub fn with_mode_names(
117 mut self,
118 mode_names: impl IntoIterator<Item = impl Into<String>>,
119 ) -> Self {
120 Arc::make_mut(&mut self.metadata).mode_names =
121 mode_names.into_iter().map(Into::into).collect();
122 self
123 }
124
125 #[must_use]
131 pub fn rule_names(&self) -> &[String] {
132 &self.metadata.rule_names
133 }
134
135 #[must_use]
137 pub fn vocabulary(&self) -> &Vocabulary {
138 &self.metadata.vocabulary
139 }
140
141 pub const fn state(&self) -> isize {
142 self.state
143 }
144
145 pub const fn set_state(&mut self, state: isize) {
146 self.state = state;
147 }
148
149 fn add_error_listener<L>(&mut self, listener: L)
150 where
151 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
152 {
153 self.error_listeners.push(ErrorListenerSlot::new(listener));
154 }
155
156 fn remove_error_listeners(&mut self) {
157 self.console_error_listener = false;
158 self.error_listeners.clear();
159 }
160
161 fn notify_error_listeners(&self, recognizer: &dyn Recognizer, event: &SyntaxErrorEvent<'_>) {
162 if self.console_error_listener {
163 ConsoleErrorListener.syntax_error(recognizer, event);
164 }
165 for listener in &self.error_listeners {
166 listener.syntax_error(recognizer, event);
167 }
168 }
169}
170
171pub trait Recognizer {
172 fn data(&self) -> &RecognizerData;
173 fn data_mut(&mut self) -> &mut RecognizerData;
174
175 fn grammar_file_name(&self) -> &str {
176 &self.data().metadata.grammar_file_name
177 }
178
179 fn rule_names(&self) -> &[String] {
180 &self.data().metadata.rule_names
181 }
182
183 fn channel_names(&self) -> &[String] {
184 &self.data().metadata.channel_names
185 }
186
187 fn mode_names(&self) -> &[String] {
188 &self.data().metadata.mode_names
189 }
190
191 fn vocabulary(&self) -> &Vocabulary {
192 &self.data().metadata.vocabulary
193 }
194
195 fn state(&self) -> isize {
196 self.data().state()
197 }
198
199 fn set_state(&mut self, state: isize) {
200 self.data_mut().set_state(state);
201 }
202
203 fn add_error_listener<L>(&mut self, listener: L)
209 where
210 Self: Sized,
211 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
212 {
213 self.data_mut().add_error_listener(listener);
214 }
215
216 fn remove_error_listeners(&mut self) {
218 self.data_mut().remove_error_listeners();
219 }
220
221 fn notify_error_listeners(&self, event: SyntaxErrorEvent<'_>)
223 where
224 Self: Sized,
225 {
226 self.data().notify_error_listeners(self, &event);
227 }
228
229 fn sempred(&mut self, _rule_index: usize, _pred_index: usize) -> bool {
230 true
231 }
232
233 fn action(&mut self, _rule_index: usize, _action_index: usize) {}
234}
235
236#[cfg(test)]
237#[allow(clippy::disallowed_methods)] mod tests {
239 use std::mem::size_of;
240
241 use super::*;
242 use crate::errors::AntlrError;
243 use crate::generated::GrammarMetadata;
244
245 static SHARED_METADATA: GrammarMetadata = GrammarMetadata::new(
246 "Shared.g4",
247 &["start"],
248 &[None, Some("'x'")],
249 &[None, Some("X")],
250 &[None, None],
251 &["DEFAULT_TOKEN_CHANNEL", "HIDDEN"],
252 &["DEFAULT_MODE"],
253 &[],
254 );
255
256 #[derive(Clone, Debug, Eq, PartialEq)]
257 struct RecordedError {
258 grammar_file_name: String,
259 offending_text: Option<String>,
260 line: usize,
261 column: usize,
262 span: Option<std::ops::Range<usize>>,
263 message: String,
264 error: Option<AntlrError>,
265 }
266
267 #[derive(Clone, Debug)]
268 struct RecordingErrorListener {
269 errors: Arc<Mutex<Vec<RecordedError>>>,
270 }
271
272 impl<R> ErrorListener<R> for RecordingErrorListener
273 where
274 R: Recognizer + ?Sized,
275 {
276 fn syntax_error(&mut self, recognizer: &R, event: &SyntaxErrorEvent<'_>) {
277 self.errors
278 .lock()
279 .expect("recorded errors lock")
280 .push(RecordedError {
281 grammar_file_name: recognizer.grammar_file_name().to_owned(),
282 offending_text: event
283 .offending
284 .and_then(|token| token.text().map(str::to_owned)),
285 line: event.line,
286 column: event.column,
287 span: event.span.clone(),
288 message: event.message.to_owned(),
289 error: event.error.cloned(),
290 });
291 }
292 }
293
294 #[derive(Clone, Debug)]
295 struct TestRecognizer {
296 data: RecognizerData,
297 }
298
299 impl Recognizer for TestRecognizer {
300 fn data(&self) -> &RecognizerData {
301 &self.data
302 }
303
304 fn data_mut(&mut self) -> &mut RecognizerData {
305 &mut self.data
306 }
307 }
308
309 fn test_recognizer() -> TestRecognizer {
310 TestRecognizer {
311 data: RecognizerData::new(
312 "Test.g4",
313 Vocabulary::new(
314 std::iter::empty::<Option<&str>>(),
315 std::iter::empty::<Option<&str>>(),
316 std::iter::empty::<Option<&str>>(),
317 ),
318 ),
319 }
320 }
321
322 #[test]
323 fn recognizers_replace_the_default_console_error_listener() {
324 let mut recognizer = test_recognizer();
325 assert!(recognizer.data.console_error_listener);
326 assert!(recognizer.data.error_listeners.is_empty());
327
328 recognizer.remove_error_listeners();
329 assert!(!recognizer.data.console_error_listener);
330 assert!(recognizer.data.error_listeners.is_empty());
331
332 let errors = Arc::new(Mutex::new(Vec::new()));
333 recognizer.add_error_listener(RecordingErrorListener {
334 errors: Arc::clone(&errors),
335 });
336 let error = AntlrError::ParserError {
337 line: 3,
338 column: 5,
339 message: "unexpected token".to_owned(),
340 offending: None,
341 };
342 recognizer.notify_error_listeners(SyntaxErrorEvent {
343 offending: None,
344 line: 3,
345 column: 5,
346 span: Some(17..27),
347 message: "unexpected token",
348 error: Some(&error),
349 });
350
351 insta::assert_debug_snapshot!(
352 "recognizers_replace_the_default_console_error_listener",
353 *errors.lock().expect("recorded errors lock")
354 );
355 }
356
357 #[test]
358 fn recognizer_data_remains_send_and_sync() {
359 fn assert_send_and_sync<T: Send + Sync>() {}
360
361 assert_send_and_sync::<RecognizerData>();
362 }
363
364 #[test]
365 fn recognizer_data_keeps_shared_metadata_out_of_line() {
366 assert!(size_of::<RecognizerData>() < size_of::<RecognizerMetadata>());
367 }
368
369 #[test]
370 fn cloned_recognizers_can_reconfigure_their_listener_lists_independently() {
371 let mut original = test_recognizer();
372 let clone = original.clone();
373
374 original.remove_error_listeners();
375
376 assert!(!original.data.console_error_listener);
377 assert!(original.data.error_listeners.is_empty());
378 assert!(clone.data.console_error_listener);
379 assert!(clone.data.error_listeners.is_empty());
380 }
381
382 #[test]
383 fn generated_recognizers_share_metadata_but_not_instance_state() {
384 let mut first = SHARED_METADATA.recognizer_data();
385 let second = SHARED_METADATA.recognizer_data();
386
387 assert!(std::ptr::eq(first.rule_names(), second.rule_names()));
388 assert!(std::ptr::eq(first.vocabulary(), second.vocabulary()));
389 assert!(first.console_error_listener);
390 assert!(second.console_error_listener);
391
392 first.set_state(7);
393 first.remove_error_listeners();
394
395 assert_eq!(first.state(), 7);
396 assert_eq!(second.state(), -1);
397 assert!(!first.console_error_listener);
398 assert!(first.error_listeners.is_empty());
399 assert!(second.console_error_listener);
400 assert!(second.error_listeners.is_empty());
401 }
402
403 #[test]
404 fn customizing_shared_metadata_detaches_only_that_recognizer() {
405 let customized = SHARED_METADATA
406 .recognizer_data()
407 .with_rule_names(["replacement"]);
408 let shared = SHARED_METADATA.recognizer_data();
409
410 assert_eq!(customized.rule_names(), ["replacement"]);
411 assert_eq!(shared.rule_names(), ["start"]);
412 assert!(!std::ptr::eq(customized.rule_names(), shared.rule_names()));
413 }
414}