about summary refs log tree commit diff
diff options
context:
space:
mode:
authorElly Jones <elly@leptoquark.net>2011-12-20 16:52:04 -0500
committerElly Jones <elly@leptoquark.net>2011-12-20 16:52:04 -0500
commitfb0896fe7bc0a8a0a37a1bc71ed1befb1905acd7 (patch)
tree9197948d1737c4967f179e37391f9997b49be7af
parent3bc4da96f16298c0575ae82904a2552f7ee1547c (diff)
downloadrust-fb0896fe7bc0a8a0a37a1bc71ed1befb1905acd7.tar.gz
rust-fb0896fe7bc0a8a0a37a1bc71ed1befb1905acd7.zip
rustdoc: Add.
Parses #[doc] attributes on top-level module items and generates Markdown.

Signed-off-by: Elly Jones <elly@leptoquark.net>
-rwxr-xr-xsrc/rustdoc/rustdoc.rs205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/rustdoc/rustdoc.rs b/src/rustdoc/rustdoc.rs
new file mode 100755
index 00000000000..9d119d208f4
--- /dev/null
+++ b/src/rustdoc/rustdoc.rs
@@ -0,0 +1,205 @@
+/* rustdoc - rust->markdown translator
+ *
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std;
+use rustc;
+
+import option;
+import option::{some, none};
+import rustc::syntax::ast;
+import rustc::syntax::codemap;
+import rustc::syntax::parse::parser;
+import rustc::syntax::print::pprust;
+import rustc::syntax::visit;
+import std::io;
+import std::map;
+
+type rustdoc = {
+    ps: pprust::ps,
+    w: io::writer
+};
+
+type fndoc = {
+    brief: str,
+    desc: option::t<str>,
+    return: option::t<str>,
+    args: map::hashmap<str, str>
+};
+
+#[doc(
+  brief = "Documents a single function.",
+  args(rd = "Rustdoc context",
+       ident = "Identifier for this function",
+       doc = "Function docs extracted from attributes",
+       _fn = "AST object representing this function")
+)]
+fn doc_fn(rd: rustdoc, ident: str, doc: fndoc, _fn: ast::_fn) {
+    rd.w.write_line("## Function `" + ident + "`");
+    rd.w.write_line(doc.brief);
+    alt doc.desc {
+        some(_d) {
+            rd.w.write_line("");
+            rd.w.write_line(_d);
+            rd.w.write_line("");
+        }
+        none. { }
+    }
+    for arg: ast::arg in _fn.decl.inputs {
+        rd.w.write_str("### Argument `" + arg.ident + "`: ");
+        rd.w.write_line("`" + pprust::ty_to_str(arg.ty) + "`");
+        alt doc.args.find(arg.ident) {
+            some(_d) {
+                rd.w.write_line(_d);
+            }
+            none. { }
+        };
+    }
+    rd.w.write_line("### Returns `" + pprust::ty_to_str(_fn.decl.output) + "`");
+    alt doc.return {
+        some(_r) { rd.w.write_line(_r); }
+        none. { }
+    }
+}
+
+#[doc(
+  brief = "Parses function docs from a complex #[doc] attribute.",
+  desc = "Supported attributes:
+
+* `brief`: Brief description
+* `desc`: Long description
+* `return`: Description of return value
+* `args`: List of argname = argdesc pairs
+",
+  args(items = "Doc attribute contents"),
+  return = "Parsed function docs."
+)]
+fn parse_compound_fndoc(items: [@ast::meta_item]) -> fndoc {
+    let brief = none;
+    let desc = none;
+    let return = none;
+    let argdocs = map::new_str_hash::<str>();
+    let argdocsfound = none;
+    for item: @ast::meta_item in items {
+        alt item.node {
+            ast::meta_name_value("brief", {node: ast::lit_str(value),
+                                           span: _}) {
+                brief = some(value);
+            }
+            ast::meta_name_value("desc", {node: ast::lit_str(value),
+                                              span: _}) {
+                desc = some(value);
+            }
+            ast::meta_name_value("return", {node: ast::lit_str(value),
+                                            span: _}) {
+                return = some(value);
+            }
+            ast::meta_list("args", args) {
+                argdocsfound = some(args);
+            }
+            _ { }
+        }
+    }
+
+    alt argdocsfound {
+        none. { }
+        some(ds) {
+            for d: @ast::meta_item in ds {
+                alt d.node {
+                    ast::meta_name_value(key, {node: ast::lit_str(value),
+                                               span: _}) {
+                        argdocs.insert(key, value);
+                    }
+                }
+            }
+        }
+    }
+
+    let _brief = alt brief {
+        some(_b) { _b }
+        none. { "_undocumented_" }
+    };
+
+    { brief: _brief, desc: desc, return: return, args: argdocs }
+}
+
+#[doc(
+  brief = "Documents a single crate item.",
+  args(rd = "Rustdoc context",
+       item = "AST item to document")
+)]
+fn doc_item(rd: rustdoc, item: @ast::item) {
+    let _fndoc = none;
+    let noargdocs = map::new_str_hash::<str>();
+    for attr: ast::attribute in item.attrs {
+        alt attr.node.value.node {
+            ast::meta_name_value("doc", {node: ast::lit_str(value), span: _}) {
+                _fndoc = some({ brief: value,
+                                desc: none,
+                                return: none,
+                                args: noargdocs });
+            }
+            ast::meta_list("doc", docs) {
+                _fndoc = some(parse_compound_fndoc(docs));
+            }
+        }
+    }
+
+    let _fndoc0 = alt _fndoc {
+        some(_d) { _d }
+        none. { { brief: "_undocumented_", desc: none, return: none, args: noargdocs } }
+    };
+
+    alt item.node {
+        ast::item_const(ty, expr) { }
+        ast::item_fn(_fn, _) {
+            doc_fn(rd, item.ident, _fndoc0, _fn);
+        }
+        ast::item_mod(_mod) { }
+        ast::item_ty(ty, typarams) { }
+        ast::item_tag(variant, typarams) { }
+        ast::item_obj(_obj, typarams, node_id) { }
+        ast::item_res(dtor, dtorid, typarams, ctorid) { }
+    };
+}
+
+#[doc(
+  brief = "Generate a crate document header.",
+  args(rd = "Rustdoc context",
+       name = "Crate name")
+)]
+fn doc_header(rd: rustdoc, name: str) {
+    rd.w.write_line("# Crate " + name);
+}
+
+#[doc(
+  brief = "Main function.",
+  desc = "Command-line arguments:
+
+*  argv[1]: crate file name",
+  args(argv = "Command-line arguments.")
+)]
+fn main(argv: [str]) {
+    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
+    let w = io::stdout();
+    let rd = { ps: pprust::rust_printer(w), w: w };
+    doc_header(rd, argv[1]);
+    let p = parser::parse_crate_from_source_file(argv[1], [], sess);
+    let v = visit::mk_simple_visitor(@{
+        visit_item: bind doc_item(rd, _)
+        with *visit::default_simple_visitor()});
+    visit::visit_crate(*p, (), v);
+}