From 51507ccdad5593e58baa93600292a0477e610084 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Mon, 13 Sep 2021 12:58:54 -0400 Subject: [PATCH] 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. --- tamer/src/ir/xir.rs | 18 +++++++++--------- tamer/src/ir/xir/tree.rs | 33 ++++++++++++++------------------- tamer/src/ir/xir/writer.rs | 19 +++++++++---------- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/tamer/src/ir/xir.rs b/tamer/src/ir/xir.rs index a7f8630a..afc2ea21 100644 --- a/tamer/src/ir/xir.rs +++ b/tamer/src/ir/xir.rs @@ -363,14 +363,8 @@ pub enum Token { /// 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, 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 { /// 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>, Span), /// Element attribute name AttrName(QName, Span), diff --git a/tamer/src/ir/xir/tree.rs b/tamer/src/ir/xir/tree.rs index 6986e569..e56cc78a 100644 --- a/tamer/src/ir/xir/tree.rs +++ b/tamer/src/ir/xir/tree.rs @@ -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 ParserState { 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::::Open(name, *S), - Token::::SelfClose(*S2), + Token::::Close(None, *S2), ]); let expected = Element { @@ -631,7 +626,7 @@ mod test { let toks = std::array::IntoIter::new([ Token::::Open(name, *S), - Token::::Close(name, *S2), + Token::::Close(Some(name), *S2), ]); let expected = Element { @@ -660,7 +655,7 @@ mod test { let toks = std::array::IntoIter::new([ Token::::Open(open_name, *S), - Token::::Close(close_name, *S2), + Token::::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::::Open(name, *S), Token::AttrName(attr, *S), Token::AttrValue(val, *S2), - Token::SelfClose(*S2), + Token::Close(None, *S2), ]); let expected = Element { diff --git a/tamer/src/ir/xir/writer.rs b/tamer/src/ir/xir/writer.rs index 0889cfd5..502332cd 100644 --- a/tamer/src/ir/xir/writer.rs +++ b/tamer/src/ir/xir/writer.rs @@ -181,15 +181,13 @@ impl XmlWriter for Token { 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 // ``. 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::::SelfClose(*S).write_new(WriterState::NodeOpen)?; + Token::::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::::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""); assert_eq!(result.1, WriterState::NodeExpected); @@ -382,7 +380,8 @@ mod test { fn closes_open_node_with_closing_tag() -> TestResult { let name = QName::::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">"); 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())?;