diff --git a/parser/src/parser.rs b/parser/src/parser.rs index c885856..a83bdc4 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -51,7 +51,7 @@ pub enum Event { usize, ), /// Value, style, anchor_id, tag - Scalar(String, TScalarStyle, usize, Option), + Scalar(String, TScalarStyle, usize, Option), SequenceStart( /// The anchor ID of the start of the squence. usize, @@ -60,10 +60,21 @@ pub enum Event { MappingStart( /// The anchor ID of the start of the mapping. usize, + /// An optional tag + Option, ), MappingEnd, } +/// A YAML tag. +#[derive(Clone, PartialEq, Debug, Eq)] +pub struct Tag { + /// Handle of the tag (`!` included). + pub handle: String, + /// The suffix of the tag. + pub suffix: String, +} + impl Event { /// Create an empty scalar. fn empty_scalar() -> Event { @@ -72,7 +83,7 @@ impl Event { } /// Create an empty scalar with the given anchor. - fn empty_scalar_with_anchor(anchor: usize, tag: Option) -> Event { + fn empty_scalar_with_anchor(anchor: usize, tag: Option) -> Event { Event::Scalar(String::new(), TScalarStyle::Plain, anchor, tag) } } @@ -340,7 +351,7 @@ impl> Parser { recv.on_event(first_ev, mark); self.load_sequence(recv) } - Event::MappingStart(_) => { + Event::MappingStart(..) => { recv.on_event(first_ev, mark); self.load_mapping(recv) } @@ -575,8 +586,8 @@ impl> Parser { if let Token(mark, TokenType::Anchor(name)) = self.fetch_token() { anchor_id = self.register_anchor(name, &mark); if let TokenType::Tag(..) = self.peek_token()?.1 { - if let tg @ TokenType::Tag(..) = self.fetch_token().1 { - tag = Some(tg); + if let TokenType::Tag(handle, suffix) = self.fetch_token().1 { + tag = Some(Tag { handle, suffix }); } else { unreachable!() } @@ -586,9 +597,9 @@ impl> Parser { } } Token(_, TokenType::Tag(..)) => { - if let tg @ TokenType::Tag(..) = self.fetch_token().1 { - tag = Some(tg); - if let TokenType::Anchor(_) = self.peek_token()?.1 { + if let TokenType::Tag(handle, suffix) = self.fetch_token().1 { + tag = Some(Tag { handle, suffix }); + if let TokenType::Anchor(_) = &self.peek_token()?.1 { if let Token(mark, TokenType::Anchor(name)) = self.fetch_token() { anchor_id = self.register_anchor(name, &mark); } else { @@ -620,7 +631,7 @@ impl> Parser { } Token(mark, TokenType::FlowMappingStart) => { self.state = State::FlowMappingFirstKey; - Ok((Event::MappingStart(anchor_id), mark)) + Ok((Event::MappingStart(anchor_id, tag), mark)) } Token(mark, TokenType::BlockSequenceStart) if block => { self.state = State::BlockSequenceFirstEntry; @@ -628,7 +639,7 @@ impl> Parser { } Token(mark, TokenType::BlockMappingStart) if block => { self.state = State::BlockMappingFirstKey; - Ok((Event::MappingStart(anchor_id), mark)) + Ok((Event::MappingStart(anchor_id, tag), mark)) } // ex 7.2, an empty scalar can follow a secondary tag Token(mark, _) if tag.is_some() || anchor_id > 0 => { @@ -819,7 +830,7 @@ impl> Parser { Token(mark, TokenType::Key) => { self.state = State::FlowSequenceEntryMappingKey; self.skip(); - Ok((Event::MappingStart(0), mark)) + Ok((Event::MappingStart(0, None), mark)) } _ => { self.push_state(State::FlowSequenceEntry); diff --git a/parser/src/scanner.rs b/parser/src/scanner.rs index 9f42cc1..a271602 100644 --- a/parser/src/scanner.rs +++ b/parser/src/scanner.rs @@ -109,26 +109,43 @@ impl fmt::Display for ScanError { #[derive(Clone, PartialEq, Debug, Eq)] pub enum TokenType { NoToken, + /// The start of the stream. Sent first, before even [`DocumentStart`]. StreamStart(TEncoding), + /// The end of the stream, EOF. StreamEnd, - /// major, minor - VersionDirective(u32, u32), - /// handle, prefix - TagDirective(String, String), + VersionDirective( + /// Major + u32, + /// Minor + u32, + ), + TagDirective( + /// Handle + String, + /// Prefix + String, + ), + /// The start of a YAML document (`---`). DocumentStart, + /// The end of a YAML document (`...`). DocumentEnd, BlockSequenceStart, BlockMappingStart, BlockEnd, + /// Start of an inline array (`[ a, b ]`). FlowSequenceStart, + /// End of an inline array. FlowSequenceEnd, + /// Start of an inline mapping (`{ a: b, c: d }`). FlowMappingStart, + /// End of an inline mapping. FlowMappingEnd, BlockEntry, FlowEntry, Key, Value, Alias(String), + /// A YAML anchor (`&`/`*`). Anchor(String), /// handle, suffix Tag(String, String), diff --git a/parser/src/yaml.rs b/parser/src/yaml.rs index 67b8b76..07a8592 100644 --- a/parser/src/yaml.rs +++ b/parser/src/yaml.rs @@ -1,6 +1,6 @@ #![allow(clippy::module_name_repetitions)] -use crate::parser::{Event, MarkedEventReceiver, Parser}; +use crate::parser::{Event, MarkedEventReceiver, Parser, Tag}; use crate::scanner::{Marker, ScanError, TScalarStyle, TokenType}; use linked_hash_map::LinkedHashMap; use std::collections::BTreeMap; @@ -98,7 +98,7 @@ impl MarkedEventReceiver for YamlLoader { let node = self.doc_stack.pop().unwrap(); self.insert_new_node(node); } - Event::MappingStart(aid) => { + Event::MappingStart(aid, _) => { self.doc_stack.push((Yaml::Hash(Hash::new()), aid)); self.key_stack.push(Yaml::BadValue); } @@ -110,7 +110,7 @@ impl MarkedEventReceiver for YamlLoader { Event::Scalar(v, style, aid, tag) => { let node = if style != TScalarStyle::Plain { Yaml::String(v) - } else if let Some(TokenType::Tag(ref handle, ref suffix)) = tag { + } else if let Some(Tag { ref handle, ref suffix }) = tag { // XXX tag:yaml.org,2002: if handle == "!!" { match suffix.as_ref() { diff --git a/parser/tests/yaml-test-suite.rs b/parser/tests/yaml-test-suite.rs index 48f265e..788484f 100644 --- a/parser/tests/yaml-test-suite.rs +++ b/parser/tests/yaml-test-suite.rs @@ -3,8 +3,8 @@ use std::fs::{self, DirEntry}; use libtest_mimic::{run_tests, Arguments, Outcome, Test}; use yaml_rust::{ - parser::{Event, EventReceiver, Parser}, - scanner::{TScalarStyle, TokenType}, + parser::{Event, EventReceiver, Parser, Tag}, + scanner::{TScalarStyle}, yaml, ScanError, Yaml, YamlLoader, }; @@ -148,7 +148,9 @@ impl EventReceiver for EventReporter { Event::SequenceStart(idx) => format!("+SEQ{}", format_index(idx)), Event::SequenceEnd => "-SEQ".into(), - Event::MappingStart(idx) => format!("+MAP{}", format_index(idx)), + Event::MappingStart(idx, tag) => { + format!("+MAP{}{}", format_index(idx), format_tag(&tag)) + } Event::MappingEnd => "-MAP".into(), Event::Scalar(ref text, style, idx, ref tag) => { @@ -197,13 +199,13 @@ fn escape_text(text: &str) -> String { text } -fn format_tag(tag: &Option) -> String { - if let Some(TokenType::Tag(ns, tag)) = tag { - let ns = match ns.as_str() { +fn format_tag(tag: &Option) -> String { + if let Some(tag) = tag { + let ns = match tag.handle.as_str() { "!!" => "tag:yaml.org,2002:", // Wrong if this ns is overridden other => other, }; - format!(" <{}{}>", ns, tag) + format!(" <{}{}>", ns, tag.suffix) } else { "".into() } @@ -302,13 +304,9 @@ static EXPECTED_FAILURES: &[&str] = &[ "35KP", "57H4", "6JWB", - "735Y", - "9KAX", - "BU8L", "C4HZ", "EHF6", "J7PZ", - "UGM3", // Cannot resolve tag namespaces "5TYM", "6CK3",