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)]
205mod tests {
206 use super::*;
207
208 #[derive(Clone, Debug, Eq, PartialEq)]
209 struct RecordedError {
210 grammar_file_name: String,
211 line: usize,
212 column: usize,
213 message: String,
214 error: Option<AntlrError>,
215 }
216
217 #[derive(Clone, Debug)]
218 struct RecordingErrorListener {
219 errors: Arc<Mutex<Vec<RecordedError>>>,
220 }
221
222 impl<R> ErrorListener<R> for RecordingErrorListener
223 where
224 R: Recognizer + ?Sized,
225 {
226 fn syntax_error(
227 &mut self,
228 recognizer: &R,
229 line: usize,
230 column: usize,
231 message: &str,
232 error: Option<&AntlrError>,
233 ) {
234 self.errors
235 .lock()
236 .expect("recorded errors lock")
237 .push(RecordedError {
238 grammar_file_name: recognizer.grammar_file_name().to_owned(),
239 line,
240 column,
241 message: message.to_owned(),
242 error: error.cloned(),
243 });
244 }
245 }
246
247 #[derive(Clone, Debug)]
248 struct TestRecognizer {
249 data: RecognizerData,
250 }
251
252 impl Recognizer for TestRecognizer {
253 fn data(&self) -> &RecognizerData {
254 &self.data
255 }
256
257 fn data_mut(&mut self) -> &mut RecognizerData {
258 &mut self.data
259 }
260 }
261
262 fn test_recognizer() -> TestRecognizer {
263 TestRecognizer {
264 data: RecognizerData::new(
265 "Test.g4",
266 Vocabulary::new(
267 std::iter::empty::<Option<&str>>(),
268 std::iter::empty::<Option<&str>>(),
269 std::iter::empty::<Option<&str>>(),
270 ),
271 ),
272 }
273 }
274
275 #[test]
276 fn recognizers_replace_the_default_console_error_listener() {
277 let mut recognizer = test_recognizer();
278 assert_eq!(recognizer.data.error_listeners.len(), 1);
279
280 recognizer.remove_error_listeners();
281 assert!(recognizer.data.error_listeners.is_empty());
282
283 let errors = Arc::new(Mutex::new(Vec::new()));
284 recognizer.add_error_listener(RecordingErrorListener {
285 errors: Arc::clone(&errors),
286 });
287 let error = AntlrError::ParserError {
288 line: 3,
289 column: 5,
290 message: "unexpected token".to_owned(),
291 };
292 recognizer.notify_error_listeners(3, 5, "unexpected token", Some(&error));
293
294 assert_eq!(
295 *errors.lock().expect("recorded errors lock"),
296 [RecordedError {
297 grammar_file_name: "Test.g4".to_owned(),
298 line: 3,
299 column: 5,
300 message: "unexpected token".to_owned(),
301 error: Some(error),
302 }]
303 );
304 }
305
306 #[test]
307 fn recognizer_data_remains_send_and_sync() {
308 fn assert_send_and_sync<T: Send + Sync>() {}
309
310 assert_send_and_sync::<RecognizerData>();
311 }
312
313 #[test]
314 fn cloned_recognizers_can_reconfigure_their_listener_lists_independently() {
315 let mut original = test_recognizer();
316 let clone = original.clone();
317
318 original.remove_error_listeners();
319
320 assert!(original.data.error_listeners.is_empty());
321 assert_eq!(clone.data.error_listeners.len(), 1);
322 }
323}