use super::block::reaches_key_colon;
use super::scalars::is_plain_scalar_kind;
use super::Parser;
use crate::error_recovery::ParseContext;
use crate::lex::SyntaxKind;
use crate::ParseErrorKind;
impl Parser<'_> {
fn next_flow_element_is_implicit_mapping(&self) -> bool {
self.current() == Some(SyntaxKind::QUESTION)
|| self
.tokens
.len()
.checked_sub(1)
.is_some_and(|i| self.implicit_mapping_starts[i])
}
fn parse_flow_content_before_colon(&mut self) {
let whitespace = usize::from(self.current() == Some(SyntaxKind::WHITESPACE));
let rest = std::iter::once(self.current().unwrap_or(SyntaxKind::EOF))
.chain(self.upcoming_tokens())
.skip(whitespace);
if !self.peek_kind(whitespace).is_some_and(is_plain_scalar_kind) || !reaches_key_colon(rest)
{
return;
}
if whitespace == 1 {
self.bump();
}
self.parse_scalar();
}
fn skip_to_explicit_key(&mut self) {
match self.next_significant_kind() {
None
| Some(
SyntaxKind::COMMA
| SyntaxKind::COLON
| SyntaxKind::RIGHT_BRACE
| SyntaxKind::RIGHT_BRACKET,
) => self.skip_whitespace(),
Some(_) => self.skip_ws_and_newlines(),
}
}
fn parse_implicit_flow_mapping(&mut self) {
self.builder.start_node(SyntaxKind::MAPPING.into());
self.builder.start_node(SyntaxKind::MAPPING_ENTRY.into());
self.builder.start_node(SyntaxKind::KEY.into());
if self.current() == Some(SyntaxKind::QUESTION) {
self.bump();
self.skip_to_explicit_key();
}
if matches!(
self.next_significant_kind(),
Some(SyntaxKind::COLON | SyntaxKind::COMMA | SyntaxKind::RIGHT_BRACKET)
) {
self.emit_implicit_null();
} else {
self.parse_value();
self.parse_flow_content_before_colon();
}
self.builder.finish_node();
self.skip_ws_and_newlines();
if self.current() == Some(SyntaxKind::COLON) {
self.bump();
self.skip_whitespace();
}
if self.at_flow_entry_end(SyntaxKind::RIGHT_BRACKET) {
self.emit_implicit_null_value();
} else {
self.skip_ws_and_newlines();
self.builder.start_node(SyntaxKind::VALUE.into());
self.parse_value();
self.builder.finish_node();
}
self.builder.finish_node(); self.builder.finish_node(); }
fn flow_progress_guard(&mut self, tokens_before: usize, what: &str) {
if self.tokens.len() != tokens_before {
return;
}
self.parse_stray_token(&format!("flow {what}"));
}
pub(super) fn parse_flow_sequence(&mut self) {
self.parse_flow_collection(SyntaxKind::RIGHT_BRACKET, Self::parse_flow_sequence_entry);
}
pub(super) fn parse_flow_mapping(&mut self) {
self.parse_flow_collection(SyntaxKind::RIGHT_BRACE, Self::parse_flow_mapping_entry);
}
fn parse_flow_collection(&mut self, closer: SyntaxKind, entry: fn(&mut Self) -> bool) {
let (node, context, what, expected, error_kind) = match closer {
SyntaxKind::RIGHT_BRACKET => (
SyntaxKind::SEQUENCE,
ParseContext::FlowSequence,
"sequence",
"']' to close sequence",
ParseErrorKind::UnclosedFlowSequence,
),
_ => (
SyntaxKind::MAPPING,
ParseContext::FlowMapping,
"mapping",
"'}' to close mapping",
ParseErrorKind::UnclosedFlowMapping,
),
};
self.builder.start_node(node.into());
self.error_context.push_context(context);
self.flow_depth += 1;
self.bump();
let prev_flow = std::mem::replace(&mut self.in_flow_context, true);
loop {
self.skip_ws_and_newlines();
if self.current() == Some(closer) || self.current().is_none() {
break;
}
let tokens_before = self.tokens.len();
if !entry(self) {
break;
}
self.flow_progress_guard(tokens_before, what);
}
self.in_flow_context = prev_flow;
if self.current() == Some(closer) {
self.bump();
} else {
let error_msg = self.create_detailed_error(
&format!("Unclosed flow {what}"),
expected,
self.current_text(),
);
self.add_error_and_recover(error_msg, closer, error_kind);
}
self.flow_depth -= 1;
self.builder.finish_node();
self.error_context.pop_context();
}
fn finish_flow_entry(&mut self) {
if self.next_significant_kind() == Some(SyntaxKind::COMMA) {
self.skip_ws_and_newlines();
self.bump();
}
self.skip_line_end_trivia();
if self.current() == Some(SyntaxKind::NEWLINE) && !self.line_ended() {
self.bump();
}
self.builder.finish_node();
}
fn parse_flow_sequence_entry(&mut self) -> bool {
self.builder.start_node(SyntaxKind::SEQUENCE_ENTRY.into());
if matches!(
self.current(),
Some(SyntaxKind::COMMA) | Some(SyntaxKind::RIGHT_BRACKET)
) {
self.emit_implicit_null();
} else if self.next_flow_element_is_implicit_mapping() {
self.parse_implicit_flow_mapping();
} else {
self.parse_value();
}
self.finish_flow_entry();
!matches!(
self.current(),
Some(SyntaxKind::DASH | SyntaxKind::DOC_START | SyntaxKind::DOC_END)
)
}
fn parse_flow_mapping_entry(&mut self) -> bool {
if matches!(
self.current(),
Some(SyntaxKind::DASH | SyntaxKind::DOC_START | SyntaxKind::DOC_END)
) {
return false;
}
self.builder.start_node(SyntaxKind::MAPPING_ENTRY.into());
self.builder.start_node(SyntaxKind::KEY.into());
if self.current() == Some(SyntaxKind::QUESTION) {
self.bump(); self.skip_to_explicit_key();
}
if matches!(
self.next_significant_kind(),
Some(SyntaxKind::COMMA | SyntaxKind::COLON | SyntaxKind::RIGHT_BRACE)
) {
self.emit_implicit_null();
} else {
self.parse_value();
self.parse_flow_content_before_colon();
}
self.builder.finish_node();
if self.at_flow_entry_end(SyntaxKind::RIGHT_BRACE) {
self.emit_implicit_null_value();
} else if self.next_significant_kind() == Some(SyntaxKind::COLON) {
self.skip_ws_and_newlines(); self.bump();
self.skip_whitespace();
if self.at_flow_entry_end(SyntaxKind::RIGHT_BRACE) {
self.emit_implicit_null_value();
} else {
self.skip_ws_and_newlines(); self.builder.start_node(SyntaxKind::VALUE.into());
self.parse_value();
self.builder.finish_node();
}
} else {
self.emit_implicit_null_value();
}
self.finish_flow_entry();
true
}
}
pub(crate) fn implicit_mapping_starts(kinds: &[SyntaxKind]) -> Vec<bool> {
let mut starts = vec![false; kinds.len()];
let mut closers = Vec::new();
for (i, kind) in kinds.iter().enumerate().rev() {
let from = match kind {
SyntaxKind::LEFT_BRACE | SyntaxKind::LEFT_BRACKET => closers.pop().map(|c| c + 1),
SyntaxKind::RIGHT_BRACE | SyntaxKind::RIGHT_BRACKET => {
closers.push(i);
None
}
SyntaxKind::COLON => {
starts[i] = true;
None
}
SyntaxKind::COMMA => None,
_ => Some(i + 1),
};
if let Some(from) = from {
starts[i] = starts.get(from).copied().unwrap_or(false);
}
}
starts
}