tamer: xir::parse: Fixes for {ele,attr}_parse! outside of module
The tests had certain things in scope, but now that I'm trying to use it outside of those modules, some fixes are needed. This is admittedly a sloppy commit, with a number of miscellaneous fixes. I didn't bother separating it more because most of them are type fixes, and the `From<Attr>` stuff is going to have to change into, likely, `TryFrom<Attr>` so that parse failures can occur when attributes do not match certain patterns. DEV-7145main
parent
e517e15a29
commit
184ff6bdcc
|
@ -25,4 +25,5 @@
|
|||
mod attr;
|
||||
mod ele;
|
||||
|
||||
pub use attr::{AttrParseError, AttrParseState};
|
||||
pub use attr::{parse_attrs, AttrParseError, AttrParseState};
|
||||
pub use ele::{EleParseCfg, EleParseState};
|
||||
|
|
|
@ -199,7 +199,6 @@ pub trait AttrParseState: ParseState {
|
|||
/// This function is useful when the type of [`AttrParseState`] `S` can be
|
||||
/// inferred,
|
||||
/// so that the expression reads more like natural language.
|
||||
#[cfg(test)] // currently only used by tests; remove when ready
|
||||
pub fn parse_attrs<S: AttrParseState>(ele: QName, span: OpenSpan) -> S {
|
||||
S::with_element(ele, span)
|
||||
}
|
||||
|
@ -219,7 +218,7 @@ macro_rules! attr_parse {
|
|||
// rather than relying on `Into::into` to cause the error
|
||||
// later on,
|
||||
// which places the error inside the macro definition.
|
||||
assert_impl_all!($ty: From<crate::xir::attr::Attr>);
|
||||
$crate::attr_parse!(@ty_assert $($fmod)? $ty);
|
||||
)*
|
||||
|
||||
#[doc=concat!("Parser producing [`", stringify!($struct_name), "`].")]
|
||||
|
@ -240,7 +239,7 @@ macro_rules! attr_parse {
|
|||
___done: bool,
|
||||
$(
|
||||
// Value + key span
|
||||
pub $field: Option<($ty, Span)>,
|
||||
pub $field: Option<($ty, crate::span::Span)>,
|
||||
)*
|
||||
}
|
||||
|
||||
|
@ -313,8 +312,11 @@ macro_rules! attr_parse {
|
|||
}
|
||||
|
||||
impl $state_name {
|
||||
fn done_with_element(ele: crate::xir::QName, span: OpenSpan) -> Self {
|
||||
use crate::xir::parse::attr::AttrParseState;
|
||||
fn done_with_element(
|
||||
ele: crate::xir::QName,
|
||||
span: crate::xir::OpenSpan,
|
||||
) -> Self {
|
||||
use crate::xir::parse::AttrParseState;
|
||||
|
||||
let mut new = Self::with_element(ele, span);
|
||||
new.___done = true;
|
||||
|
@ -374,7 +376,7 @@ macro_rules! attr_parse {
|
|||
parse::{AttrParseError, AttrParseState}
|
||||
};
|
||||
#[allow(unused_imports)]
|
||||
use crate::xir::attr::Attr; // unused if no attrs
|
||||
use crate::xir::attr::{Attr, AttrSpan}; // unused if no attrs
|
||||
|
||||
match tok {
|
||||
$(
|
||||
|
@ -402,7 +404,9 @@ macro_rules! attr_parse {
|
|||
// First time seeing attribute name
|
||||
None => {
|
||||
self.$field.replace((
|
||||
attr.into(),
|
||||
$crate::attr_parse!(
|
||||
@into_value $($fmod)? attr
|
||||
),
|
||||
kspan,
|
||||
));
|
||||
|
||||
|
@ -447,6 +451,26 @@ macro_rules! attr_parse {
|
|||
}
|
||||
};
|
||||
|
||||
// Optional attribute if input above is of the form `(QN_FOO?) => ...`.
|
||||
(@ty_assert ? $ty:ty) => {
|
||||
// This type assertion isn't supported by `assert_impl_all!`.
|
||||
// The error isn't the most clear,
|
||||
// but it's better than nothing and we can improve upon it later
|
||||
// on.
|
||||
const _: fn() = || {
|
||||
trait OptionFromAttr {}
|
||||
impl<T: From<Attr>> OptionFromAttr for Option<T> {}
|
||||
|
||||
// Fail when `$ty` is not Option<impl From<Attr>>.
|
||||
fn assert_attr_option<T: OptionFromAttr>() {}
|
||||
assert_attr_option::<$ty>();
|
||||
};
|
||||
};
|
||||
|
||||
(@ty_assert $ty:ty) => {
|
||||
assert_impl_all!($ty: From<crate::xir::attr::Attr>);
|
||||
};
|
||||
|
||||
// Optional attribute if input above is of the form `(QN_FOO?) => ...`.
|
||||
(@if_missing_req ? $from:ident.$field:ident $body:block) => {
|
||||
// This is an optional field;
|
||||
|
@ -460,6 +484,15 @@ macro_rules! attr_parse {
|
|||
}
|
||||
};
|
||||
|
||||
// Optional attribute if input above is of the form `(QN_FOO?) => ...`.
|
||||
(@into_value ? $from:ident) => {
|
||||
Some($from.into())
|
||||
};
|
||||
|
||||
(@into_value $from:ident) => {
|
||||
$from.into()
|
||||
};
|
||||
|
||||
// Optional attribute if input above is of the form `(QN_FOO?) => ...`.
|
||||
(@maybe_value ? $from:ident.$field:ident) => {
|
||||
// This does not produce a great error if the user forgets to use an
|
||||
|
|
|
@ -185,6 +185,26 @@ fn optional_with_values() {
|
|||
);
|
||||
}
|
||||
|
||||
// This test would fail at compile time.
|
||||
#[test]
|
||||
fn attr_value_into() {
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Foo;
|
||||
|
||||
impl From<Attr> for Foo {
|
||||
fn from(_: Attr) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
attr_parse! {
|
||||
struct OptValuesState -> OptValues {
|
||||
name: (QN_NAME) => Foo,
|
||||
yields: (QN_YIELDS?) => Option<Foo>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn optional_with_all_missing() {
|
||||
attr_parse! {
|
||||
|
|
|
@ -34,13 +34,13 @@ pub struct EleParseCfg {
|
|||
/// Whether to allow zero-or-more repetition for this element.
|
||||
///
|
||||
/// This is the Kleene star modifier (`*`).
|
||||
repeat: bool,
|
||||
pub repeat: bool,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ele_parse {
|
||||
(type Object = $objty:ty; $($rest:tt)*) => {
|
||||
ele_parse!(@!nonterm_decl <$objty> $($rest)*)
|
||||
ele_parse!(@!nonterm_decl <$objty> $($rest)*);
|
||||
};
|
||||
|
||||
(@!nonterm_decl <$objty:ty> $nt:ident := $($rest:tt)*) => {
|
||||
|
@ -138,7 +138,7 @@ macro_rules! ele_parse {
|
|||
// `$attrmap`.
|
||||
$(
|
||||
$(#[$fattr:meta])*
|
||||
$field:ident: ($fmatch:tt) => $fty:ty,
|
||||
$field:ident: ($($fmatch:tt)+) => $fty:ty,
|
||||
)*
|
||||
} => $attrmap:expr,
|
||||
|
||||
|
@ -165,7 +165,7 @@ macro_rules! ele_parse {
|
|||
struct [<$nt AttrsState_>] -> [<$nt Attrs_>] {
|
||||
$(
|
||||
$(#[$fattr])*
|
||||
$field: ($fmatch) => $fty,
|
||||
$field: ($($fmatch)+) => $fty,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,11 @@ macro_rules! ele_parse {
|
|||
Expecting_,
|
||||
/// Recovery state ignoring all remaining tokens for this
|
||||
/// element.
|
||||
RecoverEleIgnore_(crate::xir::QName, crate::xir::OpenSpan, Depth),
|
||||
RecoverEleIgnore_(
|
||||
crate::xir::QName,
|
||||
crate::xir::OpenSpan,
|
||||
crate::xir::flat::Depth
|
||||
),
|
||||
// Recovery completed because end tag corresponding to the
|
||||
// invalid element has been found.
|
||||
RecoverEleIgnoreClosed_(crate::xir::QName, crate::xir::CloseSpan),
|
||||
|
@ -193,19 +197,28 @@ macro_rules! ele_parse {
|
|||
/// may be a child element,
|
||||
/// but it may be text,
|
||||
/// for example.
|
||||
CloseRecoverIgnore_((crate::span::Span, Depth), crate::span::Span),
|
||||
CloseRecoverIgnore_(
|
||||
(crate::span::Span, crate::xir::flat::Depth),
|
||||
crate::span::Span
|
||||
),
|
||||
/// Parsing element attributes.
|
||||
Attrs_((crate::span::Span, Depth), [<$nt AttrsState_>]),
|
||||
Attrs_(
|
||||
(crate::span::Span, crate::xir::flat::Depth),
|
||||
[<$nt AttrsState_>]
|
||||
),
|
||||
$(
|
||||
$ntref((crate::span::Span, Depth), $ntref),
|
||||
$ntref(
|
||||
(crate::span::Span, crate::xir::flat::Depth),
|
||||
$ntref
|
||||
),
|
||||
)*
|
||||
ExpectClose_((crate::span::Span, Depth), ()),
|
||||
ExpectClose_((crate::span::Span, crate::xir::flat::Depth), ()),
|
||||
/// Closing tag found and parsing of the element is
|
||||
/// complete.
|
||||
Closed_(crate::span::Span),
|
||||
}
|
||||
|
||||
impl crate::xir::parse::ele::EleParseState for $nt {}
|
||||
impl crate::xir::parse::EleParseState for $nt {}
|
||||
|
||||
impl $nt {
|
||||
/// [`QName`](crate::xir::QName) of the element recognized
|
||||
|
@ -376,7 +389,7 @@ macro_rules! ele_parse {
|
|||
type Token = crate::xir::flat::XirfToken;
|
||||
type Object = $objty;
|
||||
type Error = [<$nt Error_>];
|
||||
type Context = crate::parse::Context<crate::xir::parse::ele::EleParseCfg>;
|
||||
type Context = crate::parse::Context<crate::xir::parse::EleParseCfg>;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
|
@ -386,8 +399,9 @@ macro_rules! ele_parse {
|
|||
use crate::{
|
||||
parse::{EmptyContext, Transition, Transitionable},
|
||||
xir::{
|
||||
EleSpan,
|
||||
flat::XirfToken,
|
||||
parse::attr::parse_attrs,
|
||||
parse::parse_attrs,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue