use crate::parser::Stream;
use winnow::combinator::{cut_err, repeat};
use winnow::error::{StrContext, StrContextValue};
use winnow::token::{one_of, take_while};
use winnow::{ModalResult, Parser};
const CTX_LABEL: &str = "name";
fn id_char(c: char) -> bool {
id_start_char(c)
| matches!(
c,
|'0'..='9' // rustfmt
| '_' | '-' | '\u{00B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}' )
}
fn id_start_char(c: char) -> bool {
matches!(c,
'a'..='z'
| 'A'..='Z'
| '$' | '¢' | '£' | '¤' | '¥' | '\u{00C0}'..='\u{00D6}'
| '\u{00D8}'..='\u{00F6}'
| '\u{00F8}'..='\u{02FF}'
| '\u{0370}'..='\u{037D}'
| '\u{037F}'..='\u{1FFF}'
| '\u{200C}'..='\u{200D}'
| '\u{2070}'..='\u{218F}'
| '\u{2C00}'..='\u{2FEF}'
| '\u{3001}'..='\u{D7FF}'
| '\u{F900}'..='\u{FDCF}'
| '\u{FDF0}'..='\u{FFFD}'
| '\u{00B5}' | '\u{00B9}' | '\u{00B2}' | '\u{00B3}' | '\u{00B0}' | '\u{00BC}' | '\u{00BD}' | '\u{00BE}' )
}
pub(crate) fn p_id_part<'s>(is: &mut Stream<'s>) -> ModalResult<&'s str> {
take_while(1.., id_char).take().parse_next(is)
}
pub(crate) fn p_identifier<'s>(is: &mut Stream<'s>) -> ModalResult<&'s str> {
let res_str = (one_of(id_start_char), take_while(0.., id_char))
.take()
.parse_next(is)?;
Ok(res_str)
}
fn p_id_part_helper<'s>(is: &mut Stream<'s>) -> ModalResult<&'s str> {
(
take_while(1, ':'),
cut_err(p_id_part)
.context(StrContext::Label(CTX_LABEL))
.context(StrContext::Expected(StrContextValue::Description(
"sub-part of name",
))),
)
.take()
.parse_next(is)
}
pub(crate) fn p_multi_part_id<'s>(is: &mut Stream<'s>) -> ModalResult<&'s str> {
let dec_str = (
p_identifier,
cut_err(
repeat(0.., p_id_part_helper).fold(String::new, |mut string, s| {
string.push_str(s);
string
}),
)
.context(StrContext::Label(CTX_LABEL))
.context(StrContext::Expected(StrContextValue::Description(
"for multi part name",
))),
)
.take()
.parse_next(is)?;
Ok(dec_str)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::kernel::Settings;
#[test]
fn test_p_id() {
let mut settings = Settings::default();
let input = "abcABCäöåÄÖÅ$€£";
let mut is = Stream {
input,
state: &mut settings,
};
let res = p_identifier(&mut is);
assert!(res.is_ok());
assert_eq!(input, res.unwrap());
}
#[test]
fn test_p_sub_id() {
let mut settings = Settings::default();
let input = "1234abcABCäöåÄÖÅ$€£";
let mut is = Stream {
input,
state: &mut settings,
};
let res = p_id_part(&mut is);
assert!(res.is_ok());
assert_eq!(input, res.unwrap());
}
}