tamer: ir::xir::tree: Child element attribute parsing

This correctly retains and restores the parent stack after processing an
attribute for a child element.

This does increase the size of [`Stack`] a bit, but we can evaluate whether
it's too large at a later time.  It's currently 832 bits with `Ix=u32`,
which is large, but the question is whether it matters; we'll see as we
begin to use it.
main
Mike Gerwitz 2021-09-15 16:46:15 -04:00
parent 61e493066c
commit a49ac23aeb
1 changed files with 48 additions and 12 deletions

View File

@ -393,7 +393,7 @@ pub enum Stack<Ix: SymbolIndexSize> {
/// An attribute is awaiting its value,
/// after which it will be attached to an element.
EleAttrName(Element<Ix>, QName<Ix>, Span),
EleAttrName(ElementStack<Ix>, QName<Ix>, Span),
}
impl<Ix: SymbolIndexSize> Default for Stack<Ix> {
@ -476,10 +476,8 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// value via [`Stack::close_attr`].
fn open_attr(self, name: QName<Ix>, span: Span) -> Result<Self, Ix> {
Ok(match self {
// TODO: this drops the parent stack!
Self::BuddingElement(ElementStack { element, pstack }) => {
assert!(pstack.is_none(), "TODO: child element attributes");
Self::EleAttrName(element, name, span)
Self::BuddingElement(ele_stack) => {
Self::EleAttrName(ele_stack, name, span)
}
_ => todo! {},
@ -490,18 +488,15 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// element.
fn close_attr(self, value: AttrValue<Ix>, span: Span) -> Result<Self, Ix> {
Ok(match self {
Self::EleAttrName(mut element, name, open_span) => {
element.attrs.push(Attr {
Self::EleAttrName(mut ele_stack, name, open_span) => {
// TODO: Demeter
ele_stack.element.attrs.push(Attr {
name,
value,
span: (open_span, span),
});
// TODO: ...see (parent stack lost)!
Stack::BuddingElement(ElementStack {
element,
pstack: None,
})
Stack::BuddingElement(ele_stack)
}
_ => todo! {},
})
@ -737,6 +732,8 @@ mod test {
Span::from_byte_interval((0, 0), "test case, 1".intern());
static ref S2: Span =
Span::from_byte_interval((0, 0), "test case, 2".intern());
static ref S3: Span =
Span::from_byte_interval((0, 0), "test case, 3".intern());
}
mod tree {
@ -928,6 +925,45 @@ mod test {
assert_eq!(sut.next(), None);
}
// Ensures that attributes do not cause the parent context to be lost.
#[test]
fn element_with_child_with_attributes() {
let parent = "parent".unwrap_into();
let child = "child".unwrap_into();
let attr = "attr".unwrap_into();
let value = AttrValue::Escaped("attr value".into());
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(parent, *S),
Token::<Ix>::Open(child, *S),
Token::<Ix>::AttrName(attr, *S),
Token::<Ix>::AttrValue(value, *S2),
Token::<Ix>::Close(None, *S3),
Token::<Ix>::Close(Some(parent), *S3),
]);
let expected = Element {
name: parent,
attrs: AttrList::new(),
children: vec![Tree::Element(Element {
name: child,
attrs: AttrList::from([Attr {
name: attr,
value,
span: (*S, *S2),
}]),
children: vec![],
span: (*S, *S3),
})],
span: (*S, *S3),
};
let mut sut = parser_from(toks);
assert_eq!(sut.next(), Some(Ok(Tree::Element(expected))));
assert_eq!(sut.next(), None);
}
#[test]
fn parser_from_filters_incomplete() {
let name = ("ns", "elem").unwrap_into();