use crate::ast::*;
macro_rules! mk {
(@visit_inner_call, Span, $self:ident, $x:expr) => {::std::ops::ControlFlow::Continue(())};
(@visit_inner_call, GloablId, $self:ident, $x:expr) => {::std::ops::ControlFlow::Continue(())};
(@visit_inner_call, $ty:ty, $self:ident, $x:expr) => {
$self.visit_inner($x)
};
($($ty:ident),*) => {
#[derive_group_for_ast]
#[derive(Copy)]
pub enum FragmentTypeId {
$(
#[doc = concat!("An identifier for the type [`", stringify!($ty), "`].")]
$ty,
)*
}
mod private {
pub use super::*;
pub trait Sealed {}
$(impl Sealed for $ty {})*
}
pub trait AnyFragment: private::Sealed {
fn type_id() -> FragmentTypeId;
fn as_fragment<'a>(&'a self, type_id: FragmentTypeId) -> Option<FragmentRef<'a>>;
fn as_owned_fragment(&self, type_id: FragmentTypeId) -> Option<Fragment>;
}
$(
impl AnyFragment for $ty {
fn type_id() -> FragmentTypeId {
FragmentTypeId::$ty
}
fn as_fragment<'a>(&'a self, type_id: FragmentTypeId) -> Option<FragmentRef<'a>> {
if type_id == Self::type_id() {
Some(self.into())
} else {
None
}
}
fn as_owned_fragment(&self, type_id: FragmentTypeId) -> Option<Fragment> {
if type_id == Self::type_id() {
#[allow(unreachable_code)]
Some(self.clone().into())
} else {
None
}
}
}
)*
pub struct FragmentMarker {
addr: usize,
type_id: fragment::FragmentTypeId,
}
impl FragmentMarker {
pub fn new<T: AnyFragment>(value: &T) -> Self {
Self {
addr: (value as *const T).addr(),
type_id: T::type_id(),
}
}
}
impl<'a> derive_generic_visitor::Visitor for FragmentMarker {
type Break = Fragment;
}
impl visitors::AstEarlyExitVisitor for FragmentMarker {
$(
pastey::paste!{
fn [<visit_ $ty:snake>](&mut self, x: &$ty) -> ::std::ops::ControlFlow<Self::Break> {
if self.addr == (x as *const $ty).addr()
&& let Some(fragment) = x.as_owned_fragment(self.type_id)
{
return ::std::ops::ControlFlow::Break(fragment);
}
mk!(@visit_inner_call, $ty, self, x)
}
}
)*
}
#[derive_group_for_ast]
#[allow(missing_docs)]
pub enum Fragment {
$(
#[doc = concat!("An owned [`", stringify!($ty), "`] node.")]
$ty($ty),
)*
Unknown(String),
}
#[derive(Copy)]
#[derive_group_for_ast_base]
#[derive(::serde::Serialize)]
#[allow(missing_docs)]
pub enum FragmentRef<'lt> {
$(
#[doc = concat!("A borrowed [`", stringify!($ty), "`] node.")]
$ty(&'lt $ty),
)*
}
$(
impl From<$ty> for Fragment {
fn from(fragment: $ty) -> Self {
Self::$ty(fragment)
}
}
impl<'lt> From<&'lt $ty> for FragmentRef<'lt> {
fn from(fragment: &'lt $ty) -> Self {
Self::$ty(fragment)
}
}
)*
};
}
#[hax_rust_engine_macros::replace(AstNodes => include(VisitableAstNodes))]
mk!(GlobalId, Span, AstNodes);