feat(ast_codegen): introduce the #[span] hint. (#4012)

closes #3904
This commit is contained in:
rzvxa 2024-07-02 10:18:58 +00:00
parent 71e9286fa6
commit 1854a52bd7
4 changed files with 18 additions and 31 deletions

View file

@ -1344,6 +1344,7 @@ pub struct BindingPattern<'a> {
feature = "serialize",
tsify(type = "(BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern)")
)]
#[span]
pub kind: BindingPatternKind<'a>,
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
pub optional: bool,

View file

@ -925,6 +925,13 @@ impl GetSpan for DebuggerStatement {
}
}
impl<'a> GetSpan for BindingPattern<'a> {
#[inline]
fn span(&self) -> Span {
self.kind.span()
}
}
impl<'a> GetSpan for BindingPatternKind<'a> {
fn span(&self) -> Span {
match self {
@ -2185,9 +2192,3 @@ impl<'a> GetSpan for JSXText<'a> {
self.span
}
}
impl<'a> GetSpan for BindingPattern<'a> {
fn span(&self) -> Span {
self.kind.span()
}
}

View file

@ -22,7 +22,7 @@ pub fn visited_node(_args: TokenStream, input: TokenStream) -> TokenStream {
/// Dummy derive macro for a non-existent trait `VisitedNode`.
///
/// Does not generate any code, only purpose is to allow using `#[scope]` attr in the type def.
#[proc_macro_derive(VisitedNode, attributes(scope, visit, visit_as, visit_args))]
#[proc_macro_derive(VisitedNode, attributes(span, scope, visit, visit_as, visit_args))]
pub fn visited_node_derive(_item: TokenStream) -> TokenStream {
TokenStream::new()
}

View file

@ -15,23 +15,6 @@ use super::generated_header;
pub struct ImplGetSpanGenerator;
const EDGE_CASES: [&str; 1] = ["BindingPattern"];
fn edge_case(it: &std::cell::Ref<RType>) -> bool {
!it.ident().is_some_and(|it| EDGE_CASES.contains(&it.to_string().as_str()))
}
fn edge_case_impls() -> TokenStream {
quote! {
endl!();
impl<'a> GetSpan for BindingPattern<'a> {
fn span(&self) -> Span {
self.kind.span()
}
}
}
}
impl Generator for ImplGetSpanGenerator {
fn name(&self) -> &'static str {
"ImplGetSpanGenerator"
@ -44,7 +27,6 @@ impl Generator for ImplGetSpanGenerator {
.map(|it| it.borrow())
.filter(|it| it.visitable())
.filter(|it| matches!(&**it, RType::Enum(_) | RType::Struct(_)))
.filter(edge_case)
.map(|kind| match &*kind {
RType::Enum(it) => impl_enum(it),
RType::Struct(it) => impl_struct(it),
@ -52,8 +34,6 @@ impl Generator for ImplGetSpanGenerator {
})
.collect();
let edge_impls = edge_case_impls();
let header = generated_header!();
GeneratorOutput::One(quote! {
@ -65,9 +45,6 @@ impl Generator for ImplGetSpanGenerator {
use oxc_span::{GetSpan, Span};
#(#impls)*
#edge_impls
})
}
}
@ -96,12 +73,20 @@ fn impl_enum(it @ REnum { item, .. }: &REnum) -> TokenStream {
fn impl_struct(it @ RStruct { item, .. }: &RStruct) -> TokenStream {
let typ = it.as_type();
let generics = &item.generics;
let inner_span_hint =
item.fields.iter().find(|it| it.attrs.iter().any(|a| a.path().is_ident("span")));
let span = if let Some(span_field) = inner_span_hint {
let ident = span_field.ident.as_ref().unwrap();
quote!(#ident.span())
} else {
quote!(span)
};
quote! {
endl!();
impl #generics GetSpan for #typ {
#[inline]
fn span(&self) -> Span {
self.span
self.#span
}
}
}