swc_macros_common/
lib.rs

1//! Internal crate for the swc project.
2
3extern crate proc_macro;
4
5use proc_macro2::{Span, TokenStream};
6use quote::ToTokens;
7use syn::{punctuated::Pair, *};
8
9pub mod binder;
10pub mod derive;
11pub mod prelude;
12mod syn_ext;
13
14pub fn call_site() -> Span {
15    Span::call_site()
16}
17
18pub fn def_site() -> Span {
19    call_site()
20}
21
22/// `attr` - tokens inside `#[]`. e.g. `derive(EqIgnoreSpan)`, ast_node
23pub fn print(attr: &'static str, tokens: proc_macro2::TokenStream) -> proc_macro::TokenStream {
24    use std::env;
25
26    match env::var("PRINT_GENERATED") {
27        Ok(ref s) if s == "1" || attr == s => {}
28        _ => return tokens.into(),
29    }
30
31    println!("\n\tOutput of #[{attr}]:\n\t {tokens}");
32    tokens.into()
33}
34
35pub fn is_attr_name(attr: &Attribute, name: &str) -> bool {
36    attr.path().is_ident(name)
37}
38
39/// Returns `None` if `attr` is not a doc attribute.
40pub fn doc_str(attr: &Attribute) -> Option<String> {
41    fn parse_tts(attr: &Attribute) -> String {
42        match &attr.meta {
43            Meta::NameValue(MetaNameValue {
44                value:
45                    Expr::Lit(ExprLit {
46                        lit: Lit::Str(s), ..
47                    }),
48                ..
49            }) => s.value(),
50            _ => panic!("failed to parse {:?}", attr.meta),
51        }
52    }
53
54    if !is_attr_name(attr, "doc") {
55        return None;
56    }
57
58    Some(parse_tts(attr))
59}
60
61/// Creates a doc comment.
62pub fn make_doc_attr(s: &str) -> Attribute {
63    let span = Span::call_site();
64
65    Attribute {
66        style: AttrStyle::Outer,
67        bracket_token: Default::default(),
68        pound_token: Token![#](span),
69        meta: Meta::NameValue(MetaNameValue {
70            path: Path {
71                leading_colon: None,
72                segments: vec![Pair::End(PathSegment {
73                    ident: Ident::new("doc", span),
74                    arguments: Default::default(),
75                })]
76                .into_iter()
77                .collect(),
78            },
79            eq_token: Token![=](span),
80            value: Expr::Lit(ExprLit {
81                attrs: Default::default(),
82                lit: Lit::Str(LitStr::new(s, span)),
83            }),
84        }),
85    }
86}
87
88pub fn access_field(obj: &dyn ToTokens, idx: usize, f: &Field) -> Expr {
89    Expr::Field(ExprField {
90        attrs: Default::default(),
91        base: syn::parse2(obj.to_token_stream())
92            .expect("swc_macros_common::access_field: failed to parse object"),
93        dot_token: Token![.](Span::call_site()),
94        member: match &f.ident {
95            Some(id) => Member::Named(id.clone()),
96            _ => Member::Unnamed(Index {
97                index: idx as _,
98                span: Span::call_site(),
99            }),
100        },
101    })
102}
103
104pub fn join_stmts(stmts: &[Stmt]) -> TokenStream {
105    let mut q = TokenStream::new();
106
107    for s in stmts {
108        s.to_tokens(&mut q);
109    }
110
111    q
112}
113
114/// fail! is a panic! with location reporting.
115#[macro_export]
116macro_rules! fail {
117    ($($args:tt)+) => {{
118        panic!("{}\n --> {}:{}:{}", format_args!($($args)*), file!(), line!(), column!());
119    }};
120}
121
122#[macro_export]
123macro_rules! unimplemented {
124    ($($args:tt)+) => {{
125        fail!("not yet implemented: {}", format_args!($($args)*));
126    }};
127}
128
129#[macro_export]
130macro_rules! unreachable {
131    () => {{
132        fail!("internal error: unreachable");
133    }};
134    ($($args:tt)+) => {{
135        fail!("internal error: unreachable\n{}", format_args!($($args)*));
136    }};
137}