kodept_macros/
erased.rs

1use std::any::Any;
2
3use kodept_ast::graph::{ChangeSet, AnyNode, PermTkn, RefMut, RefNode};
4use kodept_ast::utils::Execution;
5use kodept_ast::visit_side::{VisitGuard, VisitSide};
6use kodept_core::ConvertibleToRef;
7use kodept_core::structure::Located;
8
9use crate::error::report::ReportMessage;
10use crate::Macro;
11use crate::traits::{Context, UnrecoverableError};
12
13pub trait CanErase<C: Context> {
14    type Error;
15
16    fn erase(self) -> BoxedMacro<C, Self::Error>;
17    fn into_any(self: Box<Self>) -> Box<dyn Any>;
18}
19
20pub trait ErasedMacro<C: Context>: CanErase<C> {
21    fn transform(
22        &mut self,
23        node: RefNode,
24        side: VisitSide,
25        token: &mut PermTkn,
26        context: &mut C,
27    ) -> Execution<Self::Error, ChangeSet>;
28}
29
30pub type BoxedMacro<C, E> = Box<dyn ErasedMacro<C, Error = E>>;
31
32impl<C, T, E: Into<ReportMessage>> CanErase<C> for T
33where
34    T: Macro<Error = E> + 'static,
35    C: Context,
36    AnyNode: ConvertibleToRef<T::Node>,
37{
38    type Error = UnrecoverableError;
39
40    fn erase(self) -> BoxedMacro<C, Self::Error> {
41        Box::new(self)
42    }
43
44    fn into_any(self: Box<Self>) -> Box<dyn Any> {
45        self
46    }
47}
48
49impl<C, T, E: Into<ReportMessage>> ErasedMacro<C> for T
50where
51    C: Context,
52    T: Macro<Error = E> + 'static,
53    AnyNode: ConvertibleToRef<T::Node>,
54{
55    fn transform(
56        &mut self,
57        node: RefNode,
58        side: VisitSide,
59        token: &mut PermTkn,
60        context: &mut C,
61    ) -> Execution<Self::Error, ChangeSet> {
62        let Some(_) = node.ro(token).try_as_ref() else {
63            return Execution::Skipped;
64        };
65        let exec = <Self as Macro>::transform(
66            self,
67            VisitGuard::new(side, RefMut::new(node), token),
68            context,
69        );
70
71        match exec {
72            Execution::Failed(e) => {
73                let location = context
74                    .access_unknown(node.ro(token))
75                    .map_or(vec![], |it| vec![it.location()]);
76                match context.report_and_fail::<E, ()>(location, e) {
77                    Ok(_) => unreachable!(),
78                    Err(report) => Execution::Failed(report),
79                }
80            }
81            Execution::Completed(x) => Execution::Completed(x),
82            Execution::Skipped => Execution::Skipped,
83        }
84    }
85}