1use crate::hashgen::*;
24use multimap::MultiMap;
25
26pub type HistoricalFlag = i32;
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct DCKeyword {
33 name: String,
34 historical_flag: HistoricalFlag,
37}
38
39impl From<interim::DCKeyword> for DCKeyword {
40 fn from(value: interim::DCKeyword) -> Self {
41 Self {
42 name: value.name,
43 historical_flag: value.historical_flag,
44 }
45 }
46}
47
48impl std::fmt::Display for DCKeyword {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 write!(f, "keyword ")?;
51 f.write_str(&self.name)?;
52 writeln!(f, ";")
53 }
54}
55
56impl LegacyDCHash for DCKeyword {
57 fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
58 hashgen.add_string(self.name.clone());
59 }
60}
61
62impl DCKeyword {
63 #[inline]
64 pub fn get_name(&self) -> String {
65 self.name.clone()
66 }
67
68 #[inline]
69 pub fn get_historical_flag(&self) -> HistoricalFlag {
70 self.historical_flag
71 }
72}
73
74pub type KeywordName2Keyword<'dc> = MultiMap<String, &'dc DCKeyword>;
76
77pub enum IdentifyKeyword {
81 ByStruct(DCKeyword),
82 ByName(String),
83}
84
85#[derive(Debug)]
88pub struct DCKeywordList<'dc> {
89 keywords: Vec<&'dc DCKeyword>,
90 kw_name_2_keyword: KeywordName2Keyword<'dc>,
91 flags: HistoricalFlag,
92}
93
94impl std::cmp::PartialEq for DCKeywordList<'_> {
95 fn eq(&self, other: &Self) -> bool {
96 let target_kw_map: KeywordName2Keyword = other._get_keywords_by_name_map();
97
98 if self.kw_name_2_keyword.len() != target_kw_map.len() {
100 return false;
101 }
102
103 for key in self.kw_name_2_keyword.keys() {
106 if !target_kw_map.contains_key(key) {
107 return false;
108 }
109 }
110 true }
112}
113
114impl std::fmt::Display for DCKeywordList<'_> {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 for (i, kw) in self.keywords.iter().enumerate() {
117 f.write_str(&kw.name)?;
121
122 if i != self.keywords.len() - 1 {
123 write!(f, " ")?;
124 }
125 }
126 writeln!(f, ";")
127 }
128}
129
130impl LegacyDCHash for DCKeywordList<'_> {
131 fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
132 if self.flags != !0 {
133 hashgen.add_int(self.flags);
136 } else {
137 hashgen.add_int(self.keywords.len().try_into().unwrap());
138
139 for keyword in &self.keywords {
140 keyword.generate_hash(hashgen);
141 }
142 }
143 }
144}
145
146impl<'dc> DCKeywordList<'dc> {
147 pub fn get_num_keywords(&self) -> usize {
149 self.keywords.len()
150 }
151
152 pub fn has_keyword(&self, kw: IdentifyKeyword) -> bool {
155 match kw {
156 IdentifyKeyword::ByName(kw_id) => self.get_keyword_by_name(kw_id).is_some(),
157 IdentifyKeyword::ByStruct(kw_obj) => {
158 for keyword in &self.keywords {
159 if **keyword == kw_obj {
160 return true;
161 }
162 }
163 false }
165 }
166 }
167
168 pub fn get_keyword(&self, index: usize) -> Option<&'dc DCKeyword> {
170 self.keywords.get(index).copied()
171 }
172
173 pub fn get_keyword_by_name(&self, name: String) -> Option<&'dc DCKeyword> {
175 self.kw_name_2_keyword.get(&name).copied()
176 }
177
178 pub fn _get_keywords_by_name_map(&self) -> KeywordName2Keyword {
180 self.kw_name_2_keyword.clone()
181 }
182}
183
184pub(crate) mod interim {
187 use super::HistoricalFlag;
188 use crate::parser::ast;
189 use crate::parser::lexer::Span;
190 use multimap::MultiMap;
191 use std::rc::Rc;
192
193 #[derive(Debug)]
194 pub struct DCKeyword {
195 pub span: Span,
196 pub name: String,
197 pub historical_flag: HistoricalFlag,
198 }
199
200 impl From<ast::KeywordDefinition> for DCKeyword {
201 fn from(value: ast::KeywordDefinition) -> Self {
202 Self {
203 span: value.span,
204 name: value.identifier,
205 historical_flag: {
206 if value.historical {
207 !0
211 } else {
212 0
213 }
214 },
215 }
216 }
217 }
218
219 #[derive(Debug)]
220 pub struct DCKeywordList {
221 pub keywords: Vec<Rc<DCKeyword>>,
222 pub kw_name_2_keyword: MultiMap<String, Rc<DCKeyword>>,
223 pub flags: HistoricalFlag,
224 }
225
226 impl Default for DCKeywordList {
227 fn default() -> Self {
228 Self {
229 keywords: vec![],
230 kw_name_2_keyword: MultiMap::new(),
231 flags: 0_i32,
235 }
236 }
237 }
238
239 impl DCKeywordList {
240 pub fn add_keyword(&mut self, keyword: DCKeyword) -> Result<(), ()> {
241 let kw_name: String = keyword.name.clone(); if self.kw_name_2_keyword.get(&kw_name).is_some() {
244 return Err(()); }
246
247 self.flags |= keyword.historical_flag;
249
250 self.keywords.push(Rc::new(keyword));
251 self.kw_name_2_keyword
252 .insert(kw_name, self.keywords.last().unwrap().clone());
253 Ok(())
254 }
255
256 pub fn copy_keywords(&mut self, target: &DCKeywordList) {
258 let target_kw_array: Vec<Rc<DCKeyword>> = target._get_keyword_list();
259 let target_kw_map: MultiMap<String, Rc<DCKeyword>> = target._get_keywords_by_name_map();
260
261 self.keywords = target_kw_array; self.kw_name_2_keyword = target_kw_map;
263 }
264
265 pub fn _get_keyword_list(&self) -> Vec<Rc<DCKeyword>> {
267 self.keywords.clone()
268 }
269
270 pub fn _get_keywords_by_name_map(&self) -> MultiMap<String, Rc<DCKeyword>> {
272 self.kw_name_2_keyword.clone()
273 }
274
275 pub fn clear_keywords(&mut self) {
278 self.keywords.clear();
279 self.kw_name_2_keyword.clear();
280 self.flags = 0_i32;
281 }
282 }
283}