tamer: ir::xir: Combine Token::{SelfClose, Close} variants
This removes `SelfClose` and merges it with `Close` by making the first parameter an `Option`. This isn't really ideal, but it really simplifies pattern matching, especially for the next commit. I'll have more details there. The primary motivation was lack of stabalization for binding after `@` in matches, e.g. `Foo(name, ele) | ele @ Element { name, .. }`. It looks like it's ready, though; maybe next Rust release? https://github.com/rust-lang/rust/issues/65490 I don't know if I'll revert this change after then. This seems plenty clear, albeit more verbose.main
parent
1c40b9c504
commit
51507ccdad
|
@ -363,14 +363,8 @@ pub enum Token<Ix: SymbolIndexSize> {
|
|||
|
||||
/// Closing tag of an element.
|
||||
///
|
||||
/// If no child nodes have been encountered since the last `Open`,
|
||||
/// then the tag is assumed to be self-closing;
|
||||
/// if this is not desired,
|
||||
/// emit an empty `Text` variant.
|
||||
Close(QName<Ix>, Span),
|
||||
|
||||
/// End of self-closing tag.
|
||||
///
|
||||
/// If the name is [`None`],
|
||||
/// then the tag is self-closing.
|
||||
/// This is intended primarily as a safety measure:
|
||||
/// It allows writers to act as simple state machines without having
|
||||
/// to ensure balancing by indicating that a node was intended to
|
||||
|
@ -383,7 +377,13 @@ pub enum Token<Ix: SymbolIndexSize> {
|
|||
/// Instead of losing tags,
|
||||
/// writers can error,
|
||||
/// indicating a bug in the stream.
|
||||
SelfClose(Span),
|
||||
///
|
||||
/// The reason for using an option here rather than a variant is to
|
||||
/// simplify pattern matching,
|
||||
/// given especially that bindings after `@` in patterns have not
|
||||
/// yet been stabalized at the time of writing (but are very
|
||||
/// close!).
|
||||
Close(Option<QName<Ix>>, Span),
|
||||
|
||||
/// Element attribute name
|
||||
AttrName(QName<Ix>, Span),
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
//! Parsing operates on _context_.
|
||||
//! At present, the only parsing context is an element---it
|
||||
//! begins parsing at an opening tag ([`Token::Open`]) and completes
|
||||
//! parsing at a _matching_ [`Token::Close`] or [`Token::SelfClose`].
|
||||
//! parsing at a _matching_ [`Token::Close`].
|
||||
//! All attributes and child nodes encountered during parsing of an element
|
||||
//! will automatically be added to the appropriate element,
|
||||
//! recursively.
|
||||
|
@ -386,19 +386,14 @@ impl<Ix: SymbolIndexSize> ParserState<Ix> {
|
|||
Ok(Parsed::Incomplete)
|
||||
}
|
||||
|
||||
(Token::SelfClose(span), Stack::BuddingElement(ele)) => {
|
||||
Ok(Parsed::Object(Tree::Element(Element {
|
||||
span: (ele.span.0, span),
|
||||
..ele
|
||||
})))
|
||||
}
|
||||
|
||||
(Token::Close(name, span), Stack::BuddingElement(ele)) => {
|
||||
if name != ele.name {
|
||||
return Err(ParseError::UnbalancedTagName {
|
||||
open: (ele.name, ele.span.0),
|
||||
close: (name, span),
|
||||
});
|
||||
(Token::Close(balance_name, span), Stack::BuddingElement(ele)) => {
|
||||
if let Some(name) = balance_name {
|
||||
if name != ele.name {
|
||||
return Err(ParseError::UnbalancedTagName {
|
||||
open: (ele.name, ele.span.0),
|
||||
close: (name, span),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Parsed::Object(Tree::Element(Element {
|
||||
|
@ -603,7 +598,7 @@ mod test {
|
|||
|
||||
let toks = std::array::IntoIter::new([
|
||||
Token::<Ix>::Open(name, *S),
|
||||
Token::<Ix>::SelfClose(*S2),
|
||||
Token::<Ix>::Close(None, *S2),
|
||||
]);
|
||||
|
||||
let expected = Element {
|
||||
|
@ -631,7 +626,7 @@ mod test {
|
|||
|
||||
let toks = std::array::IntoIter::new([
|
||||
Token::<Ix>::Open(name, *S),
|
||||
Token::<Ix>::Close(name, *S2),
|
||||
Token::<Ix>::Close(Some(name), *S2),
|
||||
]);
|
||||
|
||||
let expected = Element {
|
||||
|
@ -660,7 +655,7 @@ mod test {
|
|||
|
||||
let toks = std::array::IntoIter::new([
|
||||
Token::<Ix>::Open(open_name, *S),
|
||||
Token::<Ix>::Close(close_name, *S2),
|
||||
Token::<Ix>::Close(Some(close_name), *S2),
|
||||
]);
|
||||
|
||||
let mut sut = toks.scan(ParserState::new(), parse);
|
||||
|
@ -692,7 +687,7 @@ mod test {
|
|||
Token::AttrValue(val1, *S2),
|
||||
Token::AttrName(attr2, *S),
|
||||
Token::AttrValue(val2, *S2),
|
||||
Token::SelfClose(*S2),
|
||||
Token::Close(None, *S2),
|
||||
]);
|
||||
|
||||
let expected = Element {
|
||||
|
@ -737,7 +732,7 @@ mod test {
|
|||
Token::<Ix>::Open(name, *S),
|
||||
Token::AttrName(attr, *S),
|
||||
Token::AttrValue(val, *S2),
|
||||
Token::SelfClose(*S2),
|
||||
Token::Close(None, *S2),
|
||||
]);
|
||||
|
||||
let expected = Element {
|
||||
|
|
|
@ -181,15 +181,13 @@ impl<Ix: SymbolIndexSize> XmlWriter for Token<Ix> {
|
|||
Ok(S::NodeOpen)
|
||||
}
|
||||
|
||||
// TODO: Remove whitespace from here, add to stream, then it can
|
||||
// be used with attrs
|
||||
(Self::SelfClose(_), S::NodeOpen) => {
|
||||
(Self::Close(None, _), S::NodeOpen) => {
|
||||
sink.write(b"/>")?;
|
||||
|
||||
Ok(S::NodeExpected)
|
||||
}
|
||||
|
||||
(Self::Close(name, _), S::NodeExpected | S::NodeOpen) => {
|
||||
(Self::Close(Some(name), _), S::NodeExpected | S::NodeOpen) => {
|
||||
// If open, we're going to produce an element of the form
|
||||
// `<foo></foo>`.
|
||||
prev_state.close_tag_if_open(sink)?;
|
||||
|
@ -355,7 +353,7 @@ mod test {
|
|||
#[test]
|
||||
fn closes_open_node_as_empty_element() -> TestResult {
|
||||
let result =
|
||||
Token::<Ix>::SelfClose(*S).write_new(WriterState::NodeOpen)?;
|
||||
Token::<Ix>::Close(None, *S).write_new(WriterState::NodeOpen)?;
|
||||
|
||||
assert_eq!(result.0, b"/>");
|
||||
assert_eq!(result.1, WriterState::NodeExpected);
|
||||
|
@ -367,8 +365,8 @@ mod test {
|
|||
fn closing_tag_when_node_expected() -> TestResult {
|
||||
let name = QName::<Ix>::try_from(("a", "closed-element"))?;
|
||||
|
||||
let result =
|
||||
Token::Close(name, *S).write_new(WriterState::NodeExpected)?;
|
||||
let result = Token::Close(Some(name), *S)
|
||||
.write_new(WriterState::NodeExpected)?;
|
||||
|
||||
assert_eq!(result.0, b"</a:closed-element>");
|
||||
assert_eq!(result.1, WriterState::NodeExpected);
|
||||
|
@ -382,7 +380,8 @@ mod test {
|
|||
fn closes_open_node_with_closing_tag() -> TestResult {
|
||||
let name = QName::<Ix>::try_from(("b", "closed-element"))?;
|
||||
|
||||
let result = Token::Close(name, *S).write_new(WriterState::NodeOpen)?;
|
||||
let result =
|
||||
Token::Close(Some(name), *S).write_new(WriterState::NodeOpen)?;
|
||||
|
||||
assert_eq!(result.0, b"></b:closed-element>");
|
||||
assert_eq!(result.1, WriterState::NodeExpected);
|
||||
|
@ -522,8 +521,8 @@ mod test {
|
|||
Token::Text(Text::Escaped("text".intern()), *S),
|
||||
Token::Open(("c", "child").try_into()?, *S),
|
||||
Token::Whitespace(" ".try_into()?, *S),
|
||||
Token::SelfClose(*S),
|
||||
Token::Close(root, *S),
|
||||
Token::Close(None, *S),
|
||||
Token::Close(Some(root), *S),
|
||||
]
|
||||
.into_iter()
|
||||
.write_new(Default::default())?;
|
||||
|
|
Loading…
Reference in New Issue