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