1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Have docs for items exist in separate files and inserted at compile time for
//! rustdoc

#![feature(plugin_registrar, rustc_private, type_ascription)]
extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::registry::Registry;

use syntax::ast::Name;
use syntax::ext::base::{ AttrProcMacro, ExtCtxt, SyntaxExtension };
use syntax::codemap::Span;
use syntax::tokenstream::TokenStream;
use syntax::tokenstream::TokenTree;
use syntax::parse::token::{ Lit, Token };

use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(  Name::intern("rdoc"),
                                    SyntaxExtension::AttrProcMacro(
                                        Box::new(Expansion)
                                    )
                                 );
}

struct Expansion;

impl AttrProcMacro for Expansion {
    fn expand<'cx>(&self,
                   _: &'cx mut ExtCtxt,
                   _: Span,
                   annotation: TokenStream,
                   annotated: TokenStream) -> TokenStream

    {
        if !annotation.is_empty() {
            let mut trees = annotation.into_trees();
            if let Some(TokenTree::Token(_, val)) = trees.next() {
                if val == Token::Eq {
                    if let Some(TokenTree::Token(_, val)) = trees.next() {
                        if let Token::Literal(Lit::Str_(path) ,_) = val {
                            let out = TokenStream::concat(
                                vec![
                                      TokenStream::from(
                                        Token::DocComment(
                                            Name::intern(
                                                &docs_gen(&path.as_str())
                                            )
                                        )
                                      )
                                    , annotated
                                    ]
                                );
                            out
                        } else {
                            annotated
                        }
                    } else {
                        annotated
                    }
                } else {
                    annotated
                }

            } else {
                annotated
            }
        } else {
            annotated
        }
    }
}

fn docs_gen(path: &str) -> String {
    let mut buf_reader = BufReader::new( File::open(path)
                                              .expect(
                                                  &format!("Failed to open {} \
                                                           while expanding out \
                                                           documentation", path)
                                              )
                                       );
    let mut comments = String::new() + "///";
    let _ = buf_reader.read_to_string(&mut comments);
    comments
}