feat(visit): Add path-aware variants (#5073)

This commit is contained in:
Donny/강동윤 2022-07-05 13:38:27 +09:00 committed by GitHub
parent d2284f5f7e
commit 204d742ed6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1429 additions and 214 deletions

View File

@ -34,6 +34,14 @@
SWC (stands for `Speedy Web Compiler`) is a super-fast TypeScript / JavaScript compiler written in Rust. It's a library for Rust and JavaScript at the same time. If you are using SWC from Rust, see [rustdoc](https://rustdoc.swc.rs/swc/) and for most users, your entry point for using the library will be [parser](https://rustdoc.swc.rs/swc_ecma_parser/).
Also, SWC tries to ensure that
> If you select the latest version of each crates, it will work
for rust users. Without such guarantee, using SWC would be too hard as SWC is a large, modular project and typically you have to use many modules.
---
If you are using SWC from JavaScript, please refer to [docs on the website](https://swc.rs/docs/installation/).
# Documentation

View File

@ -8,11 +8,18 @@ name = "swc_css_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.94.0"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lib]
bench = false
[features]
path = []
[dependencies]
swc_atoms = {version = "0.2.7", path = "../swc_atoms"}
swc_common = { version = "0.20.0", path = "../swc_common"}
swc_common = {version = "0.20.0", path = "../swc_common"}
swc_css_ast = {version = "0.95.0", path = "../swc_css_ast"}
swc_visit = {version = "0.3.0", path = "../swc_visit"}

View File

@ -8,16 +8,21 @@ name = "swc_ecma_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.67.0"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lib]
bench = false
[features]
debug = []
path = []
[dependencies]
num-bigint = {version = "0.4", features = ["serde"]}
swc_atoms = {version = "0.2", path = "../swc_atoms"}
swc_common = { version = "0.20.0", path = "../swc_common"}
swc_common = {version = "0.20.0", path = "../swc_common"}
swc_ecma_ast = {version = "0.81.0", path = "../swc_ecma_ast"}
swc_visit = {version = "0.3.0", path = "../swc_visit"}
tracing = "0.1.32"

View File

@ -8,11 +8,18 @@ name = "swc_html_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.13.0"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lib]
bench = false
[features]
path = []
[dependencies]
swc_atoms = {version = "0.2.7", path = "../swc_atoms"}
swc_common = { version = "0.20.0", path = "../swc_common"}
swc_common = {version = "0.20.0", path = "../swc_common"}
swc_html_ast = {version = "0.13.0", path = "../swc_html_ast"}
swc_visit = {version = "0.3.0", path = "../swc_visit"}

1
crates/swc_visit/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
tests/expanded.rs

View File

