extern crate alloc;
use alloc::{borrow::Cow, format, vec::Vec};
use facet_format::{
ContainerKind, DeserializeErrorKind, FieldKey, FieldLocationHint, FormatParser, ParseError,
ParseEvent, ParseEventKind, SavePoint, ScalarValue,
};
use facet_reflect::Span;
use saphyr_parser::{Event, Parser, ScalarStyle, Span as SaphyrSpan, StrInput};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ContextState {
MappingKey,
MappingValue,
SequenceValue,
}
pub struct YamlParser<'de> {
input: &'de str,
parser: Parser<'de, StrInput<'de>>,
stack: Vec<ContextState>,
event_peek: Option<ParseEvent<'de>>,
started: bool,
last_span: Span,
save_counter: u64,
recording: Option<Vec<ParseEvent<'de>>>,
replay_buffer: Vec<ParseEvent<'de>>,
}
fn span_from_saphyr(span: &SaphyrSpan) -> Span {
let start = span.start.index();
let end = span.end.index();
Span::new(start, end.saturating_sub(start))
}
impl<'de> YamlParser<'de> {
pub fn new(input: &'de str) -> Self {
Self {
input,
parser: Parser::new_from_str(input),
stack: Vec::new(),
event_peek: None,
started: false,
last_span: Span::new(0, 0),
save_counter: 0,
recording: None,
replay_buffer: Vec::new(),
}
}
pub const fn input(&self) -> &'de str {
self.input
}
fn next_raw_event(&mut self) -> Result<Option<(Event<'de>, SaphyrSpan)>, ParseError> {
match self.parser.next_event() {
Some(Ok((event, span))) => {
self.last_span = span_from_saphyr(&span);
Ok(Some((event, span)))
}
Some(Err(e)) => {
let span = Span::new(e.marker().index(), 1);
Err(ParseError::new(
span,
DeserializeErrorKind::InvalidValue {
message: format!("{e}").into(),
},
))
}
None => Ok(None),
}
}
fn skip_preamble(&mut self) -> Result<(), ParseError> {
if self.started {
return Ok(());
}
self.started = true;
if let Some((Event::StreamStart, _)) = self.next_raw_event()? {
}
if let Some(Ok((Event::DocumentStart(_), _))) = self.parser.peek() {
self.next_raw_event()?;
}
Ok(())
}
fn produce_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
self.skip_preamble()?;
let (event, _span) = match self.next_raw_event()? {
Some(ev) => ev,
None => return Ok(None),
};
match event {
Event::StreamStart | Event::DocumentStart(_) => {
self.produce_event()
}
Event::StreamEnd | Event::DocumentEnd => {
Ok(None)
}
Event::MappingStart(_anchor, _tag) => {
self.stack.push(ContextState::MappingKey);
Ok(Some(
self.event(ParseEventKind::StructStart(ContainerKind::Object)),
))
}
Event::MappingEnd => {
self.stack.pop();
if let Some(ctx @ ContextState::MappingValue) = self.stack.last_mut() {
*ctx = ContextState::MappingKey;
}
Ok(Some(self.event(ParseEventKind::StructEnd)))
}
Event::SequenceStart(_anchor, _tag) => {
self.stack.push(ContextState::SequenceValue);
Ok(Some(self.event(ParseEventKind::SequenceStart(
ContainerKind::Array,
))))
}
Event::SequenceEnd => {
self.stack.pop();
if let Some(ctx @ ContextState::MappingValue) = self.stack.last_mut() {
*ctx = ContextState::MappingKey;
}
Ok(Some(self.event(ParseEventKind::SequenceEnd)))
}
Event::Scalar(value, style, _anchor, _tag) => {
if let Some(ctx @ ContextState::MappingKey) = self.stack.last_mut() {
*ctx = ContextState::MappingValue;
Ok(Some(self.event(ParseEventKind::FieldKey(FieldKey::new(
value,
FieldLocationHint::KeyValue,
)))))
} else {
if let Some(ctx @ ContextState::MappingValue) = self.stack.last_mut() {
*ctx = ContextState::MappingKey;
}
Ok(Some(self.event(ParseEventKind::Scalar(
self.scalar_to_value(value, style),
))))
}
}
Event::Alias(_id) => {
if let Some(ctx @ ContextState::MappingValue) = self.stack.last_mut() {
*ctx = ContextState::MappingKey;
}
Ok(Some(self.event(ParseEventKind::Scalar(ScalarValue::Null))))
}
Event::Nothing => {
self.produce_event()
}
}
}
fn scalar_to_value(&self, value: Cow<'de, str>, style: ScalarStyle) -> ScalarValue<'de> {
if matches!(style, ScalarStyle::SingleQuoted | ScalarStyle::DoubleQuoted) {
return ScalarValue::Str(value);
}
if is_yaml_null(&value) {
return ScalarValue::Null;
}
if let Some(b) = parse_yaml_bool(&value) {
return ScalarValue::Bool(b);
}
if let Ok(n) = value.parse::<i64>() {
return ScalarValue::I64(n);
}
if let Ok(n) = value.parse::<u64>() {
return ScalarValue::U64(n);
}
if let Ok(f) = value.parse::<f64>() {
return ScalarValue::F64(f);
}
match value.as_ref() {
".inf" | ".Inf" | ".INF" => return ScalarValue::F64(f64::INFINITY),
"-.inf" | "-.Inf" | "-.INF" => return ScalarValue::F64(f64::NEG_INFINITY),
".nan" | ".NaN" | ".NAN" => return ScalarValue::F64(f64::NAN),
_ => {}
}
ScalarValue::Str(value)
}
fn skip_current_value(&mut self) -> Result<(), ParseError> {
let mut depth = 0i32;
loop {
let event = self.next_event_internal()?;
match event.as_ref().map(|e| &e.kind) {
Some(ParseEventKind::StructStart(_) | ParseEventKind::SequenceStart(_)) => {
depth += 1;
}
Some(ParseEventKind::StructEnd | ParseEventKind::SequenceEnd) => {
depth -= 1;
if depth <= 0 {
return Ok(());
}
}
Some(ParseEventKind::Scalar(_)) if depth == 0 => {
return Ok(());
}
Some(_) => {}
None => return Ok(()),
}
}
}
fn next_event_internal(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
if let Some(event) = self.replay_buffer.pop() {
return Ok(Some(event));
}
if let Some(event) = self.event_peek.take() {
if let Some(ref mut rec) = self.recording {
rec.push(event.clone());
}
return Ok(Some(event));
}
let event = self.produce_event()?;
if let Some(ref mut rec) = self.recording
&& let Some(ref e) = event
{
rec.push(e.clone());
}
Ok(event)
}
}
impl<'de> FormatParser<'de> for YamlParser<'de> {
fn next_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
self.next_event_internal()
}
fn peek_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
if let Some(event) = self.replay_buffer.last().cloned() {
return Ok(Some(event));
}
if let Some(event) = self.event_peek.clone() {
return Ok(Some(event));
}
let event = self.produce_event()?;
if let Some(ref e) = event {
self.event_peek = Some(e.clone());
}
Ok(event)
}
fn skip_value(&mut self) -> Result<(), ParseError> {
debug_assert!(
self.event_peek.is_none(),
"skip_value called while an event is buffered"
);
self.skip_current_value()
}
fn save(&mut self) -> SavePoint {
self.save_counter += 1;
self.recording = Some(Vec::new());
SavePoint(self.save_counter)
}
fn restore(&mut self, _save_point: SavePoint) {
if let Some(mut recorded) = self.recording.take() {
recorded.reverse();
recorded.append(&mut self.replay_buffer);
self.replay_buffer = recorded;
}
}
fn capture_raw(&mut self) -> Result<Option<&'de str>, ParseError> {
self.skip_value()?;
Ok(None)
}
fn current_span(&self) -> Option<Span> {
Some(self.last_span)
}
}
impl<'de> YamlParser<'de> {
#[inline]
fn event(&self, kind: ParseEventKind<'de>) -> ParseEvent<'de> {
ParseEvent::new(kind, self.last_span)
}
}
fn is_yaml_null(value: &str) -> bool {
matches!(
value.to_lowercase().as_str(),
"null" | "~" | "" | "nil" | "none"
)
}
fn parse_yaml_bool(value: &str) -> Option<bool> {
match value.to_lowercase().as_str() {
"true" | "yes" | "on" | "y" => Some(true),
"false" | "no" | "off" | "n" => Some(false),
_ => None,
}
}