tamer: xir::parse::ele: Visibility specifier

We need to be able to export generated identifiers.  Trying to figure out a
syntax for this was a bit tricky considering how much is generated, so I
just settled on something that's reasonably clear and easy to parse with
`macro_rules!`.

I had intended to just make everything public by default and encapsulate
using private modules, but that then required making everything else that it
uses public (e.g. error and token objects), which would have been a bizarre
thing to do in e.g. test cases.

DEV-7145
main
Mike Gerwitz 2022-07-21 14:56:43 -04:00
parent acced76788
commit 0504788a16
3 changed files with 55 additions and 18 deletions

View File

@ -228,6 +228,7 @@ pub fn parse_attrs<S: AttrParseState>(ele: QName, span: OpenSpan) -> S {
#[macro_export]
macro_rules! attr_parse {
($(#[$sattr:meta])*
$(vis($vis:vis);)?
$(type ValueError = $evty:ty;)?
struct $state_name:ident -> $struct_name:ident {
@ -256,7 +257,7 @@ macro_rules! attr_parse {
/// This object is exposed for recovery and error reporting on
/// [`AttrParseError::MissingRequired`].
#[derive(Debug, PartialEq, Eq)]
struct $state_name {
$($vis)? struct $state_name {
#[doc(hidden)]
___ctx: (crate::xir::QName, crate::xir::OpenSpan),
#[doc(hidden)]
@ -358,7 +359,7 @@ macro_rules! attr_parse {
"`]."
)]
#[derive(Debug, PartialEq)]
struct $struct_name {
$($vis)? struct $struct_name {
$(
$(#[$fattr])*
pub $field: $ty,

View File

@ -40,54 +40,61 @@ pub struct EleParseCfg {
#[macro_export]
macro_rules! ele_parse {
(
$(vis($vis:vis);)?
// 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)*);
ele_parse!(@!nonterm_decl <$objty, $($evty)?> $($vis)? $($rest)*);
};
(@!nonterm_decl <$objty:ty, $($evty:ty)?> $nt:ident := $($rest:tt)*) => {
ele_parse!(@!nonterm_def <$objty, $($evty)?> $nt $($rest)*);
(@!nonterm_decl <$objty:ty, $($evty:ty)?>
$vis:vis $nt:ident := $($rest:tt)*
) => {
ele_parse!(@!nonterm_def <$objty, $($evty)?> $vis $nt $($rest)*);
};
(@!nonterm_def <$objty:ty, $($evty:ty)?>
$nt:ident $qname:ident $(($($ntp:tt)*))?
$vis:vis $nt:ident $qname:ident $(($($ntp:tt)*))?
{ $($matches:tt)* } $($rest:tt)*
) => {
ele_parse!(@!ele_expand_body <$objty, $($evty)?>
$nt $qname ($($($ntp)*)?) $($matches)*
$vis $nt $qname ($($($ntp)*)?) $($matches)*
);
ele_parse! {
vis($vis);
$(type AttrValueError = $evty;)?
type Object = $objty;
$($rest)*
}
};
(@!nonterm_def <$objty:ty, $($evty:ty)?> $nt:ident
(@!nonterm_def <$objty:ty, $($evty:ty)?>
$vis:vis $nt:ident
($ntref_first:ident $(| $ntref:ident)+); $($rest:tt)*
) => {
ele_parse!(@!ele_dfn_sum <$objty>
$nt [$ntref_first $($ntref)*]
$vis $nt [$ntref_first $($ntref)*]
);
ele_parse! {
vis($vis);
$(type AttrValueError = $evty;)?
type Object = $objty;
$($rest)*
}
};
(@!nonterm_decl <$objty:ty, $($evty:ty)?>) => {};
(@!nonterm_decl <$objty:ty, $($evty:ty)?> $vis:vis) => {};
// Expand the provided data to a more verbose form that provides the
// context necessary for state transitions.
(@!ele_expand_body <$objty:ty, $($evty:ty)?>
$nt:ident $qname:ident ($($ntp:tt)*)
$vis:vis $nt:ident $qname:ident ($($ntp:tt)*)
@ { $($attrbody:tt)* } => $attrmap:expr,
$(/$(($close_span:ident))? => $closemap:expr,)?
@ -99,7 +106,7 @@ macro_rules! ele_parse {
)*
) => {
ele_parse! {
@!ele_dfn_body <$objty, $($evty)?> $nt $qname ($($ntp)*)
@!ele_dfn_body <$objty, $($evty)?> $vis $nt $qname ($($ntp)*)
@ { $($attrbody)* } => $attrmap,
/$($($close_span)?)? => ele_parse!(@!ele_close $($closemap)?),
@ -144,7 +151,7 @@ macro_rules! ele_parse {
};
(@!ele_dfn_body <$objty:ty, $($evty:ty)?>
$nt:ident $qname:ident ($($open_span:ident)?)
$vis:vis $nt:ident $qname:ident ($($open_span:ident)?)
// Attribute definition special form.
@ {
@ -177,6 +184,7 @@ macro_rules! ele_parse {
) => {
paste::paste! {
crate::attr_parse! {
vis($vis);
$(type ValueError = $evty;)?
struct [<$nt AttrsState_>] -> [<$nt Attrs_>] {
@ -189,7 +197,7 @@ macro_rules! ele_parse {
#[doc=concat!("Parser for element [`", stringify!($qname), "`].")]
#[derive(Debug, PartialEq, Eq, Default)]
enum $nt {
$vis enum $nt {
#[doc=concat!(
"Expecting opening tag for element [`",
stringify!($qname),
@ -297,7 +305,7 @@ macro_rules! ele_parse {
}
#[derive(Debug, PartialEq)]
enum [<$nt Error_>] {
$vis enum [<$nt Error_>] {
/// An element was expected,
/// but the name of the element was unexpected.
UnexpectedEle_(crate::xir::QName, crate::span::Span),
@ -546,7 +554,7 @@ macro_rules! ele_parse {
}
};
(@!ele_dfn_sum <$objty:ty> $nt:ident [$($ntref:ident)*]) => {
(@!ele_dfn_sum <$objty:ty> $vis:vis $nt:ident [$($ntref:ident)*]) => {
$(
// Provide a (hopefully) helpful error that can be corrected
// rather than any obscure errors that may follow from trying
@ -561,7 +569,7 @@ macro_rules! ele_parse {
"."
)]
#[derive(Debug, PartialEq, Eq, Default)]
enum $nt {
$vis enum $nt {
#[default]
Expecting_,
/// Recovery state ignoring all remaining tokens for this
@ -618,7 +626,7 @@ macro_rules! ele_parse {
}
#[derive(Debug, PartialEq)]
enum [<$nt Error_>] {
$vis enum [<$nt Error_>] {
UnexpectedEle_(crate::xir::QName, crate::span::Span),
$(
$ntref([<$ntref Error_>]),

View File

@ -1227,3 +1227,31 @@ fn sum_repetition() {
Sut::parse(toks.into_iter()).collect(),
);
}
// Ensure that we can actually export the generated identifiers
// (add visibility to them).
// We don't want to always make them public by default because then Rust
// forces us to make any other objects they use public,
// which is annoying and confusing for things like test cases.
// Otherwise it wouldn't pose much of a practical issue,
// since we could still encapsulate default-pub identifiers within private
// modules.
//
// This will fail at compile time if there's a problem.
pub use test_exportable_generated_idents::ExportMe;
mod test_exportable_generated_idents {
use super::*;
ele_parse! {
// This is the line that determines visibility of all identifiers
// generated within this macro invocation.
vis(pub);
type Object = ();
ExportMe := QN_PACKAGE {
@ {} => (),
}
}
}