extern crate nom;
use nom::{
bytes::complete::{take_while, take_while1, take_while_m_n},
combinator::recognize,
IResult,
sequence::pair,
};
pub fn ncname(input: &str) -> IResult<&str, &str> {
recognize(pair(ncnamestartchar, take_while(is_ncnamechar)))(input)
}
pub fn name(input: &str) -> IResult<&str, &str> {
recognize(pair(namestartchar, take_while1(is_namechar)))(input)
}
fn is_namechar(ch: char) -> bool {
if is_namestartchar(ch) {
true
} else {
matches!(ch, '.' | '-' | '0'..='9' | '\u{B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}')
}
}
#[cfg(test)]
fn ncnamechar(input: &str) -> IResult<&str, &str> {
take_while_m_n(1, 1, is_ncnamechar)(input)
}
fn is_ncnamechar(ch: char) -> bool {
if is_ncnamestartchar(ch) {
true
} else {
matches!(ch,
'.'
| '-'
| '0'..='9'
| '\u{B7}'
| '\u{0300}'..='\u{036F}'
| '\u{203F}'..='\u{2040}'
)
}
}
fn namestartchar(input: &str) -> IResult<&str, &str> {
take_while_m_n(1, 1, is_namestartchar)(input)
}
fn is_namestartchar(ch: char) -> bool {
match ch {
':' => true,
_ => is_ncnamestartchar(ch),
}
}
fn ncnamestartchar(input: &str) -> IResult<&str, &str> {
take_while_m_n(1, 1, is_ncnamestartchar)(input)
}
fn is_ncnamestartchar(ch: char) -> bool {
match ch {
'\u{0041}'..='\u{005A}' | '\u{005F}' | '\u{0061}'..='\u{007A}' | '\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{10000}'..='\u{EFFFF}' => {
true
}
_ => false
}
}
pub fn is_char(ch: &char) -> bool {
match ch {
'\u{0009}' | '\u{000A}' | '\u{000D}' | '\u{0020}'..='\u{D7FF}' | '\u{E000}'..='\u{FFFD}' | '\u{10000}'..='\u{10FFFF}' => {
true
}
_ => false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_name() {
assert_eq!(name("Foo"), Ok(("", "Foo")))
}
#[test]
fn test_ncnamechar() {
assert_eq!(ncnamechar("F"), Ok(("", "F")))
}
}