use crate::{
Error, MapPattern, Pattern, Result, StructurePattern,
parse::{Token, meta::parse_or},
};
pub(crate) fn parse_bracket_map(
lexer: &mut logos::Lexer<Token>,
) -> Result<Pattern> {
let mut lookahead = lexer.clone();
match lookahead.next() {
Some(Ok(Token::Range(quantifier_result))) => {
lexer.next();
let quantifier = quantifier_result?;
match lexer.next() {
Some(Ok(Token::BraceClose)) => {
let pattern =
MapPattern::with_length_interval(quantifier.interval());
Ok(Pattern::Structure(StructurePattern::Map(pattern)))
}
Some(Ok(token)) => {
Err(Error::UnexpectedToken(Box::new(token), lexer.span()))
}
Some(Err(e)) => Err(e),
None => Err(Error::ExpectedCloseBrace(lexer.span())),
}
}
_ => {
parse_key_value_constraints(lexer)
}
}
}
fn parse_key_value_constraints(
lexer: &mut logos::Lexer<Token>,
) -> Result<Pattern> {
let mut constraints = Vec::new();
loop {
let key_pattern = parse_or(lexer)?;
match lexer.next() {
Some(Ok(Token::Colon)) => {}
Some(Ok(token)) => {
return Err(Error::UnexpectedToken(
Box::new(token),
lexer.span(),
));
}
Some(Err(e)) => return Err(e),
None => return Err(Error::ExpectedColon(lexer.span())),
}
let value_pattern = parse_or(lexer)?;
constraints.push((key_pattern, value_pattern));
match lexer.next() {
Some(Ok(Token::Comma)) => {
continue;
}
Some(Ok(Token::BraceClose)) => {
break;
}
Some(Ok(token)) => {
return Err(Error::UnexpectedToken(
Box::new(token),
lexer.span(),
));
}
Some(Err(e)) => return Err(e),
None => return Err(Error::ExpectedCloseBrace(lexer.span())),
}
}
Ok(Pattern::Structure(StructurePattern::Map(
MapPattern::with_key_value_constraints(constraints),
)))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Interval;
#[test]
fn test_parse_bracket_map_exact_count() {
let pattern = Pattern::parse("{{3}}").unwrap();
assert!(matches!(
pattern,
Pattern::Structure(StructurePattern::Map(MapPattern::Length(_)))
));
}
#[test]
fn test_parse_bracket_map_length_range() {
let pattern = Pattern::parse("{{2,5}}").unwrap();
assert!(matches!(
pattern,
Pattern::Structure(StructurePattern::Map(MapPattern::Length(_)))
));
if let Pattern::Structure(StructurePattern::Map(MapPattern::Length(
interval,
))) = pattern
{
assert_eq!(interval, Interval::new(2..=5));
}
}
#[test]
fn test_parse_bracket_map_open_range() {
let pattern = Pattern::parse("{{3,}}").unwrap();
assert!(matches!(
pattern,
Pattern::Structure(StructurePattern::Map(MapPattern::Length(_)))
));
if let Pattern::Structure(StructurePattern::Map(MapPattern::Length(
interval,
))) = pattern
{
assert_eq!(interval, Interval::new(3..));
}
}
#[test]
fn test_parse_bracket_map_key_value_constraints() {
let pattern =
Pattern::parse(r#"{"key": text, number: "value"}"#).unwrap();
assert!(matches!(
pattern,
Pattern::Structure(StructurePattern::Map(MapPattern::Constraints(
_
)))
));
}
}