tamer: xir::parse::ele: AttrValueError for attr_parse!'s ValueError

This integrates the previous ValueError for `attr_parse!` into
`ele_parse!`.

DEV-7145
main
Mike Gerwitz 2022-07-21 09:23:34 -04:00
parent 3a764d111e
commit 992c000b68
2 changed files with 74 additions and 17 deletions

View File

@ -39,42 +39,55 @@ pub struct EleParseCfg {
#[macro_export]
macro_rules! ele_parse {
(type Object = $objty:ty; $($rest:tt)*) => {
ele_parse!(@!nonterm_decl <$objty> $($rest)*);
(
// Attr has to be first to avoid ambiguity with `$rest`.
$(type AttrValueError = $evty:ty;)?
type Object = $objty:ty;
$($rest:tt)*
) => {
ele_parse!(@!nonterm_decl <$objty, $($evty)?> $($rest)*);
};
(@!nonterm_decl <$objty:ty> $nt:ident := $($rest:tt)*) => {
ele_parse!(@!nonterm_def <$objty> $nt $($rest)*);
(@!nonterm_decl <$objty:ty, $($evty:ty)?> $nt:ident := $($rest:tt)*) => {
ele_parse!(@!nonterm_def <$objty, $($evty)?> $nt $($rest)*);
};
(@!nonterm_def <$objty:ty>
(@!nonterm_def <$objty:ty, $($evty:ty)?>
$nt:ident $qname:ident $(($($ntp:tt)*))?
{ $($matches:tt)* } $($rest:tt)*
) => {
ele_parse!(@!ele_expand_body <$objty> $nt $qname ($($($ntp)*)?) $($matches)*);
ele_parse!(@!ele_expand_body <$objty, $($evty)?>
$nt $qname ($($($ntp)*)?) $($matches)*
);
ele_parse! {
$(type AttrValueError = $evty;)?
type Object = $objty;
$($rest)*
}
};
(@!nonterm_def <$objty:ty> $nt:ident
(@!nonterm_def <$objty:ty, $($evty:ty)?> $nt:ident
($ntref_first:ident $(| $ntref:ident)+); $($rest:tt)*
) => {
ele_parse!(@!ele_dfn_sum <$objty> $nt [$ntref_first $($ntref)*]);
ele_parse!(@!ele_dfn_sum <$objty>
$nt [$ntref_first $($ntref)*]
);
ele_parse! {
$(type AttrValueError = $evty;)?
type Object = $objty;
$($rest)*
}
};
(@!nonterm_decl <$objty:ty>) => {};
(@!nonterm_decl <$objty:ty, $($evty:ty)?>) => {};
// Expand the provided data to a more verbose form that provides the
// context necessary for state transitions.
(@!ele_expand_body <$objty:ty> $nt:ident $qname:ident ($($ntp:tt)*)
(@!ele_expand_body <$objty:ty, $($evty:ty)?>
$nt:ident $qname:ident ($($ntp:tt)*)
@ { $($attrbody:tt)* } => $attrmap:expr,
$(/$(($close_span:ident))? => $closemap:expr,)?
@ -86,7 +99,7 @@ macro_rules! ele_parse {
)*
) => {
ele_parse! {
@!ele_dfn_body <$objty> $nt $qname ($($ntp)*)
@!ele_dfn_body <$objty, $($evty)?> $nt $qname ($($ntp)*)
@ { $($attrbody)* } => $attrmap,
/$($($close_span)?)? => ele_parse!(@!ele_close $($closemap)?),
@ -130,7 +143,9 @@ macro_rules! ele_parse {
Self::Context::default()
};
(@!ele_dfn_body <$objty:ty> $nt:ident $qname:ident ($($open_span:ident)?)
(@!ele_dfn_body <$objty:ty, $($evty:ty)?>
$nt:ident $qname:ident ($($open_span:ident)?)
// Attribute definition special form.
@ {
// We must lightly parse attributes here so that we can retrieve
@ -162,6 +177,8 @@ macro_rules! ele_parse {
) => {
paste::paste! {
crate::attr_parse! {
$(type ValueError = $evty;)?
struct [<$nt AttrsState_>] -> [<$nt Attrs_>] {
$(
$(#[$fattr])*

View File

@ -32,6 +32,8 @@
//! the system,
//! simply force the test to panic at the end.
use std::{error::Error, fmt::Display};
use crate::{
convert::ExpectInto,
diagnose::Diagnostic,
@ -169,7 +171,45 @@ fn empty_element_with_attr_bindings() {
struct Foo(SymbolId, SymbolId, (Span, Span));
impl Object for Foo {}
#[derive(Debug, PartialEq, Eq)]
struct AttrVal(Attr);
impl TryFrom<Attr> for AttrVal {
// Type must match AttrValueError on `ele_parse!`
type Error = AttrValueError;
fn try_from(attr: Attr) -> Result<Self, Self::Error> {
Ok(AttrVal(attr))
}
}
#[derive(Debug, PartialEq)]
enum AttrValueError {}
impl Error for AttrValueError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
impl Display for AttrValueError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
unimplemented!()
}
}
impl Diagnostic for AttrValueError {
fn describe(&self) -> Vec<crate::diagnose::AnnotatedSpan> {
unimplemented!()
}
}
ele_parse! {
// AttrValueError should be passed to `attr_parse!`
// (which is invoked by `ele_parse!`)
// as ValueError.
type AttrValueError = AttrValueError;
type Object = Foo;
// In practice we wouldn't actually use Attr
@ -177,12 +217,12 @@ fn empty_element_with_attr_bindings() {
// but for the sake of this test we'll keep things simple.
Sut := QN_PACKAGE {
@ {
name: (QN_NAME) => Attr,
value: (QN_VALUE) => Attr,
name: (QN_NAME) => AttrVal,
value: (QN_VALUE) => AttrVal,
} => Foo(
name.value(),
value.value(),
(name.attr_span().value_span(), value.attr_span().value_span())
name.0.value(),
value.0.value(),
(name.0.attr_span().value_span(), value.0.attr_span().value_span())
),
}
}