blob: e08ed015dbf483c481dd6d714db0ecb58d2fe781 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2024 Boeing
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Boeing - initial API and implementation
**********************************************************************/
use applicability::applic_tag::{ApplicabilityTag, ApplicabilityTagTypes};
use nom::{
branch::alt,
character::complete::line_ending,
combinator::{map, opt},
multi::many0,
sequence::tuple,
IResult,
};
use crate::applicability_parser_syntax_tag::{
ApplicabilitySyntaxTag, ApplicabilitySyntaxTagAnd, ApplicabilitySyntaxTagNot,
ApplicabilitySyntaxTagNotAnd, ApplicabilitySyntaxTagNotOr, ApplicabilitySyntaxTagOr,
};
use super::{
applicability_parser_syntax_tag::{ApplicabilityParserSyntaxTag, TagVariants},
config_group_text::{
else_config_group_text_parser, end_config_group_text_parser, not_config_group_text_parser,
start_config_group_text_parser,
},
end::end_tag_parser,
next::next_inner,
tag_parser::applicability_tag,
tag_parser::TokenSplit,
};
///
/// Parse End:
/// End Configuration
/// Line Ending
fn parse_end<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(
&'a str,
) -> IResult<
&str,
(
&str,
Vec<ApplicabilityParserSyntaxTag>,
(Option<&str>, Option<&str>),
),
> {
map(
tuple((
opt(end_config_group_parser(
custom_start_comment_syntax,
custom_end_comment_syntax,
)),
opt(line_ending),
)),
|s: (Option<&str>, Option<&str>)| (s.1.unwrap_or(""), vec![], s),
)
}
fn config_group_tag_parser<'a>(
starting_parser: impl FnMut(&'a str) -> IResult<&str, &str>,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<TokenSplit>> {
applicability_tag(starting_parser, end_tag_parser(custom_end_comment_syntax))
}
fn config_group_contents_parser<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
starting_parser: impl FnMut(&'a str) -> IResult<&str, &str>,
) -> impl FnMut(
&'a str,
) -> IResult<
&'a str,
(
Vec<TokenSplit>,
Option<&str>,
Vec<ApplicabilityParserSyntaxTag>,
),
> {
let tag_parser = config_group_tag_parser(starting_parser, custom_end_comment_syntax);
let content_parser =
parse_config_group_inner(custom_start_comment_syntax, custom_end_comment_syntax);
tuple((tag_parser, opt(line_ending), content_parser))
}
///
/// "Configuration Group Else"
/// Configuration Group Inner
/// Parse End
/// alt((Parse Else, Parse End))
fn else_parser<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(
&'a str,
) -> IResult<
&'a str,
(
&str,
Vec<ApplicabilityParserSyntaxTag>,
(Option<&str>, Option<&str>),
),
> {
let end_parser = tuple((
opt(end_config_group_parser(
custom_start_comment_syntax,
custom_end_comment_syntax,
)),
opt(line_ending),
));
tuple((
else_config_group_parser(custom_start_comment_syntax, custom_end_comment_syntax),
parse_config_group_inner(custom_start_comment_syntax, custom_end_comment_syntax),
//note the following parser is equivalent to parse_end...just not using parse_end to not cause type explosion
end_parser,
))
}
fn config_group_parser<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
starting_parser: impl FnMut(&'a str) -> IResult<&str, &str>,
) -> impl FnMut(
&'a str,
) -> IResult<
&'a str,
(
(
Vec<TokenSplit>,
Option<&str>,
Vec<ApplicabilityParserSyntaxTag>,
),
(
&'a str,
Vec<ApplicabilityParserSyntaxTag>,
(Option<&str>, Option<&str>),
),
),
> {
let parse_else_or_end = alt((
else_parser(custom_start_comment_syntax, custom_end_comment_syntax),
parse_end(custom_start_comment_syntax, custom_end_comment_syntax),
));
tuple((
config_group_contents_parser(
custom_start_comment_syntax,
custom_end_comment_syntax,
starting_parser,
),
parse_else_or_end,
))
}
pub fn parse_config_group<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(&'a str) -> IResult<&'a str, ApplicabilityParserSyntaxTag> {
let combined_parser = config_group_parser(
custom_start_comment_syntax,
custom_end_comment_syntax,
start_config_group_text_parser(custom_start_comment_syntax),
);
map(
combined_parser,
|(
(tokens, _ln1, contents),
(_potential_else, else_contents, (_potential_end1, _potential_end2)),
)| {
let config_group_type = match tokens.first().cloned() {
Some(token) => match token {
TokenSplit::And(_) => TagVariants::And,
TokenSplit::Or(_) => TagVariants::Or,
TokenSplit::AndOr(_) => TagVariants::Normal,
},
None => TagVariants::Normal,
};
let tag_list = tokens
.iter()
.map(|tag| match tag {
TokenSplit::And(tag_content)
| TokenSplit::Or(tag_content)
| TokenSplit::AndOr(tag_content) => tag_content.to_string().into(),
})
.collect::<Vec<ApplicabilityTag>>();
match config_group_type {
TagVariants::And => {
ApplicabilityParserSyntaxTag::TagAnd(ApplicabilitySyntaxTagAnd(
tag_list,
contents,
ApplicabilityTagTypes::ConfigurationGroup,
else_contents,
))
}
TagVariants::Or => ApplicabilityParserSyntaxTag::TagOr(ApplicabilitySyntaxTagOr(
tag_list,
contents,
ApplicabilityTagTypes::ConfigurationGroup,
else_contents,
)),
TagVariants::Normal => ApplicabilityParserSyntaxTag::Tag(ApplicabilitySyntaxTag(
tag_list,
contents,
ApplicabilityTagTypes::ConfigurationGroup,
else_contents,
)),
}
},
)
}
#[cfg(test)]
mod parse_config_group_tests {
use applicability::applic_tag::{ApplicabilityTag, ApplicabilityTagTypes};
use crate::applicability_parser_syntax_tag::{
ApplicabilityParserSyntaxTag, ApplicabilitySyntaxTag, ApplicabilitySyntaxTagAnd,
ApplicabilitySyntaxTagOr,
};
use super::parse_config_group;
#[test]
fn simple_config_group() {
let mut parser = parse_config_group("``", "``");
assert_eq!(
parser(
"`` ConfigurationGroup[SOMETHING] \n Some Text Here \n`` End ConfigurationGroup ``"
),
Ok((
"",
ApplicabilityParserSyntaxTag::Tag(ApplicabilitySyntaxTag(
vec![ApplicabilityTag {
tag: "SOMETHING".to_string(),
value: "Included".to_string()
}],
vec![ApplicabilityParserSyntaxTag::Text(
"Some Text Here \n".to_string()
),],
ApplicabilityTagTypes::ConfigurationGroup,
vec![]
))
))
)
}
#[test]
fn anded_config_group() {
let mut parser = parse_config_group("``", "``");
assert_eq!(
parser("`` ConfigurationGroup[SOMETHING & SOMETHING ELSE] \n Some Text Here \n`` End ConfigurationGroup ``"),
Ok((
"",
ApplicabilityParserSyntaxTag::TagAnd(ApplicabilitySyntaxTagAnd(
vec![ApplicabilityTag {
tag: "SOMETHING".to_string(),
value: "Included".to_string()
}, ApplicabilityTag {
tag: "SOMETHING ELSE".to_string(),
value: "Included".to_string()
}],
vec![ApplicabilityParserSyntaxTag::Text("Some Text Here \n".to_string()),],
ApplicabilityTagTypes::ConfigurationGroup,
vec![]
))
))
)
}
#[test]
fn ored_config_group() {
let mut parser = parse_config_group("``", "``");
assert_eq!(
parser("`` ConfigurationGroup[SOMETHING | SOMETHING ELSE] \n Some Text Here \n`` End ConfigurationGroup ``"),
Ok((
"",
ApplicabilityParserSyntaxTag::TagOr(ApplicabilitySyntaxTagOr(
vec![ApplicabilityTag {
tag: "SOMETHING".to_string(),
value: "Included".to_string()
},ApplicabilityTag {
tag: "SOMETHING ELSE".to_string(),
value: "Included".to_string()
}],
vec![ApplicabilityParserSyntaxTag::Text("Some Text Here \n".to_string()),],
ApplicabilityTagTypes::ConfigurationGroup,
vec![]
))
))
)
}
}
pub fn parse_config_group_not<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(&'a str) -> IResult<&'a str, ApplicabilityParserSyntaxTag> {
let combined_parser = config_group_parser(
custom_start_comment_syntax,
custom_end_comment_syntax,
not_config_group_text_parser(custom_start_comment_syntax),
);
map(
combined_parser,
|(
(tokens, _ln1, contents),
(_potential_else, else_contents, (_potential_end1, _potential_end2)),
)| {
let config_group_type = match tokens.first().cloned() {
Some(token) => match token {
TokenSplit::And(_) => TagVariants::And,
TokenSplit::Or(_) => TagVariants::Or,
TokenSplit::AndOr(_) => TagVariants::Normal,
},
None => TagVariants::Normal,
};
let tag_list = tokens
.iter()
.map(|tag| match tag {
TokenSplit::And(tag_content)
| TokenSplit::Or(tag_content)
| TokenSplit::AndOr(tag_content) => tag_content.to_string().into(),
})
.collect::<Vec<ApplicabilityTag>>();
match config_group_type {
TagVariants::And => {
ApplicabilityParserSyntaxTag::TagNotAnd(ApplicabilitySyntaxTagNotAnd(
tag_list,
contents,
ApplicabilityTagTypes::ConfigurationGroup,
else_contents,
))
}
TagVariants::Or => {
ApplicabilityParserSyntaxTag::TagNotOr(ApplicabilitySyntaxTagNotOr(
tag_list,
contents,
ApplicabilityTagTypes::ConfigurationGroup,
else_contents,
))
}
TagVariants::Normal => {
ApplicabilityParserSyntaxTag::TagNot(ApplicabilitySyntaxTagNot(
tag_list,
contents,
ApplicabilityTagTypes::ConfigurationGroup,
else_contents,
))
}
}
},
)
}
#[cfg(test)]
mod parse_config_group_not_tests {
use applicability::applic_tag::{ApplicabilityTag, ApplicabilityTagTypes};
use crate::applicability_parser_syntax_tag::{
ApplicabilityParserSyntaxTag, ApplicabilitySyntaxTagNot, ApplicabilitySyntaxTagNotAnd,
ApplicabilitySyntaxTagNotOr,
};
use super::parse_config_group_not;
#[test]
fn simple_config_group() {
let mut parser = parse_config_group_not("``", "``");
assert_eq!(
parser("`` ConfigurationGroup Not[SOMETHING] \n Some Text Here \n`` End ConfigurationGroup ``"),
Ok((
"",
ApplicabilityParserSyntaxTag::TagNot(ApplicabilitySyntaxTagNot(
vec![ApplicabilityTag {
tag: "SOMETHING".to_string(),
value: "Included".to_string()
}],
vec![ApplicabilityParserSyntaxTag::Text("Some Text Here \n".to_string()),],
ApplicabilityTagTypes::ConfigurationGroup,
vec![]
))
))
)
}
#[test]
fn anded_config_group() {
let mut parser = parse_config_group_not("``", "``");
assert_eq!(
parser(
"`` ConfigurationGroup Not[SOMETHING & SOMETHING ELSE] \n Some Text Here \n`` End ConfigurationGroup ``"
),
Ok((
"",
ApplicabilityParserSyntaxTag::TagNotAnd(ApplicabilitySyntaxTagNotAnd(
vec![ApplicabilityTag {
tag: "SOMETHING".to_string(),
value: "Included".to_string()
}, ApplicabilityTag {
tag: "SOMETHING ELSE".to_string(),
value: "Included".to_string()
}],
vec![ApplicabilityParserSyntaxTag::Text("Some Text Here \n".to_string()),],
ApplicabilityTagTypes::ConfigurationGroup,
vec![]
))
))
)
}
#[test]
fn ored_config_group() {
let mut parser = parse_config_group_not("``", "``");
assert_eq!(
parser(
"`` ConfigurationGroup Not[SOMETHING | SOMETHING ELSE] \n Some Text Here \n`` End ConfigurationGroup ``"
),
Ok((
"",
ApplicabilityParserSyntaxTag::TagNotOr(ApplicabilitySyntaxTagNotOr(
vec![ApplicabilityTag {
tag: "SOMETHING".to_string(),
value: "Included".to_string()
}, ApplicabilityTag {
tag: "SOMETHING ELSE".to_string(),
value: "Included".to_string()
}],
vec![ApplicabilityParserSyntaxTag::Text("Some Text Here \n".to_string()),],
ApplicabilityTagTypes::ConfigurationGroup,
vec![]
))
))
)
}
}
fn end_config_group_parser<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(&'a str) -> IResult<&'a str, &str> {
end_config_group_text_parser(custom_start_comment_syntax, custom_end_comment_syntax)
}
fn else_config_group_parser<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(&'a str) -> IResult<&'a str, &str> {
else_config_group_text_parser(custom_start_comment_syntax, custom_end_comment_syntax)
}
fn parse_config_group_inner<'a>(
custom_start_comment_syntax: &'a str,
custom_end_comment_syntax: &'a str,
) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<ApplicabilityParserSyntaxTag>> {
many0(next_inner(
custom_start_comment_syntax,
custom_end_comment_syntax,
))
}