@ -70,6 +70,18 @@
//! You can use your `Visit` implementation like `node.visit_with(&Invalid{
//! span: DUMMY_SP, }, &mut visitor`. I think API is mis-designed, but it works
//! and there are really lots of code using `Visit` already.
//!
//!
//!
//! # Cargo features
//!
//! You should add
//! ```toml
//! [features]
//! path = []
//! ```
//!
//! If you want to allow using path-aware visitor.
pub use either::Either;
pub use swc_visit_macros::define;
@ -191,3 +203,99 @@ where
self.second.reset();
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AstKindPath<K>
where
K: Copy,
{
path: Vec<K>,
}
impl<K> std::ops::Deref for AstKindPath<K>
where
K: Copy,
{
type Target = Vec<K>;
fn deref(&self) -> &Self::Target {
&self.path
}
}
impl<K> Default for AstKindPath<K>
where
K: Copy,
{
fn default() -> Self {
Self {
path: Default::default(),
}
}
}
impl<K> AstKindPath<K>
where
K: Copy,
{
pub fn new(path: Vec<K>) -> Self {
Self { path }
}
pub fn with<Ret>(&mut self, path: K, op: impl FnOnce(&mut Self) -> Ret) -> Ret {
self.path.push(path);
let ret = op(self);
self.path.pop();
ret
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AstNodePath<N>
where
N: Copy,
{
path: Vec<N>,
}
impl<N> std::ops::Deref for AstNodePath<N>
where
N: Copy,
{
type Target = Vec<N>;
fn deref(&self) -> &Self::Target {
&self.path
}
}
impl<N> Default for AstNodePath<N>
where
N: Copy,
{
fn default() -> Self {
Self {
path: Default::default(),
}
}
}
impl<N> AstNodePath<N>
where
N: Copy,
{
pub fn new(path: Vec<N>) -> Self {
Self { path }
}
pub fn with<F, Ret>(&mut self, node: N, op: F) -> Ret
where
F: for<'aa> FnOnce(&'aa mut AstNodePath<N>) -> Ret,
{
self.path.push(node);
let ret = op(self);
self.path.pop();
ret
}
}

View File

@ -4,10 +4,12 @@ use std::sync::Arc;
use swc_visit::define;
#[derive(Debug, PartialEq)]
pub struct Item {
pub item: Option<Arc<Item>>,
pub ref_to_enum: Option<Arc<Enum>>,
}
#[derive(Debug, PartialEq)]
pub enum Enum {
Item(Arc<Item>),
Items(Arc<Vec<Item>>),

View File

@ -9,14 +9,19 @@ pub trait Node: Any {}
impl<T: ?Sized> Node for T where T: Any {}
#[derive(Debug, PartialEq)]
pub struct Item {
// pub field: usize,
// pub inner: Option<Box<Item>>,
pub opt_vec: Option<Vec<Item>>,
pub vec_opt: Vec<Option<Item>>,
pub value: f64,
}
#[derive(Debug, PartialEq)]
pub enum Enum {
Item(Item),
Boxed(Box<Enum>),
}
define!({
@ -25,8 +30,11 @@ define!({
// pub inner: Option<Box<Item>>,
pub opt_vec: Option<Vec<Item>>,
pub vec_opt: Vec<Option<Item>>,
pub value: f64,
}
pub enum Enum {
Item(Item),
Boxed(Box<Enum>),
}
});

View File

@ -9,10 +9,12 @@ pub trait Node: Any {}
impl<T: ?Sized> Node for T where T: Any {}
#[derive(Debug, PartialEq)]
pub struct Item {
pub opt_vec1: Option<Vec<Item>>,
pub opt_vec2: Option<Vec<Enum>>,
}
#[derive(Debug, PartialEq)]
pub enum Enum {
Item(Item),
}

View File

@ -1,18 +1,13 @@
#![allow(clippy::ptr_arg)]
use std::any::Any;
use swc_visit::define;
/// Visitable nodes.
pub trait Node: Any {}
impl<T: ?Sized> Node for T where T: Any {}
#[derive(Debug, PartialEq)]
pub struct Item {
pub vec_opt1: Vec<Option<Item>>,
pub vec_opt2: Vec<Option<Enum>>,
}
#[derive(Debug, PartialEq)]
pub enum Enum {
Item(Item),
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
# Provide more information to visitor methods
- Status: accepted <!-- optional -->
- Deciders: @kdy1, @kwonoj <!-- optional -->
- Date: 2022-06-30 <!-- optional -->
## Context and Problem Statement
Currently one can't get any information about parent node.
This is due to ownership restriction of rust.
We can't pass a reference to the parent to a visitor method.
Let's say we have a `CallExpr`, and we are now going to call `visit_mut_callee` from `visit_mut_call_expr`.
We want `&mut callee`, because it's the signature of `visit_mut_callee`.
So we **borrow it from CallExpr**.
As we mutabily borrowed something from `CallExpr`, we cannot pass `&CallExpr` to `visit_mut_callee`.
We can workaround this by
- taking `CallExpr.callee`
- call `visit_mut_callee(&mut self, callee: &mut Callee, parent: &CallExpr)`, with dummy callee in `parent.callee`.
- restore the original callee from `visit_mut_call`.
But doing this by hand is error-prone and doing this automatically by codegen is costly.
This is explicit `memmove`, and `memmove` is quite costly.
SWC moved from `Fold` to `VisitMut` because of `mmemove`.
## Decision Drivers
- Help plugin authors writing plugins.
## Considered Options
- [option 1] Stay with as-is.
- [option 2] Provide full information using `unsafe`.
- **[option 3] Provide small amount of information .**
We will expose the spans and kinds of the parent ast nodes for `VisitMut` and `Fold`, while passing an enum with parent data for `Visit`.
This difference is related to the restriction above.
This is the exact problem rust is trying to solve, and we don't want to violate the rules of rust.
## Decision Outcome
Chosen option: **[option 3] Provide small amount of information .**
This decision is taken because
- It's too hard to **port** plugins, because a plugin author has to recreate logic instead of porting, if the original babel plugin uses parent node information.
- Using `unsafe` in public API requires more discussion.
- We don't have good debugging api for plugins at the moment, so using `unsafe` in plugins is strongly discourages.