-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is there a way to traverse the AST? #501
Comments
Traversal is implemented both for rust and javascript, but there's no untyped traversal yet. In rust, you need to turn on specialization and implement In javascript, you can use |
@anurbol In rust, almost all of /ecmascript/transforms are example of type-based ast traversal |
Wow, great! I'll look there! Thanks for all the help! I'll do my best to make a universal (untyped) traversal and contribute, if I'll manage to do that. |
Until then closing this issue... |
I am back to this problem. Wow this was harder than I thought. I have spent hours reading the SWC source code, including Transforms, and I now have some (very basic) idea of how stuff works, but I don't know how to apply it to my use case (without writing mountains of code). So as far as I understand, I need to write something like this:
Did I get the idea? If yes, then, do I really have to implement
What do you think? Will it work? Disclaimer: the code may be horribly wrong, silly etc. |
If you only need to process comment of each node, you can easily handle this with generic. impl<T> Fold<T> for CommentProcessor
where
T: FoldWith<Self> + Spanned,
{
fn fold(&mut self, n: T) -> T {
let span = n.span();
n.fold_children(self)
}
} If you need to specialize behavior of some type, you need to mark fold above as default impl and should add a implementation more special than |
Hey @kdy1 can we discuss this in Gitter? I messaged you there. I am facing problems with importing stuff. |
@anurbol I sent a message. |
@kdy1 Wow, seems to work great! Thanks! When you have some time could you please explain how P.S. For those who needs this: in Gitter chat I was told to have my Cargo.toml like this:
After that |
@anurbol procedural macro implements it.
output from cargo expand#![feature(prelude_import)]
#![feature(specialization)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
use swc_common::{Fold, FoldWith};
pub trait AssertFold<T>: Fold<T> {}
pub struct LitFold;
impl Fold<Lit> for LitFold {
fn fold(&mut self, _: Lit) -> Lit {
Lit::A
}
}
impl AssertFold<Expr> for LitFold {}
impl AssertFold<ExprKind> for LitFold {}
pub struct Expr {
pub node: ExprKind,
/// This field should be skipped.
pub bool_field: bool,
/// Ensure that #[fold(ignore)] works.
#[fold(ignore)]
pub ignored: PanicOnFold,
}
const IMPL_FOLD_FOR_Expr: () = {
impl<__Fold> swc_common::FoldWith<__Fold> for Expr {
#[inline]
#[allow(clippy::needless_return)]
fn fold_children(self, _f: &mut __Fold) -> Self {
match self {
Expr {
node: _node,
bool_field: _bool_field,
ignored: _ignored,
} => {
return Expr {
node: swc_common::Fold::<ExprKind>::fold(_f, _node),
bool_field: _bool_field,
ignored: _ignored,
};
}
}
}
}
impl<__V> swc_common::VisitWith<__V> for Expr {
#[inline]
fn visit_children(&self, _v: &mut __V) {
match *self {
Expr {
node: ref _node,
bool_field: ref _bool_field,
ignored: ref _ignored,
} => {
swc_common::Visit::<ExprKind>::visit(_v, _node);
}
}
}
}
};
pub struct PanicOnFold;
impl<F> FoldWith<F> for PanicOnFold {
fn fold_children(self, _: &mut F) -> Self {
{
{
{
::std::rt::begin_panic_fmt(
&::core::fmt::Arguments::new_v1(
&["internal error: entered unreachable code: "],
&match (&"this should not be called",) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
),
&("macros/ast_node/tests/fold_simple.rs", 35u32, 9u32),
)
}
}
}
}
}
pub enum ExprKind {
RecursiveBoud(Box<Expr>),
Rec2(Vec<Option<Box<Expr>>>),
Lit(Lit),
}
const IMPL_FOLD_FOR_ExprKind: () = {
impl<__Fold> swc_common::FoldWith<__Fold> for ExprKind {
#[inline]
#[allow(clippy::needless_return)]
fn fold_children(self, _f: &mut __Fold) -> Self {
match self {
ExprKind::RecursiveBoud(_0) => {
return ExprKind::RecursiveBoud {
0: swc_common::Fold::<Box<Expr>>::fold(_f, _0),
};
}
ExprKind::Rec2(_0) => {
return ExprKind::Rec2 {
0: swc_common::Fold::<Vec<Option<Box<Expr>>>>::fold(_f, _0),
};
}
ExprKind::Lit(_0) => {
return ExprKind::Lit {
0: swc_common::Fold::<Lit>::fold(_f, _0),
};
}
}
}
}
impl<__V> swc_common::VisitWith<__V> for ExprKind {
#[inline]
fn visit_children(&self, _v: &mut __V) {
match *self {
ExprKind::RecursiveBoud(ref _0) => {
swc_common::Visit::<Box<Expr>>::visit(_v, _0);
}
ExprKind::Rec2(ref _0) => {
swc_common::Visit::<Vec<Option<Box<Expr>>>>::visit(_v, _0);
}
ExprKind::Lit(ref _0) => {
swc_common::Visit::<Lit>::visit(_v, _0);
}
}
}
}
};
pub enum Lit {
A,
B,
}
const IMPL_FOLD_FOR_Lit: () = {
impl<__Fold> swc_common::FoldWith<__Fold> for Lit {
#[inline]
#[allow(clippy::needless_return)]
fn fold_children(self, _f: &mut __Fold) -> Self {
match self {
Lit::A => {
return Lit::A;
}
Lit::B => {
return Lit::B;
}
}
}
}
impl<__V> swc_common::VisitWith<__V> for Lit {
#[inline]
fn visit_children(&self, _v: &mut __V) {
match *self {
Lit::A => {}
Lit::B => {}
}
}
}
};
#[main]
pub fn main() -> () {
extern crate test;
test::test_main_static(&[])
}
As you can see, there's There's one more magic left. Lines 91 to 107 in 42ad8a9
With this default implementation, all types implements Note that this magic is based on specialization, so you need nightly rust. |
Well this is a bit hard to understand, but thanks for posting! It's a great reference for future me (when I need this again) or others when someone is interested. Specialization is easy (and I have utilized it as you said) if compared to this macro madness :') |
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
Some parsers have a way to traverse an AST down from the root node to the leaf nodes. Something like this:
Is there something similar in SWC? I've searched and didn't find, so I think there's not, but I'd like to be sure.
Or maybe I am missing some nice idiomatic to Rust way to traverse SWC-generated AST?
The text was updated successfully, but these errors were encountered: