tamer: xir::parse::ele: Initial Close mapping support
Since the parsers produce streaming IRs, we need to be able to emit tokens representing closing delimiters, where they are important. This notably doesn't use spans; I'll add those next, since they're also needed for the previous work. DEV-7145main
parent
c30c0e268d
commit
cceb8c7fb9
|
@ -307,3 +307,9 @@ where
|
|||
Transition(to).result(self.map(|_| ParseStatus::Incomplete))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ParseState> Transitionable<S> for ParseStatus<S> {
|
||||
fn transition(self, to: S) -> TransitionResult<S> {
|
||||
Transition(to).ok(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ macro_rules! ele_parse {
|
|||
// context necessary for state transitions.
|
||||
(@!ele_expand_body <$objty:ty> $nt:ident $qname:ident
|
||||
@ { $($attrbody:tt)* } => $attrmap:expr,
|
||||
$(/ => $closemap:expr,)?
|
||||
|
||||
// Nonterminal references are provided as a list.
|
||||
$(
|
||||
|
@ -61,6 +62,7 @@ macro_rules! ele_parse {
|
|||
ele_parse! {
|
||||
@!ele_dfn_body <$objty> $nt $qname
|
||||
@ { $($attrbody)* } => $attrmap,
|
||||
/ => ele_parse!(@!ele_close $($closemap)?),
|
||||
|
||||
<> {
|
||||
$(
|
||||
|
@ -79,6 +81,16 @@ macro_rules! ele_parse {
|
|||
}
|
||||
};
|
||||
|
||||
// No explicit Close mapping defaults to doing nothing at all
|
||||
// (so yield Incomplete).
|
||||
(@!ele_close) => {
|
||||
crate::parse::ParseStatus::Incomplete
|
||||
};
|
||||
|
||||
(@!ele_close $close:expr) => {
|
||||
crate::parse::ParseStatus::Object($close)
|
||||
};
|
||||
|
||||
(@!ele_dfn_body <$objty:ty> $nt:ident $qname:ident
|
||||
// Attribute definition special form.
|
||||
@ {
|
||||
|
@ -91,6 +103,10 @@ macro_rules! ele_parse {
|
|||
)*
|
||||
} => $attrmap:expr,
|
||||
|
||||
// Close expression
|
||||
// (defaulting to Incomplete via @!ele_expand_body).
|
||||
/ => $closemap:expr,
|
||||
|
||||
// Nonterminal references.
|
||||
<> {
|
||||
$(
|
||||
|
@ -247,7 +263,7 @@ macro_rules! ele_parse {
|
|||
_: crate::parse::NoContext,
|
||||
) -> crate::parse::TransitionResult<Self> {
|
||||
use crate::{
|
||||
parse::{EmptyContext, Transition},
|
||||
parse::{EmptyContext, Transition, Transitionable},
|
||||
xir::{
|
||||
flat::XirfToken,
|
||||
parse::attr::parse_attrs,
|
||||
|
@ -316,7 +332,7 @@ macro_rules! ele_parse {
|
|||
// XIRF ensures proper nesting,
|
||||
// so this must be our own closing tag.
|
||||
(ExpectClose_(_), XirfToken::Close(_, span, _)) =>
|
||||
Transition(Closed_(span.tag_span())).incomplete(),
|
||||
$closemap.transition(Closed_(span.tag_span())),
|
||||
|
||||
// TODO: Use `is_accepting` guard if we do not utilize
|
||||
// exhaustiveness check.
|
||||
|
|
|
@ -49,7 +49,7 @@ const S6: Span = S5.offset_add(1).unwrap();
|
|||
const N: EleNameLen = 10;
|
||||
|
||||
#[test]
|
||||
fn empty_element_no_attrs() {
|
||||
fn empty_element_no_attrs_no_close() {
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Foo;
|
||||
impl Object for Foo {}
|
||||
|
@ -70,9 +70,46 @@ fn empty_element_no_attrs() {
|
|||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
Parsed::Incomplete, // Open
|
||||
Parsed::Object(Foo), // Close (store LA)
|
||||
Parsed::Incomplete, // Close (take LA)
|
||||
Parsed::Incomplete, // [Sut] Open
|
||||
Parsed::Object(Foo), // [Sut@] Close (>LA)
|
||||
Parsed::Incomplete, // [Sut] Close (<LA)
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
}
|
||||
|
||||
// Same as above,
|
||||
// but with an object emitted on Close rather than Incomplete.
|
||||
#[test]
|
||||
fn empty_element_no_attrs_with_close() {
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Foo {
|
||||
Attr,
|
||||
Close,
|
||||
}
|
||||
|
||||
impl Object for Foo {}
|
||||
|
||||
ele_parse! {
|
||||
type Object = Foo;
|
||||
|
||||
Sut := QN_PACKAGE {
|
||||
@ {} => Foo::Attr,
|
||||
/ => Foo::Close,
|
||||
}
|
||||
}
|
||||
|
||||
let toks = vec![
|
||||
// Length (second argument) here is arbitrary.
|
||||
XirfToken::Open(QN_PACKAGE, OpenSpan(S1, N), Depth(0)),
|
||||
XirfToken::Close(None, CloseSpan::empty(S2), Depth(0)),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
Parsed::Incomplete, // [Sut] Open
|
||||
Parsed::Object(Foo::Attr), // [Sut@] Close (>LA)
|
||||
Parsed::Object(Foo::Close), // [Sut] Close (<LA)
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
@ -267,9 +304,12 @@ fn single_child_element() {
|
|||
fn multiple_child_elements_sequential() {
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Foo {
|
||||
Root,
|
||||
ChildA,
|
||||
ChildB,
|
||||
RootOpen,
|
||||
ChildAOpen,
|
||||
ChildAClose,
|
||||
ChildBOpen,
|
||||
ChildBClose,
|
||||
RootClose,
|
||||
}
|
||||
|
||||
impl Object for Foo {}
|
||||
|
@ -278,7 +318,8 @@ fn multiple_child_elements_sequential() {
|
|||
type Object = Foo;
|
||||
|
||||
Sut := QN_PACKAGE {
|
||||
@ {} => Foo::Root,
|
||||
@ {} => Foo::RootOpen,
|
||||
/ => Foo::RootClose,
|
||||
|
||||
// Order matters here.
|
||||
ChildA,
|
||||
|
@ -286,11 +327,13 @@ fn multiple_child_elements_sequential() {
|
|||
}
|
||||
|
||||
ChildA := QN_CLASSIFY {
|
||||
@ {} => Foo::ChildA,
|
||||
@ {} => Foo::ChildAOpen,
|
||||
/ => Foo::ChildAClose,
|
||||
}
|
||||
|
||||
ChildB := QN_EXPORT {
|
||||
@ {} => Foo::ChildB,
|
||||
@ {} => Foo::ChildBOpen,
|
||||
/ => Foo::ChildBClose,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,15 +350,15 @@ fn multiple_child_elements_sequential() {
|
|||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
Parsed::Incomplete, // [Sut] Root Open
|
||||
Parsed::Object(Foo::Root), // [Sut@] ChildA Open (>LA)
|
||||
Parsed::Incomplete, // [ChildA] ChildA Open (<LA)
|
||||
Parsed::Object(Foo::ChildA), // [ChildA@] ChildA Close (>LA)
|
||||
Parsed::Incomplete, // [ChildA] ChildA Close (<LA)
|
||||
Parsed::Incomplete, // [ChildB] ChildB Open
|
||||
Parsed::Object(Foo::ChildB), // [ChildB@] ChildB Close (>LA)
|
||||
Parsed::Incomplete, // [ChildB] ChildB Close (<LA)
|
||||
Parsed::Incomplete, // [Sut] Root Close
|
||||
Parsed::Incomplete, // [Sut] Root Open
|
||||
Parsed::Object(Foo::RootOpen), // [Sut@] ChildA Open (>LA)
|
||||
Parsed::Incomplete, // [ChildA] ChildA Open (<LA)
|
||||
Parsed::Object(Foo::ChildAOpen), // [ChildA@] ChildA Close (>LA)
|
||||
Parsed::Object(Foo::ChildAClose), // [ChildA] ChildA Close (<LA)
|
||||
Parsed::Incomplete, // [ChildB] ChildB Open
|
||||
Parsed::Object(Foo::ChildBOpen), // [ChildB@] ChildB Close (>LA)
|
||||
Parsed::Object(Foo::ChildBClose), // [ChildB] ChildB Close (<LA)
|
||||
Parsed::Object(Foo::RootClose), // [Sut] Root Close
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue