use std::collections::BTreeMap; use nom::bytes::complete::tag; use nom::bytes::complete::take_until; use nom::character::complete::anychar; use nom::combinator::all_consuming; use nom::combinator::eof; use nom::combinator::map; use nom::combinator::map_parser; use nom::combinator::opt; use nom::combinator::peek; use nom::combinator::recognize; use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; use super::object_parser::standard_set_object; use super::util::confine_context; use crate::context::parser_with_context; use crate::context::Context; use crate::context::ContextElement; use crate::context::GlobalSettings; use crate::context::List; use crate::types::AffiliatedKeywordValue; use crate::types::AffiliatedKeywords; use crate::types::Keyword; pub(crate) fn parse_affiliated_keywords<'g, 's, AK>( global_settings: &'g GlobalSettings<'g, 's>, input: AK, ) -> AffiliatedKeywords<'s> where AK: IntoIterator>, { let mut ret = BTreeMap::new(); for kw in input { let translated_name = translate_name(global_settings, kw.key); // if is_single_string_keyword(global_settings, translated_name.as_str()) { // ret.insert( // translated_name, // AffiliatedKeywordValue::SingleString(kw.value), // ); // } else if is_list_of_single_string_keyword(global_settings, translated_name.as_str()) { // let list_of_strings = ret // .entry(translated_name) // .or_insert_with(|| AffiliatedKeywordValue::ListOfStrings(Vec::with_capacity(1))); // match list_of_strings { // AffiliatedKeywordValue::ListOfStrings(list_of_strings) // if list_of_strings.is_empty() => // { // list_of_strings.push(kw.value); // } // AffiliatedKeywordValue::ListOfStrings(list_of_strings) => { // list_of_strings.clear(); // list_of_strings.push(kw.value); // } // _ => panic!("Invalid AffiliatedKeywordValue type."), // } // } else if is_list_of_objects_keyword(global_settings, translated_name.as_str()) { // let initial_context = ContextElement::document_context(); // let initial_context = Context::new(global_settings, List::new(&initial_context)); // let (_remaining, optional_objects) = opt(all_consuming(map( // tuple(( // take_until("["), // tag("["), // map_parser( // recognize(many_till(anychar, peek(tuple((tag("]"), eof))))), // confine_context(|i| { // all_consuming(many0(parser_with_context!(standard_set_object)( // &initial_context, // )))(i) // }), // ), // tag("]"), // eof, // )), // |(_, _, objects, _, _)| objects, // )))(kw.key.into()) // .expect("Object parser should always succeed."); // // TODO: This should be omitting footnote references // let (_remaining, objects) = all_consuming(many0(parser_with_context!( // standard_set_object // )(&initial_context)))(kw.value.into()) // .expect("Object parser should always succeed."); // let list_of_lists = ret.entry(translated_name).or_insert_with(|| { // AffiliatedKeywordValue::ListOfListsOfObjects(Vec::with_capacity(1)) // }); // match list_of_lists { // AffiliatedKeywordValue::ListOfListsOfObjects(list_of_lists) => { // list_of_lists.push((optional_objects, objects)); // } // _ => panic!("Invalid AffiliatedKeywordValue type."), // } // } else { // let list_of_strings = ret // .entry(translated_name) // .or_insert_with(|| AffiliatedKeywordValue::ListOfStrings(Vec::with_capacity(1))); // match list_of_strings { // AffiliatedKeywordValue::ListOfStrings(list_of_strings) => { // list_of_strings.push(kw.value); // } // _ => panic!("Invalid AffiliatedKeywordValue type."), // } // } } AffiliatedKeywords { keywords: ret } } fn translate_name<'g, 's>(global_settings: &'g GlobalSettings<'g, 's>, name: &'s str) -> String { let name_until_optval = name .split_once("[") .map(|(before, _after)| before) .unwrap_or(name); for (src, dst) in global_settings.element_keyword_translation_alist { if name_until_optval.eq_ignore_ascii_case(src) { return dst.to_lowercase(); } } name_until_optval.to_lowercase() } fn is_single_string_keyword<'g, 's>( _global_settings: &'g GlobalSettings<'g, 's>, name: &'s str, ) -> bool { // TODO: Is this defined by an elisp variable? for single_string_name in ["plot", "name"] { if name.eq_ignore_ascii_case(single_string_name) { return true; } } false } fn is_list_of_single_string_keyword<'g, 's>( _global_settings: &'g GlobalSettings<'g, 's>, name: &'s str, ) -> bool { // TODO: Is this defined by an elisp variable? for single_string_name in ["results"] { if name.eq_ignore_ascii_case(single_string_name) { return true; } } false } fn is_list_of_objects_keyword<'g, 's>( global_settings: &'g GlobalSettings<'g, 's>, name: &'s str, ) -> bool { for parsed_keyword in global_settings.element_parsed_keywords { if name.eq_ignore_ascii_case(parsed_keyword) { return true; } } false }