c2rust_ast_printer/
pprust.rs

1#[cfg(test)]
2mod tests;
3
4#[derive(PartialEq, Eq, Debug, PartialOrd, Ord, Copy, Clone)]
5pub struct BytePos(pub u32);
6
7pub mod comments {
8    #[derive(Clone)]
9    pub struct Comment {
10        pub lines: Vec<String>,
11        pub pos: super::BytePos,
12    }
13}
14
15pub enum MacHeader<'a> {
16    Path(&'a syn::Path),
17    Keyword(&'static str),
18}
19
20pub struct Comments {
21    //cm: &'a SourceMap,
22    comments: Vec<comments::Comment>,
23    current: usize,
24}
25
26impl Comments {
27    pub fn new(
28        //cm: &'a SourceMap,
29        comments: Vec<comments::Comment>,
30    ) -> Comments {
31        Comments {
32            //cm,
33            comments,
34            current: 0,
35        }
36    }
37
38    // pub fn parse(
39    //     cm: &'a SourceMap,
40    //     sess: &ParseSess,
41    //     filename: FileName,
42    //     input: String,
43    // ) -> Comments<'a> {
44    //     let comments = comments::gather_comments(sess, filename, input);
45    //     Comments {
46    //         cm,
47    //         comments,
48    //         current: 0,
49    //     }
50    // }
51
52    pub fn next(&self) -> Option<comments::Comment> {
53        self.comments.get(self.current).cloned()
54    }
55
56    pub fn trailing_comment(
57        &mut self,
58        _span: proc_macro2::Span,
59        _next_pos: Option<usize>,
60    ) -> Option<String> {
61        /*if let Some(cmnt) = self.next() {
62            if cmnt.style != comments::Trailing { return None; }
63            let span_line = self.cm.lookup_char_pos(span.hi());
64            let comment_line = self.cm.lookup_char_pos(cmnt.pos);
65            let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
66            if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
67                return Some(cmnt);
68            }
69        }*/
70
71        None
72    }
73}
74
75impl Extend<comments::Comment> for Comments {
76    fn extend<I>(&mut self, iter: I)
77    where
78        I: IntoIterator<Item = comments::Comment>,
79    {
80        self.comments.extend(iter);
81    }
82}
83
84fn strip_main_fn(s: &str) -> &str {
85    s.trim_start()
86        .trim_start_matches("fn main()")
87        .trim_start()
88        .trim_start_matches('{')
89        .trim_start()
90        .trim_end()
91        .trim_end_matches('}')
92        .trim_end()
93}
94
95fn minimal_file(stmt: syn::Stmt) -> syn::File {
96    let item = syn::Item::Fn(main_fn(stmt));
97    syn::File {
98        shebang: None,
99        attrs: vec![],
100        items: vec![item],
101    }
102}
103
104fn main_fn(stmt: syn::Stmt) -> syn::ItemFn {
105    let generics = syn::Generics {
106        lt_token: None,
107        params: Default::default(),
108        gt_token: None,
109        where_clause: None,
110    };
111    let ident = syn::Ident::new("main", proc_macro2::Span::call_site());
112    let sig = syn::Signature {
113        constness: None,
114        asyncness: None,
115        unsafety: None,
116        abi: None,
117        fn_token: Default::default(),
118        ident,
119        generics,
120        paren_token: Default::default(),
121        inputs: Default::default(),
122        variadic: None,
123        output: syn::ReturnType::Default,
124    };
125    let block = Box::new(syn::Block {
126        brace_token: Default::default(),
127        stmts: vec![stmt],
128    });
129    syn::ItemFn {
130        attrs: vec![],
131        vis: syn::Visibility::Inherited,
132        sig,
133        block,
134    }
135}
136
137fn ret_expr() -> syn::Expr {
138    syn::Expr::Return(syn::ExprReturn {
139        attrs: vec![],
140        return_token: Default::default(),
141        expr: None,
142    })
143}
144
145pub fn expr_to_string(e: &syn::Expr) -> String {
146    let s = to_string(move || minimal_file(syn::Stmt::Expr(e.clone(), None)));
147    strip_main_fn(&s).trim_end_matches(';').to_owned()
148}
149
150pub fn path_to_string(p: &syn::Path) -> String {
151    let e = syn::Expr::Path(syn::ExprPath {
152        attrs: vec![],
153        qself: None,
154        path: p.clone(),
155    });
156    expr_to_string(&e)
157}
158
159pub fn pat_to_string(p: &syn::Pat) -> String {
160    let ret_expr = Box::new(ret_expr());
161    let e = syn::Expr::Let(syn::ExprLet {
162        attrs: vec![],
163        let_token: Default::default(),
164        pat: Box::new(p.clone()),
165        eq_token: Default::default(),
166        expr: ret_expr,
167    });
168    let expr_str = expr_to_string(&e);
169    expr_str
170        .trim_start_matches("(let")
171        .trim_start()
172        .trim_end()
173        .trim_end_matches(';')
174        .trim_end_matches("return)")
175        .trim_end()
176        .trim_end_matches('=')
177        .trim_end()
178        .to_owned()
179}
180
181pub fn stmt_to_string(s: &syn::Stmt) -> String {
182    let s = to_string(move || minimal_file(s.clone()));
183    strip_main_fn(&s).to_owned()
184}
185
186pub fn to_string<F>(f: F) -> String
187where
188    F: FnOnce() -> syn::File,
189{
190    prettyplease::unparse(&f())
191}