extension PureYAML.Parsing.LibYAML.Parser { /// Port of `yaml_parser_parse_flow_sequence_entry`. A `?` key inside a flow /// sequence opens a single-pair flow mapping. mutating func parseFlowSequenceEntry(first: Bool) throws -> Event { if first { marks.append(peekToken().startMark) skipToken() } var token = peekToken() if !isFlowSequenceEnd(token) { if !first { guard isFlowEntry(token) else { throw ParserError( context: "while parsing a flow sequence", problem: "did not find expected ',' or ']'", mark: marks.popLast() ?? token.startMark, ) } skipToken() token = peekToken() } if isKey(token) { state = .flowSequenceEntryMappingKey skipToken() return .mappingStart(anchor: nil, tag: nil, style: .flow, mark: token.startMark) } if isValue(token) { // A leading `:` opens a single-pair mapping with an empty key // (`[ : v ]`). Keep the VALUE token for the mapping-key state. state = .flowSequenceEntryMappingKey return .mappingStart(anchor: nil, tag: nil, style: .flow, mark: token.startMark) } if !isFlowSequenceEnd(token) { states.append(.flowSequenceEntry) return try parseNode(block: false, indentlessSequence: false) } } state = states.removeLast() _ = marks.popLast() skipToken() return .sequenceEnd(mark: token.startMark) } /// Port of `yaml_parser_parse_flow_sequence_entry_mapping_key`. mutating func parseFlowSequenceEntryMappingKey() throws -> Event { let token = peekToken() if !isValue(token), !isFlowEntry(token), !isFlowSequenceEnd(token) { states.append(.flowSequenceEntryMappingValue) return try parseNode(block: false, indentlessSequence: false) } // An empty key: leave a VALUE token for the value state to consume (so the // value is parsed); a closing `]` ends the pair with an empty value too. if isValue(token) || isFlowSequenceEnd(token) { state = .flowSequenceEntryMappingValue return processEmptyScalar(at: token.startMark) } let mark = token.endMark skipToken() state = .flowSequenceEntryMappingValue return processEmptyScalar(at: mark) } /// Port of `yaml_parser_parse_flow_sequence_entry_mapping_value`. mutating func parseFlowSequenceEntryMappingValue() throws -> Event { var token = peekToken() if isValue(token) { skipToken() token = peekToken() if !isFlowEntry(token), !isFlowSequenceEnd(token) { states.append(.flowSequenceEntryMappingEnd) return try parseNode(block: false, indentlessSequence: false) } } state = .flowSequenceEntryMappingEnd return processEmptyScalar(at: token.startMark) } /// Port of `yaml_parser_parse_flow_sequence_entry_mapping_end`. mutating func parseFlowSequenceEntryMappingEnd() throws -> Event { let token = peekToken() state = .flowSequenceEntry return .mappingEnd(mark: token.startMark) } /// Port of `yaml_parser_parse_flow_mapping_key`. mutating func parseFlowMappingKey(first: Bool) throws -> Event { if first { marks.append(peekToken().startMark) skipToken() } var token = peekToken() if !isFlowMappingEnd(token) { if !first { guard isFlowEntry(token) else { throw ParserError( context: "while parsing a flow mapping", problem: "did not find expected ',' or '}'", mark: marks.popLast() ?? token.startMark, ) } skipToken() token = peekToken() } if isKey(token) { return try flowMappingKeyEvent() } // YAML 1.2 permits an empty (null) key in a flow mapping: a `:` with // no preceding key denotes an entry whose key is empty. libyaml hands // the VALUE token to `parse_node` and fails; instead emit the empty // scalar key and let `parseFlowMappingValue` consume the indicator. if isValue(token) { state = .flowMappingValue return processEmptyScalar(at: token.startMark) } if !isFlowMappingEnd(token) { states.append(.flowMappingEmptyValue) return try parseNode(block: false, indentlessSequence: false) } } state = states.removeLast() _ = marks.popLast() skipToken() return .mappingEnd(mark: token.startMark) } /// The KEY branch of `parse_flow_mapping_key`: parse the key node, or an empty /// scalar when a value/entry/end follows the `?` immediately. private mutating func flowMappingKeyEvent() throws -> Event { skipToken() let token = peekToken() if !isValue(token), !isFlowEntry(token), !isFlowMappingEnd(token) { states.append(.flowMappingValue) return try parseNode(block: false, indentlessSequence: false) } state = .flowMappingValue return processEmptyScalar(at: token.startMark) } /// Port of `yaml_parser_parse_flow_mapping_value`. mutating func parseFlowMappingValue(empty: Bool) throws -> Event { var token = peekToken() if empty { state = .flowMappingKey return processEmptyScalar(at: token.startMark) } if isValue(token) { skipToken() token = peekToken() if !isFlowEntry(token), !isFlowMappingEnd(token) { states.append(.flowMappingKey) return try parseNode(block: false, indentlessSequence: false) } } state = .flowMappingKey return processEmptyScalar(at: token.startMark) } }