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
parent
61e493066c
commit
a49ac23aeb
|
@ -393,7 +393,7 @@ pub enum Stack<Ix: SymbolIndexSize> {
|
||||||
|
|
||||||
/// An attribute is awaiting its value,
|
/// An attribute is awaiting its value,
|
||||||
/// after which it will be attached to an element.
|
/// 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> {
|
impl<Ix: SymbolIndexSize> Default for Stack<Ix> {
|
||||||
|
@ -476,10 +476,8 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
|
||||||
/// value via [`Stack::close_attr`].
|
/// value via [`Stack::close_attr`].
|
||||||
fn open_attr(self, name: QName<Ix>, span: Span) -> Result<Self, Ix> {
|
fn open_attr(self, name: QName<Ix>, span: Span) -> Result<Self, Ix> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
// TODO: this drops the parent stack!
|
Self::BuddingElement(ele_stack) => {
|
||||||
Self::BuddingElement(ElementStack { element, pstack }) => {
|
Self::EleAttrName(ele_stack, name, span)
|
||||||
assert!(pstack.is_none(), "TODO: child element attributes");
|
|
||||||
Self::EleAttrName(element, name, span)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => todo! {},
|
_ => todo! {},
|
||||||
|
@ -490,18 +488,15 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
|
||||||
/// element.
|
/// element.
|
||||||
fn close_attr(self, value: AttrValue<Ix>, span: Span) -> Result<Self, Ix> {
|
fn close_attr(self, value: AttrValue<Ix>, span: Span) -> Result<Self, Ix> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::EleAttrName(mut element, name, open_span) => {
|
Self::EleAttrName(mut ele_stack, name, open_span) => {
|
||||||
element.attrs.push(Attr {
|
// TODO: Demeter
|
||||||
|
ele_stack.element.attrs.push(Attr {
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
span: (open_span, span),
|
span: (open_span, span),
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: ...see (parent stack lost)!
|
Stack::BuddingElement(ele_stack)
|
||||||
Stack::BuddingElement(ElementStack {
|
|
||||||
element,
|
|
||||||
pstack: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_ => todo! {},
|
_ => todo! {},
|
||||||
})
|
})
|
||||||
|
@ -737,6 +732,8 @@ mod test {
|
||||||
Span::from_byte_interval((0, 0), "test case, 1".intern());
|
Span::from_byte_interval((0, 0), "test case, 1".intern());
|
||||||
static ref S2: Span =
|
static ref S2: Span =
|
||||||
Span::from_byte_interval((0, 0), "test case, 2".intern());
|
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 {
|
mod tree {
|
||||||
|
@ -928,6 +925,45 @@ mod test {
|
||||||
assert_eq!(sut.next(), None);
|
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]
|
#[test]
|
||||||
fn parser_from_filters_incomplete() {
|
fn parser_from_filters_incomplete() {
|
||||||
let name = ("ns", "elem").unwrap_into();
|
let name = ("ns", "elem").unwrap_into();
|
||||||
|
|
Loading…
Reference in New Issue