1use std::fmt;
2use std::sync::{Arc, Mutex};
3
4use crate::errors::{AntlrError, ConsoleErrorListener, ErrorListener};
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(
19 &self,
20 recognizer: &(dyn Recognizer + '_),
21 line: usize,
22 column: usize,
23 message: &str,
24 error: Option<&AntlrError>,
25 ) {
26 self.0
27 .lock()
28 .expect("error listener lock poisoned")
29 .syntax_error(recognizer, line, column, message, error);
30 }
31}
32
33impl fmt::Debug for ErrorListenerSlot {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f.write_str("ErrorListener")
36 }
37}
38
39#[derive(Clone, Debug)]
40pub struct RecognizerData {
41 grammar_file_name: String,
42 rule_names: Vec<String>,
43 channel_names: Vec<String>,
44 mode_names: Vec<String>,
45 vocabulary: Vocabulary,
46 state: isize,
47 error_listeners: Vec<ErrorListenerSlot>,
48}
49
50impl RecognizerData {
51 pub fn new(grammar_file_name: impl Into<String>, vocabulary: Vocabulary) -> Self {
52 Self {
53 grammar_file_name: grammar_file_name.into(),
54 rule_names: Vec::new(),
55 channel_names: Vec::new(),
56 mode_names: Vec::new(),
57 vocabulary,
58 state: -1,
59 error_listeners: vec![ErrorListenerSlot::new(ConsoleErrorListener)],
60 }
61 }
62
63 #[must_use]
64 pub fn with_rule_names(
65 mut self,
66 rule_names: impl IntoIterator<Item = impl Into<String>>,
67 ) -> Self {
68 self.rule_names = rule_names.into_iter().map(Into::into).collect();
69 self
70 }
71
72 #[must_use]
73 pub fn with_channel_names(
74 mut self,
75 channel_names: impl IntoIterator<Item = impl Into<String>>,
76 ) -> Self {
77 self.channel_names = channel_names.into_iter().map(Into::into).collect();
78 self
79 }
80
81 #[must_use]
82 pub fn with_mode_names(
83 mut self,
84 mode_names: impl IntoIterator<Item = impl Into<String>>,
85 ) -> Self {
86 self.mode_names = mode_names.into_iter().map(Into::into).collect();
87 self
88 }
89
90 #[must_use]
96 pub fn rule_names(&self) -> &[String] {
97 &self.rule_names
98 }
99
100 #[must_use]
102 pub const fn vocabulary(&self) -> &Vocabulary {
103 &self.vocabulary
104 }
105
106 pub const fn state(&self) -> isize {
107 self.state
108 }
109
110 pub const fn set_state(&mut self, state: isize) {
111 self.state = state;
112 }
113
114 fn add_error_listener<L>(&mut self, listener: L)
115 where
116 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
117 {
118 self.error_listeners.push(ErrorListenerSlot::new(listener));
119 }
120
121 fn remove_error_listeners(&mut self) {
122 self.error_listeners.clear();
123 }
124
125 fn notify_error_listeners(
126 &self,
127 recognizer: &dyn Recognizer,
128 line: usize,
129 column: usize,
130 message: &str,
131 error: Option<&AntlrError>,
132 ) {
133 for listener in &self.error_listeners {
134 listener.syntax_error(recognizer, line, column, message, error);
135 }
136 }
137}
138
139pub trait Recognizer {
140 fn data(&self) -> &RecognizerData;
141 fn data_mut(&mut self) -> &mut RecognizerData;
142
143 fn grammar_file_name(&self) -> &str {
144 &self.data().grammar_file_name
145 }
146
147 fn rule_names(&self) -> &[String] {
148 &self.data().rule_names
149 }
150
151 fn channel_names(&self) -> &[String] {
152 &self.data().channel_names
153 }
154
155 fn mode_names(&self) -> &[String] {
156 &self.data().mode_names
157 }
158
159 fn vocabulary(&self) -> &Vocabulary {
160 &self.data().vocabulary
161 }
162
163 fn state(&self) -> isize {
164 self.data().state()
165 }
166
167 fn set_state(&mut self, state: isize) {
168 self.data_mut().set_state(state);
169 }
170
171 fn add_error_listener<L>(&mut self, listener: L)
177 where
178 Self: Sized,
179 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
180 {
181 self.data_mut().add_error_listener(listener);
182 }
183
184 fn remove_error_listeners(&mut self) {
186 self.data_mut().remove_error_listeners();
187 }
188
189 fn notify_error_listeners(
191 &self,
192 line: usize,
193 column: usize,
194 message: &str,
195 error: Option<&AntlrError>,
196 ) where
197 Self: Sized,
198 {
199 self.data()
200 .notify_error_listeners(self, line, column, message, error);
201 }
202
203 fn sempred(&mut self, _rule_index: usize, _pred_index: usize) -> bool {
204 true
205 }
206
207 fn action(&mut self, _rule_index: usize, _action_index: usize) {}
208}
209
210#[cfg(test)]
211#[allow(clippy::disallowed_methods)] mod tests {
213 use super::*;
214
215 #[derive(Clone, Debug, Eq, PartialEq)]
216 struct RecordedError {
217 grammar_file_name: String,
218 line: usize,
219 column: usize,
220 message: String,
221 error: Option<AntlrError>,
222 }
223
224 #[derive(Clone, Debug)]
225 struct RecordingErrorListener {
226 errors: Arc<Mutex<Vec<RecordedError>>>,
227 }
228
229 impl<R> ErrorListener<R> for RecordingErrorListener
230 where
231 R: Recognizer + ?Sized,
232 {
233 fn syntax_error(
234 &mut self,
235 recognizer: &R,
236 line: usize,
237 column: usize,
238 message: &str,
239 error: Option<&AntlrError>,
240 ) {
241 self.errors
242 .lock()
243 .expect("recorded errors lock")
244 .push(RecordedError {
245 grammar_file_name: recognizer.grammar_file_name().to_owned(),
246 line,
247 column,
248 message: message.to_owned(),
249 error: error.cloned(),
250 });
251 }
252 }
253
254 #[derive(Clone, Debug)]
255 struct TestRecognizer {
256 data: RecognizerData,
257 }
258
259 impl Recognizer for TestRecognizer {
260 fn data(&self) -> &RecognizerData {
261 &self.data
262 }
263
264 fn data_mut(&mut self) -> &mut RecognizerData {
265 &mut self.data
266 }
267 }
268
269 fn test_recognizer() -> TestRecognizer {
270 TestRecognizer {
271 data: RecognizerData::new(
272 "Test.g4",
273 Vocabulary::new(
274 std::iter::empty::<Option<&str>>(),
275 std::iter::empty::<Option<&str>>(),
276 std::iter::empty::<Option<&str>>(),
277 ),
278 ),
279 }
280 }
281
282 #[test]
283 fn recognizers_replace_the_default_console_error_listener() {
284 let mut recognizer = test_recognizer();
285 assert_eq!(recognizer.data.error_listeners.len(), 1);
286
287 recognizer.remove_error_listeners();
288 assert!(recognizer.data.error_listeners.is_empty());
289
290 let errors = Arc::new(Mutex::new(Vec::new()));
291 recognizer.add_error_listener(RecordingErrorListener {
292 errors: Arc::clone(&errors),
293 });
294 let error = AntlrError::ParserError {
295 line: 3,
296 column: 5,
297 message: "unexpected token".to_owned(),
298 };
299 recognizer.notify_error_listeners(3, 5, "unexpected token", Some(&error));
300
301 insta::assert_debug_snapshot!(
302 "recognizers_replace_the_default_console_error_listener",
303 *errors.lock().expect("recorded errors lock")
304 );
305 }
306
307 #[test]
308 fn recognizer_data_remains_send_and_sync() {
309 fn assert_send_and_sync<T: Send + Sync>() {}
310
311 assert_send_and_sync::<RecognizerData>();
312 }
313
314 #[test]
315 fn cloned_recognizers_can_reconfigure_their_listener_lists_independently() {
316 let mut original = test_recognizer();
317 let clone = original.clone();
318
319 original.remove_error_listeners();
320
321 assert!(original.data.error_listeners.is_empty());
322 assert_eq!(clone.data.error_listeners.len(), 1);
323 }
324}