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 pub const fn state(&self) -> isize {
101 self.state
102 }
103
104 pub const fn set_state(&mut self, state: isize) {
105 self.state = state;
106 }
107
108 fn add_error_listener<L>(&mut self, listener: L)
109 where
110 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
111 {
112 self.error_listeners.push(ErrorListenerSlot::new(listener));
113 }
114
115 fn remove_error_listeners(&mut self) {
116 self.error_listeners.clear();
117 }
118
119 fn notify_error_listeners(
120 &self,
121 recognizer: &dyn Recognizer,
122 line: usize,
123 column: usize,
124 message: &str,
125 error: Option<&AntlrError>,
126 ) {
127 for listener in &self.error_listeners {
128 listener.syntax_error(recognizer, line, column, message, error);
129 }
130 }
131}
132
133pub trait Recognizer {
134 fn data(&self) -> &RecognizerData;
135 fn data_mut(&mut self) -> &mut RecognizerData;
136
137 fn grammar_file_name(&self) -> &str {
138 &self.data().grammar_file_name
139 }
140
141 fn rule_names(&self) -> &[String] {
142 &self.data().rule_names
143 }
144
145 fn channel_names(&self) -> &[String] {
146 &self.data().channel_names
147 }
148
149 fn mode_names(&self) -> &[String] {
150 &self.data().mode_names
151 }
152
153 fn vocabulary(&self) -> &Vocabulary {
154 &self.data().vocabulary
155 }
156
157 fn state(&self) -> isize {
158 self.data().state()
159 }
160
161 fn set_state(&mut self, state: isize) {
162 self.data_mut().set_state(state);
163 }
164
165 fn add_error_listener<L>(&mut self, listener: L)
171 where
172 Self: Sized,
173 L: for<'a> ErrorListener<dyn Recognizer + 'a> + Send + 'static,
174 {
175 self.data_mut().add_error_listener(listener);
176 }
177
178 fn remove_error_listeners(&mut self) {
180 self.data_mut().remove_error_listeners();
181 }
182
183 fn notify_error_listeners(
185 &self,
186 line: usize,
187 column: usize,
188 message: &str,
189 error: Option<&AntlrError>,
190 ) where
191 Self: Sized,
192 {
193 self.data()
194 .notify_error_listeners(self, line, column, message, error);
195 }
196
197 fn sempred(&mut self, _rule_index: usize, _pred_index: usize) -> bool {
198 true
199 }
200
201 fn action(&mut self, _rule_index: usize, _action_index: usize) {}
202}
203
204#[cfg(test)]
205#[allow(clippy::disallowed_methods)] mod tests {
207 use super::*;
208
209 #[derive(Clone, Debug, Eq, PartialEq)]
210 struct RecordedError {
211 grammar_file_name: String,
212 line: usize,
213 column: usize,
214 message: String,
215 error: Option<AntlrError>,
216 }
217
218 #[derive(Clone, Debug)]
219 struct RecordingErrorListener {
220 errors: Arc<Mutex<Vec<RecordedError>>>,
221 }
222
223 impl<R> ErrorListener<R> for RecordingErrorListener
224 where
225 R: Recognizer + ?Sized,
226 {
227 fn syntax_error(
228 &mut self,
229 recognizer: &R,
230 line: usize,
231 column: usize,
232 message: &str,
233 error: Option<&AntlrError>,
234 ) {
235 self.errors
236 .lock()
237 .expect("recorded errors lock")
238 .push(RecordedError {
239 grammar_file_name: recognizer.grammar_file_name().to_owned(),
240 line,
241 column,
242 message: message.to_owned(),
243 error: error.cloned(),
244 });
245 }
246 }
247
248 #[derive(Clone, Debug)]
249 struct TestRecognizer {
250 data: RecognizerData,
251 }
252
253 impl Recognizer for TestRecognizer {
254 fn data(&self) -> &RecognizerData {
255 &self.data
256 }
257
258 fn data_mut(&mut self) -> &mut RecognizerData {
259 &mut self.data
260 }
261 }
262
263 fn test_recognizer() -> TestRecognizer {
264 TestRecognizer {
265 data: RecognizerData::new(
266 "Test.g4",
267 Vocabulary::new(
268 std::iter::empty::<Option<&str>>(),
269 std::iter::empty::<Option<&str>>(),
270 std::iter::empty::<Option<&str>>(),
271 ),
272 ),
273 }
274 }
275
276 #[test]
277 fn recognizers_replace_the_default_console_error_listener() {
278 let mut recognizer = test_recognizer();
279 assert_eq!(recognizer.data.error_listeners.len(), 1);
280
281 recognizer.remove_error_listeners();
282 assert!(recognizer.data.error_listeners.is_empty());
283
284 let errors = Arc::new(Mutex::new(Vec::new()));
285 recognizer.add_error_listener(RecordingErrorListener {
286 errors: Arc::clone(&errors),
287 });
288 let error = AntlrError::ParserError {
289 line: 3,
290 column: 5,
291 message: "unexpected token".to_owned(),
292 };
293 recognizer.notify_error_listeners(3, 5, "unexpected token", Some(&error));
294
295 insta::assert_debug_snapshot!(
296 "recognizers_replace_the_default_console_error_listener",
297 *errors.lock().expect("recorded errors lock")
298 );
299 }
300
301 #[test]
302 fn recognizer_data_remains_send_and_sync() {
303 fn assert_send_and_sync<T: Send + Sync>() {}
304
305 assert_send_and_sync::<RecognizerData>();
306 }
307
308 #[test]
309 fn cloned_recognizers_can_reconfigure_their_listener_lists_independently() {
310 let mut original = test_recognizer();
311 let clone = original.clone();
312
313 original.remove_error_listeners();
314
315 assert!(original.data.error_listeners.is_empty());
316 assert_eq!(clone.data.error_listeners.len(), 1);
317 }
318}