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
Mike Gerwitz 2021-09-13 12:58:54 -04:00
parent 1c40b9c504
commit 51507ccdad
3 changed files with 32 additions and 38 deletions

View File

@ -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),

View File

@ -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 {

View File

@ -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())?;