use crate::raw_symbol_token::RawSymbolToken;
use crate::text::parse_result::{IonParseResult, UpgradeIResult};
use crate::text::parsers::comments::whitespace_or_comments;
use nom::bytes::streaming::tag;
use nom::character::streaming::multispace0;
use nom::combinator::{map_opt, opt};
use nom::multi::many1;
use nom::sequence::{delimited, pair, preceded, terminated};
use crate::text::parsers::symbol::parse_symbol;
use crate::text::parsers::whitespace;
use crate::text::text_value::TextValue;
pub(crate) fn parse_annotations(input: &str) -> IonParseResult<Vec<RawSymbolToken>> {
terminated(many1(parse_annotation), opt(whitespace))(input)
}
pub(crate) fn parse_annotation(input: &str) -> IonParseResult<RawSymbolToken> {
map_opt(
delimited(
whitespace_or_comments,
parse_symbol,
pair(whitespace_or_comments, annotation_delimiter),
),
|text_value| {
if let TextValue::Symbol(symbol) = text_value {
return Some(symbol);
}
None
},
)(input)
}
pub(crate) fn annotation_delimiter(input: &str) -> IonParseResult<&str> {
preceded(multispace0, tag("::"))(input).upgrade()
}
#[cfg(test)]
mod parse_annotations_tests {
use rstest::*;
use crate::raw_symbol_token::{local_sid_token, text_token};
use crate::types::SymbolId;
use super::*;
#[rstest]
#[case::identifier_no_spaces("foo::", "foo")]
#[case::identifier_leading_spaces(" foo::", "foo")]
#[case::identifier_trailing_spaces("foo:: ", "foo")]
#[case::identifier_interstitial_spaces("foo ::", "foo")]
#[case::identifier_all_spaces(" foo :: ", "foo")]
#[case::quoted_no_spaces("'foo'::", "foo")]
#[case::quoted_leading_spaces(" 'foo'::", "foo")]
#[case::quoted_trailing_spaces("'foo':: ", "foo")]
#[case::quoted_interstitial_spaces("'foo' ::", "foo")]
#[case::quoted_all_spaces(" 'foo' :: ", "foo")]
fn test_parse_annotation(#[case] text: &str, #[case] expected: &str) {
assert_eq!(parse_annotation(text).unwrap().1, text_token(expected));
}
#[rstest]
#[case::symbol_id_no_spaces("$10::", 10)]
#[case::symbol_id_leading_spaces(" $10::", 10)]
#[case::symbol_id_trailing_spaces("$10:: ", 10)]
#[case::symbol_id_interstitial_spaces("$10 ::", 10)]
#[case::symbol_id_all_spaces(" $10 :: ", 10)]
fn test_parse_symbol_id_annotation(#[case] text: &str, #[case] expected: SymbolId) {
assert_eq!(parse_annotation(text).unwrap().1, local_sid_token(expected));
}
}