1pub mod error;
2pub mod overlay_registry;
3pub mod validator;
4
5use self::error::ParseError;
6use self::validator::OverlayfileValidator;
7
8use log::debug;
9use pest::Parser;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(pest_derive::Parser)]
14#[grammar = "overlay.pest"]
15struct OverlayParser;
16
17pub type Pair<'a> = pest::iterators::Pair<'a, Rule>;
18
19#[derive(Debug, Clone)]
20pub struct OverlayFile {
21 pub overlays_def: Vec<OverlayDef>,
22 pub meta: HashMap<String, String>,
23}
24
25impl OverlayFile {
26 pub fn new() -> Self {
27 OverlayFile {
28 overlays_def: Vec::new(),
29 meta: HashMap::new(),
30 }
31 }
32}
33
34impl Default for OverlayFile {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40#[derive(Hash, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
41pub struct OverlayDef {
42 pub namespace: Option<String>,
43 pub name: String,
44 pub version: String,
45 #[serde(default, skip_serializing_if = "Vec::is_empty")]
46 pub unique_keys: Vec<String>,
47 pub elements: Vec<OverlayElementDef>,
49}
50
51impl Default for OverlayDef {
52 fn default() -> Self {
53 OverlayDef {
54 namespace: None,
55 name: String::new(),
56 version: "1.0.0".to_string(),
57 unique_keys: Vec::new(),
58 elements: Vec::new(),
59 }
60 }
61}
62
63impl OverlayDef {
64 pub fn get_attr_elements(&self) -> Vec<String> {
66 self.elements
67 .iter()
68 .filter(|el| el.keys == KeyType::AttrNames)
69 .map(|el| el.name.clone())
70 .collect()
71 }
72 pub fn get_ordered_element_names(&self) -> Vec<String> {
74 self.elements.iter().map(|el| el.name.clone()).collect()
75 }
76 pub fn get_full_name(&self) -> String {
77 if let Some(namespace) = self.namespace.as_ref() {
78 format!(
79 "{}:{}/{}",
80 &namespace,
81 self.name,
82 self.version
83 )
84 } else {
85 format!("{}/{}", self.name, self.version)
86 }
87 }
88 pub fn get_name(&self) -> &str {
89 &self.name
90 }
91}
92
93#[derive(Debug, Clone, Eq, PartialEq)]
94pub struct KeyPair {
95 pub name: String,
96 pub kind: ElementType,
97}
98
99#[derive(Hash, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
100pub struct OverlayElementDef {
101 pub name: String,
102 pub keys: KeyType,
103 pub values: ElementType,
104}
105
106#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
107pub enum KeyType {
109 AttrNames,
111 Text,
113 None,
115}
116
117#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
118pub enum ElementType {
120 Object(Option<Box<OverlayElementDef>>),
121 Array(Option<Vec<ConstraintKind>>),
122 Binary,
123 Text,
124 Lang,
126 Ref,
128 Complex(Vec<ElementType>),
129 Any,
131}
132
133#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
134pub enum ConstraintKind {
135 Closed(Option<Vec<String>>),
137 Open(Option<Vec<String>>),
139 None,
141}
142
143#[derive(Debug)]
144pub struct FieldConstraint {
145 pub name: String,
146 pub required: bool,
147}
148
149pub fn parse_from_string(unparsed_file: String) -> Result<OverlayFile, ParseError> {
150 let file = OverlayParser::parse(Rule::file, &unparsed_file)
151 .map_err(|e| {
152 let (line_number, column_number) = match e.line_col {
153 pest::error::LineColLocation::Pos((line, column)) => (line, column),
154 pest::error::LineColLocation::Span((line, column), _) => (line, column),
155 };
156 ParseError::GrammarError {
157 line_number,
158 column_number,
159 raw_line: e.line().to_string(),
160 message: e.variant.to_string(),
161 }
162 })?
163 .next()
164 .unwrap();
165
166 let mut overlays_file = OverlayFile::new();
167
168 for line in file.into_inner() {
171 if let Rule::EOI = line.as_rule() {
172 continue;
173 }
174 if let Rule::comment = line.as_rule() {
175 continue;
176 }
177 if let Rule::meta_comment = line.as_rule() {
178 let mut key = "".to_string();
179 let mut value = "".to_string();
180 for attr in line.into_inner() {
181 match attr.as_rule() {
182 Rule::meta_attr_key => {
183 key = attr.as_str().to_string();
184 }
185 Rule::meta_attr_value => {
186 value = attr.as_str().to_string();
187 }
188 _ => {
189 return Err(ParseError::MetaError(attr.as_str().to_string()));
190 }
191 }
192 }
193 if key.is_empty() {
194 return Err(ParseError::MetaError("key is empty".to_string()));
195 }
196 if value.is_empty() {
197 return Err(ParseError::MetaError("value is empty".to_string()));
198 }
199 overlays_file.meta.insert(key, value);
200 continue;
201 }
202 if let Rule::overlay_block = line.as_rule() {
203 let mut overlay_def = OverlayDef {
204 namespace: None,
205 name: "".to_string(),
206 version: "".to_string(),
207 unique_keys: Vec::new(),
208 elements: Vec::new(),
209 };
210 for attr in line.into_inner() {
211 match attr.as_rule() {
212 Rule::overlay_name => {
213 let (namespace, name): (Option<String>, String) =
214 match attr.as_str().split_once(':') {
215 Some((ns, n)) if !ns.is_empty() => {
216 (Some(ns.to_string()), n.to_string())
217 }
218 Some((_, n)) => (None, n.to_string()),
219 None => (None, attr.as_str().to_string()),
220 };
221 match namespace {
222 Some(ns) => {
223 overlay_def.namespace = Some(ns.to_lowercase());
224 }
225 None => {
226 overlay_def.namespace = None;
227 }
228 };
229 overlay_def.name = name.to_lowercase();
230 }
231 Rule::version => {
232 overlay_def.version = attr.as_str().to_string();
233 }
234 Rule::unique_keys_command => {
235 overlay_def.unique_keys = parse_unique_keys_command(attr);
236 }
237 Rule::overlay_object => {
238 let mut name: Option<String> = None;
239 let mut keys_type: Option<KeyType> = None;
240 let mut values_type: Option<ElementType> = None;
241 debug!("Parsing overlay object: {:?}", attr);
242
243 for e in attr.into_inner() {
244 match e.as_rule() {
245 Rule::overlay_object_header => {
246 e.into_inner().for_each(|header| match header.as_rule() {
247 Rule::attr_name => {
248 name = Some(header.as_str().to_string());
249 }
250 _ => {
251 panic!(
252 "Missing name for an object: {:?}",
253 header.as_rule()
254 )
255 }
256 });
257 }
258 Rule::overlay_object_body => {
259 (keys_type, values_type) = parse_object_body(e)?;
260 }
261 _ => {}
262 }
263 }
264 let overlay_element = OverlayElementDef {
265 name: name.clone().unwrap_or_default(),
266 keys: keys_type.clone().unwrap_or(KeyType::Text),
267 values: values_type.clone().unwrap_or(ElementType::Object(None)),
268 };
269 overlay_def.elements.push(overlay_element);
270 }
271 Rule::overlay_attributes => {
272 let attrs = process_overlay_attributes(attr);
273 overlay_def.elements.extend(attrs);
274 }
275 Rule::overlay_array => {
276 let mut name: Option<String> = None;
277 let mut values: Option<ElementType> = None;
278 debug!("Parsing overlay array: {:?}", attr);
279 for a in attr.into_inner() {
280 debug!("Parsing overlay array element: {:?}", a);
281 match a.as_rule() {
282 Rule::overlay_array_header => {
283 for header_item in a.into_inner() {
284 if let Rule::attr_name = header_item.as_rule() {
285 name = Some(header_item.as_str().to_string());
286 }
287 }
288 }
289 Rule::overlay_array_body => {
290 for body_item in a.into_inner() {
291 if let Rule::value_type = body_item.as_rule() {
292 match body_item.into_inner().next() {
293 Some(v) => match v.as_rule() {
294 Rule::array_type => {
295 values = Some(ElementType::Array(None));
296 }
297 Rule::TEXT_TYPE => {
298 values = Some(ElementType::Text);
299 }
300 Rule::REF_TYPE => {
301 values = Some(ElementType::Ref);
302 }
303 Rule::LANG_TYPE => {
304 values = Some(ElementType::Lang);
305 }
306 Rule::ANY_TYPE => {
307 values = Some(ElementType::Any);
308 }
309 _ => continue,
310 },
311 None => {
312 return Err(ParseError::MetaError(
313 "value type is empty".to_string(),
314 ));
315 }
316 }
317 }
318 }
319 }
320 _ => continue,
321 }
322 }
323 let overlay_element = OverlayElementDef {
324 name: name.clone().unwrap_or_default(),
325 keys: KeyType::Text,
326 values: values.clone().unwrap_or(ElementType::Array(None)),
327 };
328 overlay_def.elements.push(overlay_element);
329 }
330 _ => {}
331 }
332 }
333 overlays_file.overlays_def.push(overlay_def);
334 continue;
335 }
336 if let Rule::empty_line = line.as_rule() {
337 continue;
338 }
339 }
340
341 let overlays_file = OverlayFile {
342 overlays_def: overlays_file.overlays_def,
343 meta: overlays_file.meta,
344 };
345
346 match OverlayfileValidator::validate(&overlays_file) {
348 Ok(_) => Ok(overlays_file),
349 Err(validation_errors) => Err(ParseError::ValidationError(validation_errors)),
350 }
351}
352
353fn parse_unique_keys_command(cmd: Pair) -> Vec<String> {
354 fn collect_attr_names(pair: Pair, out: &mut Vec<String>) {
355 for inner in pair.into_inner() {
356 if let Rule::attr_name = inner.as_rule() {
357 out.push(inner.as_str().to_string());
358 } else {
359 collect_attr_names(inner, out);
360 }
361 }
362 }
363
364 let mut keys = Vec::new();
365 collect_attr_names(cmd, &mut keys);
366 keys
367}
368
369fn process_overlay_attributes(attr: Pair) -> Vec<OverlayElementDef> {
370 debug!("Parsing overlay attribute: {:?}", attr);
371 let mut elements = Vec::new();
372 for a in attr.into_inner() {
373 match a.as_rule() {
374 Rule::key_pair => {
375 let element = process_key_pair(a);
376 debug!("-------- Found element {:?}", element);
377 elements.push(element);
378 }
379 Rule::ATTR_ARRAY => {
380 let result = process_attributes_array(a);
381 elements.extend(result);
382 }
383 _ => unreachable!(),
384 }
385 }
386 elements
387}
388
389fn parse_object_body(
390 object_body: Pair,
391) -> Result<(Option<KeyType>, Option<ElementType>), ParseError> {
392 let mut keys_type: Option<KeyType> = None;
393 let mut values_type: Option<ElementType> = None;
394
395 for key in object_body.into_inner() {
396 match key.as_rule() {
397 Rule::key_type => match key.into_inner().next() {
398 Some(k) => match k.as_rule() {
399 Rule::ATTR_NAMES_TYPE => keys_type = Some(KeyType::AttrNames),
400 Rule::TEXT_TYPE => keys_type = Some(KeyType::Text),
401 Rule::ARRAY_KEY_TYPE => todo!(),
402 _ => continue,
403 },
404 None => {
405 return Err(ParseError::MetaError("key type is empty".to_string()));
406 }
407 },
408 Rule::value_type => match key.into_inner().next() {
409 Some(k) => match k.as_rule() {
410 Rule::object_type => {
411 let (nested_keys, nested_values) =
412 parse_object_body(k.into_inner().next().unwrap())?;
413 let nested_def = OverlayElementDef {
414 name: "".to_string(), keys: nested_keys.unwrap_or(KeyType::Text),
416 values: nested_values.unwrap_or(ElementType::Any),
417 };
418 values_type = Some(ElementType::Object(Some(Box::new(nested_def))));
419 }
420 Rule::array_type => {
421 todo!()
422 }
423 Rule::TEXT_TYPE => {
424 values_type = Some(ElementType::Text);
425 }
426 Rule::REF_TYPE => {
427 values_type = Some(ElementType::Ref);
428 }
429 Rule::LANG_TYPE => {
430 values_type = Some(ElementType::Lang);
431 }
432 Rule::ANY_TYPE => {
433 values_type = Some(ElementType::Any);
434 }
435 Rule::complex_value_type => {
436 let mut complex_types = Vec::new();
437 for complex_type in k.into_inner() {
438 match complex_type.as_rule() {
439 Rule::array_type => complex_types.push(ElementType::Array(None)),
440 Rule::object_type => {
441 let (nested_keys, nested_values) = parse_object_body(
442 complex_type.into_inner().next().unwrap(),
443 )?;
444 let nested_def = OverlayElementDef {
445 name: "".to_string(),
446 keys: nested_keys.unwrap_or(KeyType::Text),
447 values: nested_values.unwrap_or(ElementType::Any),
448 };
449 complex_types
450 .push(ElementType::Object(Some(Box::new(nested_def))));
451 }
452 Rule::REF_TYPE => complex_types.push(ElementType::Ref),
453 Rule::TEXT_TYPE => complex_types.push(ElementType::Text),
454 Rule::LANG_TYPE => complex_types.push(ElementType::Lang),
455 _ => {}
456 }
457 }
458 values_type = Some(ElementType::Complex(complex_types));
459 }
460 _ => {
461 todo!("Value type not supported yet: {:?}", k)
462 }
463 },
464 None => {
465 return Err(ParseError::MetaError("value type is empty".to_string()));
466 }
467 },
468 _ => continue,
469 };
470 }
471 Ok((keys_type, values_type))
472}
473
474fn process_attributes_array(attr: Pair) -> Vec<OverlayElementDef> {
475 let mut attributes: Vec<OverlayElementDef> = Vec::new();
476 for array in attr.into_inner() {
478 match array.as_rule() {
479 Rule::ARRAY_KEY_TYPE => {
480 for item in array.into_inner() {
481 match item.as_rule() {
482 Rule::array_content => {
483 let mut items = Vec::new();
484 let mut has_ellipsis = false;
485 debug!("Parsing array items: {:?}", item);
486
487 for content in item.into_inner() {
488 match content.as_rule() {
489 Rule::array_items => {
490 for item in content.into_inner() {
491 if let Rule::key_item = item.as_rule() {
492 items.push(item.as_str().to_string());
493 }
494 }
495 }
496 Rule::trailing_ellipsis => {
497 has_ellipsis = true;
498 }
499 _ => {
500 panic!(
501 "Unexpected rule in array content: {:?}",
502 content.as_rule()
503 );
504 }
505 }
506 }
507
508 for i in items {
509 attributes.push(OverlayElementDef {
510 name: i.clone(),
511 keys: KeyType::None,
512 values: ElementType::Text, });
514 }
515 if has_ellipsis {
517 attributes.push(OverlayElementDef {
518 name: "".to_string(),
519 keys: KeyType::None,
520 values: ElementType::Text,
521 });
522 }
523 }
524 _ => {
525 debug!("Unexpected rule in array type: {:?}", item.as_rule());
526 }
527 }
528 }
529 }
530 Rule::keys_with_values => {
531 debug!("Parsing overlay array with values: {:?}", array);
532 for el in array.into_inner() {
533 match el.as_rule() {
534 Rule::value_type => {
535 debug!("process value type for attribute array");
536 let mut value_type = ElementType::Text;
537 match el.as_str().to_lowercase().as_str() {
538 "text" => value_type = ElementType::Text,
539 "ref" => value_type = ElementType::Ref,
540 "binary" => value_type = ElementType::Binary,
541 "array" => value_type = ElementType::Array(None),
542 "lang" => value_type = ElementType::Lang,
543 "any" => value_type = ElementType::Any,
544 _ => {}
545 }
546 for attribute in &mut attributes {
547 attribute.values = value_type.clone();
548 }
549 }
550 _ => unreachable!(),
551 }
552 }
553 }
554 _ => unreachable!(),
555 }
556 }
557 attributes
558}
559
560fn process_key_pair(pair: Pair) -> OverlayElementDef {
561 let mut key_pair = KeyPair {
562 name: "".to_string(),
563 kind: ElementType::Text,
564 };
565 pair.into_inner().for_each(|kp| match kp.as_rule() {
566 Rule::attr_name => {
567 key_pair.name = kp.as_str().to_string();
568 }
569 Rule::attr_value_type => match kp.as_str() {
570 "Text" => key_pair.kind = ElementType::Text,
571 "Ref" => key_pair.kind = ElementType::Ref,
572 "Binary" => key_pair.kind = ElementType::Binary,
573 "Array" => key_pair.kind = ElementType::Array(None),
574 "Lang" => key_pair.kind = ElementType::Lang,
575 _ => {}
576 },
577 _ => {
578 panic!("Incorrect key pair for attribute: {:?}", kp.as_rule())
579 }
580 });
581
582 OverlayElementDef {
583 name: key_pair.name.clone(),
584 keys: KeyType::Text,
585 values: key_pair.kind.clone(),
586 }
587}
588
589#[cfg(test)]
590mod tests {
591 use super::*;
592
593 #[test]
594 fn test_overlay_name() {
595 let input = r#"
596ADD OVERLAY ReferenceValues
597 VERSION 1.0.0
598 ADD OBJECT attribute_reference_values
599 WITH KEYS attr-names
600 WITH VALUES Text
601"#;
602 let result = parse_from_string(input.to_string()).unwrap();
603 let overlay = result.overlays_def.first().unwrap();
604 assert_eq!(overlay.name, "referencevalues");
605 assert_eq!(overlay.namespace, None);
606
607 let input = r#"
608ADD OVERLAY :ReferenceValues
609 VERSION 1.0.0
610 ADD OBJECT attribute_reference_values
611 WITH KEYS attr-names
612 WITH VALUES Text"#;
613 let result = parse_from_string(input.to_string()).unwrap();
614 let overlay = result.overlays_def.first().unwrap();
615 assert_eq!(overlay.name, "referencevalues");
616 assert_eq!(overlay.namespace, None);
617
618 let input = r#"
619ADD OVERLAY hcf:ReferenceValues
620 VERSION 1.0.0
621 ADD OBJECT attribute_reference_values
622 WITH KEYS attr-names
623 WITH VALUES Text
624"#;
625 let result = parse_from_string(input.to_string()).unwrap();
626 let overlay = result.overlays_def.first().unwrap();
627 assert_eq!(overlay.name, "referencevalues");
628 assert_eq!(overlay.namespace.clone().unwrap(), "hcf".to_string());
629 }
630 #[test]
631 fn test_parsing_overlayfile() {
632 let input = r#"
633--name=HCF
634# Create new overlay
635ADD OVERLAY ReferenceValues
636 VERSION 1.0.1
637 UNIQUE KEYS [language, region]
638 ADD ATTRIBUTES language=Lang
639 ADD ATTRIBUTES region=Text
640 ADD OBJECT attribute_reference_values
641 WITH KEYS attr-names
642 WITH VALUES OBJECT
643 WITH KEYS Text
644 WITH VALUES Text
645
646ADD OVERLAY hcf:Information
647 VERSION 1.2.2
648 ADD ATTRIBUTES language=Lang
649 ADD OBJECT attr
650 WITH KEYS Text
651 WITH VALUES Text
652 ADD OBJECT attribute_information
653 WITH KEYS attr-names
654 WITH VALUES Text
655
656ADD OVERLAY hcf:Meta
657 VERSION 1.2.2
658 ADD ATTRIBUTES language=Lang photo=Binary
659 ADD ATTRIBUTES [name, description]
660 WITH VALUES TEXT
661 ADD ATTRIBUTES [...]
662 WITH VALUES ANY
663
664ADD OVERLAY ENTRY
665 VERSION 1.2.2
666 ADD ATTRIBUTES language=Lang
667 ADD OBJECT attr_entries
668 with keys attr-names
669 with values Object
670 with keys Text
671 with values Object
672 with keys Text
673 with values Any
674
675ADD OVERLAY hcf:EntryCodeMapping
676 VERSION 1.0.0
677 ADD ARRAY attr_entry_codes_mapping
678 WITH VALUES Text
679
680"#;
681
682 let result = parse_from_string(input.to_string()).unwrap();
683
684 let ref_overlay = result.overlays_def.first().unwrap();
685 let information = result.overlays_def.get(1).unwrap();
686 let meta = result.overlays_def.get(2).unwrap();
687 let entry = result.overlays_def.get(3).unwrap();
688 let entry_code_mapping = result.overlays_def.get(4).unwrap();
689 assert_eq!(result.overlays_def.len(), 5);
690 assert_eq!(ref_overlay.name, "referencevalues");
691 assert_eq!(ref_overlay.version, "1.0.1");
692 assert_eq!(ref_overlay.namespace, None);
693 assert_eq!(ref_overlay.unique_keys, vec!["language", "region"]);
694 assert_eq!(ref_overlay.elements.len(), 3);
695 assert_eq!(ref_overlay.elements[0].name, "language");
696 assert_eq!(ref_overlay.elements[0].values, ElementType::Lang);
697 assert_eq!(ref_overlay.elements[1].name, "region");
698 assert_eq!(ref_overlay.elements[1].values, ElementType::Text);
699 let ref_element = ref_overlay
700 .elements
701 .iter()
702 .find(|e| e.name == "attribute_reference_values")
703 .unwrap();
704 assert_eq!(ref_element.keys, KeyType::AttrNames);
705 assert_eq!(
706 ref_element.values,
707 ElementType::Object(Some(Box::new(OverlayElementDef {
708 name: "".to_string(),
709 keys: KeyType::Text,
710 values: ElementType::Text
711 })))
712 );
713
714 assert_eq!(information.version, "1.2.2");
715 assert_eq!(information.namespace.clone().unwrap(), "hcf".to_string());
716 debug!(">>>> {:?}", information);
717 assert_eq!(information.elements[0].name, "language");
718 assert_eq!(information.elements[0].values, ElementType::Lang);
719 assert_eq!(information.elements[2].name, "attribute_information");
720 assert_eq!(information.elements.len(), 3);
721 assert_eq!(information.name, "information");
722
723 assert_eq!(meta.version, "1.2.2");
724 assert_eq!(meta.elements.len(), 5);
725 assert_eq!(
726 meta.elements
727 .iter()
728 .find(|e| e.name == "name")
729 .unwrap()
730 .values,
731 ElementType::Text
732 );
733 assert_eq!(meta.elements.first().unwrap().name, "language");
734 assert_eq!(meta.elements.first().unwrap().values, ElementType::Lang);
735 assert_eq!(meta.elements.get(2).unwrap().name, "name");
736 assert_eq!(meta.elements.get(2).unwrap().values, ElementType::Text);
737 assert_eq!(meta.elements.last().unwrap().name, "");
738 assert_eq!(meta.elements.last().unwrap().values, ElementType::Any);
739
740 assert_eq!(entry.version, "1.2.2");
741 assert_eq!(entry.elements.len(), 2);
742 assert_eq!(entry.elements[1].name, "attr_entries");
743 assert_eq!(
744 entry.elements[1].values,
745 ElementType::Object(Some(Box::new(OverlayElementDef {
746 name: "".to_string(),
747 keys: KeyType::Text,
748 values: ElementType::Object(Some(Box::new(OverlayElementDef {
749 name: "".to_string(),
750 keys: KeyType::Text,
751 values: ElementType::Any
752 })))
753 })))
754 );
755
756 assert_eq!(entry_code_mapping.name, "entrycodemapping");
757 assert_eq!(entry_code_mapping.version, "1.0.0");
758 assert_eq!(entry_code_mapping.elements.len(), 1);
759 assert_eq!(entry_code_mapping.elements[0].values, ElementType::Text);
760 }
761}