fn setup_token_stream<'a>(
source: &'a mut dyn ISource,
directives: &'a crate::parser::directives::DirectiveContext,
) -> ParseResult<crate::parser::token_stream::TokenStream<'a>> {
let mut stream = crate::parser::token_stream::TokenStream::new(source, directives, false)?;
stream.skip_trivia()?;
Ok(stream)
}
use crate::io::traits::ISource;
use crate::nodes::node::Node;
use crate::parser::ParseResult;
use crate::parser::utils::node_utils::normalize_node_to_str;
use crate::{loop_guard_check, loop_guard_init};
fn guarded_explicit_key_loop<F>(
mut body: F,
max_pairs: Option<usize>,
) -> Result<Vec<(Node, Node)>, crate::error::YamlError>
where
F: FnMut() -> Option<Result<(Node, Node), crate::error::YamlError>>,
{
let mut pairs: Vec<(Node, Node)> = Vec::new();
loop_guard_init!(explicit_key_counter);
loop {
if let Some(max) = max_pairs {
if pairs.len() >= max {
break;
}
}
loop_guard_check!(
explicit_key_counter,
crate::parser::document::loop_guards::MAX_LOOP_ITERATIONS,
"Explicit key parsing"
);
match body() {
Some(Ok((key, value))) => pairs.push((key, value)),
Some(Err(e)) => return Err(e),
None => break,
}
}
Ok(pairs)
}
fn extract_explicit_key_value_pairs(
stream: &mut crate::parser::token_stream::TokenStream,
directives: &crate::parser::directives::DirectiveContext,
max_pairs: Option<usize>,
) -> Result<Vec<(Node, Node)>, crate::error::YamlError> {
guarded_explicit_key_loop(
|| {
stream.skip_trivia().ok()?;
if !matches!(
stream.current(),
Some(crate::parser::lexer::Token::QuestionMark)
) {
return None;
}
Some(parse_explicit_mapping_entry(stream, directives))
},
max_pairs,
)
}
pub fn parse_multiple_explicit_keys(
source: &mut dyn ISource,
_indent_level: usize,
) -> crate::parser::ParseResult<Node> {
let directives_local = crate::parser::directives::DirectiveContext::new();
let mut stream = setup_token_stream(source, &directives_local)?;
let pairs = extract_explicit_key_value_pairs(&mut stream, &directives_local, None)?;
Ok(Node::Mapping(pairs))
}
use crate::parser::lexer::Token;
use crate::parser::token_stream::TokenStream;
pub(crate) fn is_explicit_key_start(stream: &mut TokenStream) -> bool {
matches!(stream.current(), Some(Token::QuestionMark))
}
pub(crate) fn parse_explicit_mapping_entry(
stream: &mut TokenStream,
directives: &crate::parser::directives::DirectiveContext,
) -> ParseResult<(Node, Node)> {
if !is_explicit_key_start(stream) {
let cur = stream.current().cloned();
return Err(
crate::parser::errors::mapping_errors::expected_explicit_key_token(
stream, cur,
),
);
}
stream.next()?;
stream.skip_trivia()?;
let mut key_node = match stream.current() {
Some(Token::Newline) => {
stream.next()?;
stream.skip_trivia()?;
crate::parser::tokens::value::parse_value_with_tokens(stream, directives, 0)?
}
_ => {
crate::parser::tokens::value::parse_value_with_tokens(stream, directives, 0)?
}
};
key_node = normalize_node_to_str(&key_node);
stream.skip_trivia()?;
let value_node = match stream.current() {
Some(Token::Colon) => {
stream.next()?;
stream.skip_trivia()?;
match stream.current() {
Some(Token::Newline) => {
stream.next()?;
stream.skip_trivia()?;
crate::parser::tokens::value::parse_value_with_tokens(
stream, directives, 0,
)?
}
_ => crate::parser::tokens::value::parse_value_with_tokens(
stream, directives, 0,
)?,
}
}
_ => Node::None,
};
Ok((key_node, value_node))
}
#[allow(dead_code)]
pub(crate) fn collect_explicit_keys_block(
stream: &mut TokenStream,
directives: &crate::parser::directives::DirectiveContext,
) -> Result<Vec<(Node, Node)>, crate::error::YamlError> {
extract_explicit_key_value_pairs(
stream,
directives,
Some(crate::parser::document::loop_guards::MAX_MAPPING_PAIRS),
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nodes::node::Node;
#[test]
fn test_guarded_explicit_key_loop_basic() {
let mut count = 0;
let result = guarded_explicit_key_loop(
|| {
if count < 3 {
count += 1;
Some(Ok((Node::from(count), Node::from(count * 10))))
} else {
None
}
},
Some(5),
)
.unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0], (Node::from(1), Node::from(10)));
assert_eq!(result[2], (Node::from(3), Node::from(30)));
}
#[test]
fn test_guarded_explicit_key_loop_max_pairs() {
let mut count = 0;
let result = guarded_explicit_key_loop(
|| {
if count < 10 {
count += 1;
Some(Ok((Node::from(count), Node::from(count))))
} else {
None
}
},
Some(4),
)
.unwrap();
assert_eq!(result.len(), 4);
}
#[test]
fn test_guarded_explicit_key_loop_error() {
let result = guarded_explicit_key_loop(
|| Some(Err(crate::error::YamlError::from("fail"))),
Some(1),
);
assert!(result.is_err());
}
#[test]
fn test_normalize_node_to_str() {
let n = Node::from("abc");
let norm = normalize_node_to_str(&n);
assert_eq!(norm, n);
let n2 = Node::from(123);
let norm2 = normalize_node_to_str(&n2);
assert!(matches!(norm2, Node::Str(_, _, _)));
}
}