Fix empty keys in implicit mappings.

This commit is contained in:
Ethiraric 2023-12-26 19:11:17 +01:00
parent f2b5946008
commit 65a89f41b9
2 changed files with 43 additions and 2 deletions

View file

@ -251,6 +251,15 @@ pub struct Scanner<T> {
token_available: bool, token_available: bool,
/// Whether all characters encountered since the last newline were whitespace. /// Whether all characters encountered since the last newline were whitespace.
leading_whitespace: bool, leading_whitespace: bool,
/// Whether we started a flow mapping.
///
/// This is used to detect implicit flow mapping starts such as:
/// ```yaml
/// [ : foo ] # { null: "foo" }
/// ```
flow_mapping_started: bool,
/// Whether we currently are in an implicit flow mapping.
implicit_flow_mapping: bool,
} }
impl<T: Iterator<Item = char>> Iterator for Scanner<T> { impl<T: Iterator<Item = char>> Iterator for Scanner<T> {
@ -365,6 +374,8 @@ impl<T: Iterator<Item = char>> Scanner<T> {
tokens_parsed: 0, tokens_parsed: 0,
token_available: false, token_available: false,
leading_whitespace: true, leading_whitespace: true,
flow_mapping_started: false,
implicit_flow_mapping: false,
} }
} }
@ -1217,6 +1228,10 @@ impl<T: Iterator<Item = char>> Scanner<T> {
let start_mark = self.mark; let start_mark = self.mark;
self.skip(); self.skip();
if tok == TokenType::FlowMappingStart {
self.flow_mapping_started = true;
}
self.tokens.push_back(Token(start_mark, tok)); self.tokens.push_back(Token(start_mark, tok));
Ok(()) Ok(())
} }
@ -1227,6 +1242,8 @@ impl<T: Iterator<Item = char>> Scanner<T> {
self.disallow_simple_key(); self.disallow_simple_key();
self.end_implicit_mapping(self.mark);
let start_mark = self.mark; let start_mark = self.mark;
self.skip(); self.skip();
@ -1239,6 +1256,8 @@ impl<T: Iterator<Item = char>> Scanner<T> {
self.remove_simple_key()?; self.remove_simple_key()?;
self.allow_simple_key(); self.allow_simple_key();
self.end_implicit_mapping(self.mark);
let start_mark = self.mark; let start_mark = self.mark;
self.skip(); self.skip();
@ -1899,6 +1918,9 @@ impl<T: Iterator<Item = char>> Scanner<T> {
TokenType::BlockMappingStart, TokenType::BlockMappingStart,
start_mark, start_mark,
); );
} else {
// The parser, upon receiving a `Key`, will insert a `MappingStart` event.
self.flow_mapping_started = true;
} }
self.remove_simple_key()?; self.remove_simple_key()?;
@ -1925,6 +1947,7 @@ impl<T: Iterator<Item = char>> Scanner<T> {
fn fetch_value(&mut self) -> ScanResult { fn fetch_value(&mut self) -> ScanResult {
let sk = self.simple_keys.last().unwrap().clone(); let sk = self.simple_keys.last().unwrap().clone();
let start_mark = self.mark; let start_mark = self.mark;
self.implicit_flow_mapping = self.flow_level > 0 && !self.flow_mapping_started;
// Skip over ':'. // Skip over ':'.
self.skip(); self.skip();
@ -1943,6 +1966,12 @@ impl<T: Iterator<Item = char>> Scanner<T> {
let tok = Token(sk.mark, TokenType::Key); let tok = Token(sk.mark, TokenType::Key);
let tokens_parsed = self.tokens_parsed; let tokens_parsed = self.tokens_parsed;
self.insert_token(sk.token_number - tokens_parsed, tok); self.insert_token(sk.token_number - tokens_parsed, tok);
if self.implicit_flow_mapping {
self.insert_token(
sk.token_number - tokens_parsed,
Token(self.mark, TokenType::FlowMappingStart),
);
}
// Add the BLOCK-MAPPING-START token if needed. // Add the BLOCK-MAPPING-START token if needed.
self.roll_indent( self.roll_indent(
@ -1956,6 +1985,10 @@ impl<T: Iterator<Item = char>> Scanner<T> {
self.simple_keys.last_mut().unwrap().possible = false; self.simple_keys.last_mut().unwrap().possible = false;
self.disallow_simple_key(); self.disallow_simple_key();
} else { } else {
if self.implicit_flow_mapping {
self.tokens
.push_back(Token(self.mark, TokenType::FlowMappingStart));
}
// The ':' indicator follows a complex key. // The ':' indicator follows a complex key.
if self.flow_level == 0 { if self.flow_level == 0 {
if !self.simple_key_allowed { if !self.simple_key_allowed {
@ -2096,6 +2129,16 @@ impl<T: Iterator<Item = char>> Scanner<T> {
fn is_within_block(&self) -> bool { fn is_within_block(&self) -> bool {
!self.indents.is_empty() !self.indents.is_empty()
} }
/// If an implicit mapping had started, end it.
fn end_implicit_mapping(&mut self, mark: Marker) {
if self.implicit_flow_mapping {
self.implicit_flow_mapping = false;
self.flow_mapping_started = false;
self.tokens
.push_back(Token(mark, TokenType::FlowMappingEnd));
}
}
} }
/// Behavior to adopt regarding treating tabs as whitespace. /// Behavior to adopt regarding treating tabs as whitespace.

View file

@ -297,8 +297,6 @@ fn expected_events(expected_tree: &str) -> Vec<String> {
#[rustfmt::skip] #[rustfmt::skip]
static EXPECTED_FAILURES: &[&str] = &[ static EXPECTED_FAILURES: &[&str] = &[
// Empty key in flow mappings
"CFD4",
// Document with no nodes and document end // Document with no nodes and document end
"HWV9", "HWV9",
"QT73", "QT73",