Skip to main content

antlr4_runtime/
generated.rs

1use std::sync::{Arc, OnceLock};
2
3use crate::atn::parser_atn::ParserAtn;
4use crate::atn::serialized::SerializedAtn;
5use crate::recognizer::{RecognizerData, RecognizerMetadata};
6use crate::vocabulary::Vocabulary;
7
8#[derive(Debug)]
9pub struct GrammarMetadata {
10    grammar_file_name: &'static str,
11    rule_names: &'static [&'static str],
12    literal_names: &'static [Option<&'static str>],
13    symbolic_names: &'static [Option<&'static str>],
14    display_names: &'static [Option<&'static str>],
15    channel_names: &'static [&'static str],
16    mode_names: &'static [&'static str],
17    serialized_atn: &'static [i32],
18    recognizer_metadata: OnceLock<Arc<RecognizerMetadata>>,
19}
20
21impl Clone for GrammarMetadata {
22    fn clone(&self) -> Self {
23        Self {
24            grammar_file_name: self.grammar_file_name,
25            rule_names: self.rule_names,
26            literal_names: self.literal_names,
27            symbolic_names: self.symbolic_names,
28            display_names: self.display_names,
29            channel_names: self.channel_names,
30            mode_names: self.mode_names,
31            serialized_atn: self.serialized_atn,
32            recognizer_metadata: OnceLock::from(Arc::clone(self.cached_recognizer_metadata())),
33        }
34    }
35}
36
37impl GrammarMetadata {
38    /// Creates static grammar metadata emitted by the Rust target generator.
39    #[allow(clippy::too_many_arguments)]
40    pub const fn new(
41        grammar_file_name: &'static str,
42        rule_names: &'static [&'static str],
43        literal_names: &'static [Option<&'static str>],
44        symbolic_names: &'static [Option<&'static str>],
45        display_names: &'static [Option<&'static str>],
46        channel_names: &'static [&'static str],
47        mode_names: &'static [&'static str],
48        serialized_atn: &'static [i32],
49    ) -> Self {
50        Self {
51            grammar_file_name,
52            rule_names,
53            literal_names,
54            symbolic_names,
55            display_names,
56            channel_names,
57            mode_names,
58            serialized_atn,
59            recognizer_metadata: OnceLock::new(),
60        }
61    }
62
63    pub const fn grammar_file_name(&self) -> &'static str {
64        self.grammar_file_name
65    }
66
67    pub const fn rule_names(&self) -> &'static [&'static str] {
68        self.rule_names
69    }
70
71    pub const fn channel_names(&self) -> &'static [&'static str] {
72        self.channel_names
73    }
74
75    pub const fn mode_names(&self) -> &'static [&'static str] {
76        self.mode_names
77    }
78
79    pub fn vocabulary(&self) -> Vocabulary {
80        Vocabulary::new(
81            self.literal_names.iter().copied(),
82            self.symbolic_names.iter().copied(),
83            self.display_names.iter().copied(),
84        )
85    }
86
87    /// Creates per-instance recognizer state backed by this grammar's cached
88    /// immutable metadata.
89    pub fn recognizer_data(&self) -> RecognizerData {
90        RecognizerData::from_shared(Arc::clone(self.cached_recognizer_metadata()))
91    }
92
93    fn cached_recognizer_metadata(&self) -> &Arc<RecognizerMetadata> {
94        self.recognizer_metadata.get_or_init(|| {
95            Arc::new(RecognizerMetadata::from_static(
96                self.grammar_file_name,
97                self.rule_names,
98                self.channel_names,
99                self.mode_names,
100                self.vocabulary(),
101            ))
102        })
103    }
104
105    /// Borrows the serialized ATN values for deserialization by the runtime
106    /// simulators without copying generated static data.
107    pub const fn serialized_atn(&self) -> SerializedAtn<'_> {
108        SerializedAtn::from_i32(self.serialized_atn)
109    }
110}
111
112pub trait GeneratedLexer {
113    fn metadata() -> &'static GrammarMetadata;
114}
115
116pub trait GeneratedParser {
117    fn metadata() -> &'static GrammarMetadata;
118
119    /// Borrows the validated packed ATN embedded by the matching generator.
120    fn parser_atn() -> &'static ParserAtn;
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    static META: GrammarMetadata = GrammarMetadata::new(
128        "Mini.g4",
129        &["file"],
130        &[None, Some("'x'")],
131        &[None, Some("X")],
132        &[None, None],
133        &["DEFAULT_TOKEN_CHANNEL", "HIDDEN"],
134        &["DEFAULT_MODE"],
135        &[4, 1, 1, 0, 0, 0],
136    );
137
138    #[test]
139    fn metadata_builds_vocabulary() {
140        assert_eq!(META.grammar_file_name(), "Mini.g4");
141        assert_eq!(META.vocabulary().display_name(1), "'x'");
142    }
143
144    #[test]
145    fn cloned_metadata_shares_the_cache_before_explicit_initialization() {
146        let original = GrammarMetadata::new(
147            "Clone.g4",
148            &["start"],
149            &[None, Some("'x'")],
150            &[None, Some("X")],
151            &[None, None],
152            &["DEFAULT_TOKEN_CHANNEL"],
153            &["DEFAULT_MODE"],
154            &[],
155        );
156        let cloned = original.clone();
157        let first = original.recognizer_data();
158        let second = cloned.recognizer_data();
159
160        assert!(std::ptr::eq(first.rule_names(), second.rule_names()));
161        assert!(std::ptr::eq(first.vocabulary(), second.vocabulary()));
162    }
163}