Skip to content

Commit fb0896f

Browse files
author
Elly Jones
committed
rustdoc: Add.
Parses #[doc] attributes on top-level module items and generates Markdown. Signed-off-by: Elly Jones <elly@leptoquark.net>
1 parent 3bc4da9 commit fb0896f

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

src/rustdoc/rustdoc.rs

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/* rustdoc - rust->markdown translator
2+
*
3+
* Copyright 2011 Google Inc. All Rights Reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
use std;
19+
use rustc;
20+
21+
import option;
22+
import option::{some, none};
23+
import rustc::syntax::ast;
24+
import rustc::syntax::codemap;
25+
import rustc::syntax::parse::parser;
26+
import rustc::syntax::print::pprust;
27+
import rustc::syntax::visit;
28+
import std::io;
29+
import std::map;
30+
31+
type rustdoc = {
32+
ps: pprust::ps,
33+
w: io::writer
34+
};
35+
36+
type fndoc = {
37+
brief: str,
38+
desc: option::t<str>,
39+
return: option::t<str>,
40+
args: map::hashmap<str, str>
41+
};
42+
43+
#[doc(
44+
brief = "Documents a single function.",
45+
args(rd = "Rustdoc context",
46+
ident = "Identifier for this function",
47+
doc = "Function docs extracted from attributes",
48+
_fn = "AST object representing this function")
49+
)]
50+
fn doc_fn(rd: rustdoc, ident: str, doc: fndoc, _fn: ast::_fn) {
51+
rd.w.write_line("## Function `" + ident + "`");
52+
rd.w.write_line(doc.brief);
53+
alt doc.desc {
54+
some(_d) {
55+
rd.w.write_line("");
56+
rd.w.write_line(_d);
57+
rd.w.write_line("");
58+
}
59+
none. { }
60+
}
61+
for arg: ast::arg in _fn.decl.inputs {
62+
rd.w.write_str("### Argument `" + arg.ident + "`: ");
63+
rd.w.write_line("`" + pprust::ty_to_str(arg.ty) + "`");
64+
alt doc.args.find(arg.ident) {
65+
some(_d) {
66+
rd.w.write_line(_d);
67+
}
68+
none. { }
69+
};
70+
}
71+
rd.w.write_line("### Returns `" + pprust::ty_to_str(_fn.decl.output) + "`");
72+
alt doc.return {
73+
some(_r) { rd.w.write_line(_r); }
74+
none. { }
75+
}
76+
}
77+
78+
#[doc(
79+
brief = "Parses function docs from a complex #[doc] attribute.",
80+
desc = "Supported attributes:
81+
82+
* `brief`: Brief description
83+
* `desc`: Long description
84+
* `return`: Description of return value
85+
* `args`: List of argname = argdesc pairs
86+
",
87+
args(items = "Doc attribute contents"),
88+
return = "Parsed function docs."
89+
)]
90+
fn parse_compound_fndoc(items: [@ast::meta_item]) -> fndoc {
91+
let brief = none;
92+
let desc = none;
93+
let return = none;
94+
let argdocs = map::new_str_hash::<str>();
95+
let argdocsfound = none;
96+
for item: @ast::meta_item in items {
97+
alt item.node {
98+
ast::meta_name_value("brief", {node: ast::lit_str(value),
99+
span: _}) {
100+
brief = some(value);
101+
}
102+
ast::meta_name_value("desc", {node: ast::lit_str(value),
103+
span: _}) {
104+
desc = some(value);
105+
}
106+
ast::meta_name_value("return", {node: ast::lit_str(value),
107+
span: _}) {
108+
return = some(value);
109+
}
110+
ast::meta_list("args", args) {
111+
argdocsfound = some(args);
112+
}
113+
_ { }
114+
}
115+
}
116+
117+
alt argdocsfound {
118+
none. { }
119+
some(ds) {
120+
for d: @ast::meta_item in ds {
121+
alt d.node {
122+
ast::meta_name_value(key, {node: ast::lit_str(value),
123+
span: _}) {
124+
argdocs.insert(key, value);
125+
}
126+
}
127+
}
128+
}
129+
}
130+
131+
let _brief = alt brief {
132+
some(_b) { _b }
133+
none. { "_undocumented_" }
134+
};
135+
136+
{ brief: _brief, desc: desc, return: return, args: argdocs }
137+
}
138+
139+
#[doc(
140+
brief = "Documents a single crate item.",
141+
args(rd = "Rustdoc context",
142+
item = "AST item to document")
143+
)]
144+
fn doc_item(rd: rustdoc, item: @ast::item) {
145+
let _fndoc = none;
146+
let noargdocs = map::new_str_hash::<str>();
147+
for attr: ast::attribute in item.attrs {
148+
alt attr.node.value.node {
149+
ast::meta_name_value("doc", {node: ast::lit_str(value), span: _}) {
150+
_fndoc = some({ brief: value,
151+
desc: none,
152+
return: none,
153+
args: noargdocs });
154+
}
155+
ast::meta_list("doc", docs) {
156+
_fndoc = some(parse_compound_fndoc(docs));
157+
}
158+
}
159+
}
160+
161+
let _fndoc0 = alt _fndoc {
162+
some(_d) { _d }
163+
none. { { brief: "_undocumented_", desc: none, return: none, args: noargdocs } }
164+
};
165+
166+
alt item.node {
167+
ast::item_const(ty, expr) { }
168+
ast::item_fn(_fn, _) {
169+
doc_fn(rd, item.ident, _fndoc0, _fn);
170+
}
171+
ast::item_mod(_mod) { }
172+
ast::item_ty(ty, typarams) { }
173+
ast::item_tag(variant, typarams) { }
174+
ast::item_obj(_obj, typarams, node_id) { }
175+
ast::item_res(dtor, dtorid, typarams, ctorid) { }
176+
};
177+
}
178+
179+
#[doc(
180+
brief = "Generate a crate document header.",
181+
args(rd = "Rustdoc context",
182+
name = "Crate name")
183+
)]
184+
fn doc_header(rd: rustdoc, name: str) {
185+
rd.w.write_line("# Crate " + name);
186+
}
187+
188+
#[doc(
189+
brief = "Main function.",
190+
desc = "Command-line arguments:
191+
192+
* argv[1]: crate file name",
193+
args(argv = "Command-line arguments.")
194+
)]
195+
fn main(argv: [str]) {
196+
let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
197+
let w = io::stdout();
198+
let rd = { ps: pprust::rust_printer(w), w: w };
199+
doc_header(rd, argv[1]);
200+
let p = parser::parse_crate_from_source_file(argv[1], [], sess);
201+
let v = visit::mk_simple_visitor(@{
202+
visit_item: bind doc_item(rd, _)
203+
with *visit::default_simple_visitor()});
204+
visit::visit_crate(*p, (), v);
205+
}

0 commit comments

Comments
 (0)