Merge branch 'master' into floop-for-snapshot

This commit is contained in:
Tim Chevalier 2012-03-09 22:16:52 -08:00
commit a0521971b1
21 changed files with 692 additions and 1775 deletions

View File

@ -14,6 +14,7 @@ Brendan Eich <brendan@mozilla.org>
Brian Anderson <banderson@mozilla.com>
Chris Double <chris.double@double.co.nz>
Chris Peterson <cpeterson@mozilla.com>
Damien Grassart <damien@grassart.com>
Daniel Brooks <db48x@db48x.net>
Daniel Luz <dev@mernen.com>
Dave Herman <dherman@mozilla.com>

View File

@ -2,7 +2,7 @@ This is preliminary version of the Rust compiler.
Source layout:
comp/ The self-hosted compiler
rustc/ The self-hosted compiler
cargo/ The package manager

View File

@ -163,6 +163,8 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
let mutbl_map =
time(time_passes, "mutability checking",
bind middle::mutbl::check_crate(ty_cx, crate));
time(time_passes, "region checking",
bind middle::regionck::check_crate(ty_cx, crate));
let (copy_map, ref_map) =
time(time_passes, "alias checking",
bind middle::alias::check_crate(ty_cx, crate));

View File

@ -0,0 +1,71 @@
/*
* The region checking pass. Ensures that region-annotated pointers never
* outlive their referents.
*/
import driver::session::session;
import middle::ty;
import std::map::hashmap;
import syntax::{ast, visit};
type ctxt = {
tcx: ty::ctxt,
enclosing_block: option<ast::node_id>
};
fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
ty::walk_ty(cx.tcx, ty::expr_ty(cx.tcx, expr)) { |t|
alt ty::get(t).struct {
ty::ty_rptr(region, _) {
alt region {
ty::re_named(_) | ty::re_caller(_) { /* ok */ }
ty::re_block(rbi) {
let referent_block_id = rbi;
let enclosing_block_id = alt cx.enclosing_block {
none {
cx.tcx.sess.span_bug(expr.span, "block " +
"region type outside " +
"a block?!");
}
some(eb) { eb }
};
let parent_blocks = cx.tcx.region_map.parent_blocks;
while enclosing_block_id != referent_block_id {
if parent_blocks.contains_key(referent_block_id) {
referent_block_id =
parent_blocks.get(referent_block_id);
} else {
// TODO: Enable this.
//cx.tcx.sess.span_err(expr.span,
// "reference escapes " +
// "its block");
break;
}
}
}
}
}
_ { /* no-op */ }
}
}
visit::visit_expr(expr, cx, visitor);
}
fn check_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
let new_cx: ctxt = { enclosing_block: some(blk.node.id) with cx };
visit::visit_block(blk, new_cx, visitor);
}
fn check_crate(ty_cx: ty::ctxt, crate: @ast::crate) {
let cx: ctxt = {tcx: ty_cx, enclosing_block: none};
let visitor = visit::mk_vt(@{
visit_expr: check_expr,
visit_block: check_block
with *visit::default_visitor()
});
visit::visit_crate(*crate, cx, visitor);
}

View File

@ -45,6 +45,7 @@ mod middle {
mod capture;
mod pat_util;
mod region;
mod regionck;
mod tstate {
mod ck;

View File

@ -9,42 +9,14 @@ import rustc::syntax::ast;
import rustc::front::attr;
import core::tuple;
export crate_attrs, basic_attrs, fn_attrs, arg_attrs,
variant_attrs, res_attrs, method_attrs;
export parse_crate, parse_basic, parse_fn,
parse_variant, parse_res, parse_method;
export crate_attrs;
export parse_crate, parse_desc;
export parse_hidden;
type crate_attrs = {
name: option<str>
};
type basic_attrs = {
brief: option<str>,
desc: option<str>
};
type fn_attrs = {
args: [arg_attrs],
return: option<str>,
failure: option<str>
};
type arg_attrs = {
name: str,
desc: str
};
type variant_attrs = {
desc: option<str>
};
type res_attrs = {
args: [arg_attrs]
};
type method_attrs = fn_attrs;
#[cfg(test)]
mod test {
@ -121,259 +93,44 @@ fn should_not_extract_crate_name_if_no_name_value_in_link_attribute() {
assert attrs.name == none;
}
fn parse_basic(
attrs: [ast::attribute]
) -> {
brief: option<str>,
desc: option<str>
} {
parse_short_doc_or(
attrs,
{|desc|
{
brief: none,
desc: desc
}
},
{|_items, brief, desc|
{
brief: brief,
desc: desc
}
}
)
fn parse_desc(attrs: [ast::attribute]) -> option<str> {
alt doc_meta(attrs) {
some(meta) {
attr::get_meta_item_value_str(meta)
}
none { none }
}
}
#[test]
fn parse_basic_should_handle_undocumented_mods() {
fn parse_desc_should_handle_undocumented_mods() {
let source = "";
let attrs = test::parse_attributes(source);
let attrs = parse_basic(attrs);
assert attrs.brief == none;
assert attrs.desc == none;
let attrs = parse_desc(attrs);
assert attrs == none;
}
#[test]
fn parse_basic_should_parse_simple_doc_attributes() {
fn parse_desc_should_parse_simple_doc_attributes() {
let source = "#[doc = \"basic\"]";
let attrs = test::parse_attributes(source);
let attrs = parse_basic(attrs);
assert attrs.desc == some("basic");
}
#[test]
fn parse_basic_should_parse_the_brief_description() {
let source = "#[doc(brief = \"short\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_basic(attrs);
assert attrs.brief == some("short");
}
#[test]
fn parse_basic_should_parse_the_long_description() {
let source = "#[doc(desc = \"description\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_basic(attrs);
assert attrs.desc == some("description");
}
fn parse_short_doc_or<T>(
attrs: [ast::attribute],
handle_short: fn&(
short_desc: option<str>
) -> T,
parse_long: fn&(
doc_items: [@ast::meta_item],
brief: option<str>,
desc: option<str>
) -> T
) -> T {
alt doc_meta(attrs) {
some(meta) {
alt attr::get_meta_item_value_str(meta) {
some(desc) { handle_short(some(desc)) }
none {
alt attr::get_meta_item_list(meta) {
some(list) {
let brief = attr::meta_item_value_from_list(list, "brief");
let desc = attr::meta_item_value_from_list(list, "desc");
parse_long(list, brief, desc)
}
none {
handle_short(none)
}
}
}
}
}
none {
handle_short(none)
}
}
}
fn parse_long_doc<T>(
attrs: [ast::attribute],
parse_long: fn&(doc_items: [@ast::meta_item]) -> T
) -> T {
alt doc_meta(attrs) {
some(meta) {
alt attr::get_meta_item_list(meta) {
some(list) {
parse_long(list)
}
none {
parse_long([])
}
}
}
none { parse_long([]) }
}
}
fn parse_fn(attrs: [ast::attribute]) -> fn_attrs {
parse_long_doc(attrs, parse_fn_long_doc)
}
fn parse_fn_long_doc(items: [@ast::meta_item]) -> fn_attrs {
let return = attr::meta_item_value_from_list(items, "return");
let failure = attr::meta_item_value_from_list(items, "failure");
let args = parse_args(items);
{
args: args,
return: return,
failure: failure
}
}
fn parse_args(items: [@ast::meta_item]) -> [arg_attrs] {
alt attr::meta_item_list_from_list(items, "args") {
some(items) {
vec::filter_map(items) {|item|
option::map(attr::name_value_str_pair(item)) { |pair|
{
name: tuple::first(pair),
desc: tuple::second(pair)
}
}
}
}
none { [] }
}
}
#[test]
fn parse_fn_should_handle_undocumented_functions() {
let source = "";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.return == none;
assert vec::len(attrs.args) == 0u;
}
#[test]
fn parse_fn_should_parse_the_return_value_description() {
let source = "#[doc(return = \"return value\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.return == some("return value");
}
#[test]
fn parse_fn_should_parse_the_argument_descriptions() {
let source = "#[doc(args(a = \"arg a\", b = \"arg b\"))]";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.args[0] == {name: "a", desc: "arg a"};
assert attrs.args[1] == {name: "b", desc: "arg b"};
}
#[test]
fn parse_fn_should_parse_failure_conditions() {
let source = "#[doc(failure = \"it's the fail\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.failure == some("it's the fail");
}
fn parse_variant(attrs: [ast::attribute]) -> variant_attrs {
parse_short_doc_or(
attrs,
{|desc|
{
desc: desc
}
},
{|_items, brief, desc|
if option::is_some(brief) && option::is_some(desc) {
// FIXME: Warn about dropping brief description
}
{
// Prefer desc over brief
desc: option::maybe(brief, desc, {|s| some(s) })
}
}
)
}
#[test]
fn should_parse_variant_short_doc() {
let source = "#[doc = \"a\"]";
let attrs = test::parse_attributes(source);
let attrs = parse_variant(attrs);
assert attrs.desc == some("a");
}
#[test]
fn should_parse_variant_brief_doc() {
let source = "#[doc(brief = \"a\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_variant(attrs);
assert attrs.desc == some("a");
}
#[test]
fn should_parse_variant_long_doc() {
let source = "#[doc(desc = \"a\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_variant(attrs);
assert attrs.desc == some("a");
}
fn parse_res(attrs: [ast::attribute]) -> res_attrs {
parse_long_doc(attrs, parse_res_long_doc)
}
fn parse_res_long_doc(items: [@ast::meta_item]) -> res_attrs {
{
args: parse_args(items)
}
}
#[test]
fn shoulde_parse_resource_arg() {
let source = "#[doc(args(a = \"b\"))]";
let attrs = test::parse_attributes(source);
let attrs = parse_res(attrs);
assert attrs.args[0].name == "a";
assert attrs.args[0].desc == "b";
}
fn parse_method(attrs: [ast::attribute]) -> method_attrs {
parse_fn(attrs)
let attrs = parse_desc(attrs);
assert attrs == some("basic");
}
fn parse_hidden(attrs: [ast::attribute]) -> bool {
parse_short_doc_or(
attrs,
{|_desc| false },
{|metas, _brief, _desc|
alt doc_meta(attrs) {
some(meta) {
alt attr::get_meta_item_list(meta) {
some(metas) {
let hiddens = attr::find_meta_items_by_name(metas, "hidden");
vec::is_not_empty(hiddens)
}
none { false }
}
)
}
none { false }
}
}
#[test]

View File

@ -26,9 +26,7 @@ fn run(
let fold = fold::fold({
fold_crate: fold_crate,
fold_item: fold_item,
fold_fn: fold_fn,
fold_enum: fold_enum,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(srv)
@ -74,18 +72,17 @@ fn fold_item(
let srv = fold.ctxt;
let doc = fold::default_seq_fold_item(fold, doc);
let attrs = if doc.id == ast::crate_node_id {
let desc = if doc.id == ast::crate_node_id {
// This is the top-level mod, use the crate attributes
astsrv::exec(srv) {|ctxt|
attr_parser::parse_basic(ctxt.ast.node.attrs)
attr_parser::parse_desc(ctxt.ast.node.attrs)
}
} else {
parse_item_attrs(srv, doc.id, attr_parser::parse_basic)
parse_item_attrs(srv, doc.id, attr_parser::parse_desc)
};
{
brief: attrs.brief,
desc: attrs.desc
desc: desc
with doc
}
}
@ -130,111 +127,12 @@ fn should_extract_native_fn_attributes() {
assert doc.cratemod().nmods()[0].fns[0].desc() == some("test");
}
fn fold_fn(
fold: fold::fold<astsrv::srv>,
doc: doc::fndoc
) -> doc::fndoc {
let srv = fold.ctxt;
let doc = fold::default_seq_fold_fn(fold, doc);
let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_fn);
ret merge_fn_attrs(doc, attrs);
fn merge_fn_attrs(
doc: doc::fndoc,
attrs: attr_parser::fn_attrs
) -> doc::fndoc {
ret {
args: merge_arg_attrs(doc.args, attrs.args),
return: merge_ret_attrs(doc.return, attrs.return),
failure: attrs.failure
with doc
};
}
}
fn merge_arg_attrs(
docs: [doc::argdoc],
attrs: [attr_parser::arg_attrs]
) -> [doc::argdoc] {
par::seqmap(docs) {|doc|
alt vec::find(attrs) {|attr|
attr.name == doc.name
} {
some(attr) {
{
desc: some(attr.desc)
with doc
}
}
none { doc }
}
}
// FIXME: Warning when documenting a non-existent arg
}
fn merge_ret_attrs(
doc: doc::retdoc,
attrs: option<str>
) -> doc::retdoc {
{
desc: attrs
with doc
}
}
#[test]
fn should_extract_fn_attributes() {
let doc = test::mk_doc("#[doc = \"test\"] fn a() -> int { }");
assert doc.cratemod().fns()[0].desc() == some("test");
}
#[test]
fn should_extract_fn_arg_attributes() {
let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn c(a: bool) { }");
assert doc.cratemod().fns()[0].args[0].desc == some("b");
}
#[test]
fn should_extract_fn_return_attributes() {
let source = "#[doc(return = \"what\")] fn a() -> int { }";
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = tystr_pass::mk_pass().f(srv, doc);
let fold = fold::default_any_fold(srv);
let doc = fold_fn(fold, doc.cratemod().fns()[0]);
assert doc.return.desc == some("what");
}
}
#[test]
fn should_preserve_fn_sig() {
let source = "fn a() -> int { }";
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = tystr_pass::mk_pass().f(srv, doc);
let fold = fold::default_any_fold(srv);
let doc = fold_fn(fold, doc.cratemod().fns()[0]);
assert doc.sig == some("fn a() -> int");
}
}
#[test]
fn should_extract_fn_failure_conditions() {
let doc = test::mk_doc("#[doc(failure = \"what\")] fn a() { }");
assert doc.cratemod().fns()[0].failure == some("what");
}
#[test]
fn should_extract_const_docs() {
let doc = test::mk_doc("#[doc(brief = \"foo\", desc = \"bar\")]\
const a: bool = true;");
assert doc.cratemod().consts()[0].brief() == some("foo");
assert doc.cratemod().consts()[0].desc() == some("bar");
}
fn fold_enum(
fold: fold::fold<astsrv::srv>,
doc: doc::enumdoc
@ -246,7 +144,7 @@ fn fold_enum(
{
variants: par::anymap(doc.variants) {|variant|
let attrs = astsrv::exec(srv) {|ctxt|
let desc = astsrv::exec(srv) {|ctxt|
alt check ctxt.ast_map.get(doc_id) {
ast_map::node_item(@{
node: ast::item_enum(ast_variants, _), _
@ -256,13 +154,13 @@ fn fold_enum(
v.node.name == variant.name
});
attr_parser::parse_variant(ast_variant.node.attrs)
attr_parser::parse_desc(ast_variant.node.attrs)
}
}
};
{
desc: attrs.desc
desc: desc
with variant
}
}
@ -272,9 +170,8 @@ fn fold_enum(
#[test]
fn should_extract_enum_docs() {
let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
let doc = test::mk_doc("#[doc = \"b\"]\
enum a { v }");
assert doc.cratemod().enums()[0].brief() == some("a");
assert doc.cratemod().enums()[0].desc() == some("b");
}
@ -284,49 +181,6 @@ fn should_extract_variant_docs() {
assert doc.cratemod().enums()[0].variants[0].desc == some("c");
}
fn fold_res(
fold: fold::fold<astsrv::srv>,
doc: doc::resdoc
) -> doc::resdoc {
let srv = fold.ctxt;
let doc = fold::default_seq_fold_res(fold, doc);
let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_res);
{
args: par::seqmap(doc.args) {|doc|
alt vec::find(attrs.args) {|attr|
attr.name == doc.name
} {
some(attr) {
{
desc: some(attr.desc)
with doc
}
}
none { doc }
}
}
with doc
}
}
#[test]
fn should_extract_res_docs() {
let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
resource r(b: bool) { }");
assert doc.cratemod().resources()[0].brief() == some("a");
assert doc.cratemod().resources()[0].desc() == some("b");
}
#[test]
fn should_extract_res_arg_docs() {
let doc = test::mk_doc("#[doc(args(a = \"b\"))]\
resource r(a: bool) { }");
assert doc.cratemod().resources()[0].args[0].name == "a";
assert doc.cratemod().resources()[0].args[0].desc == some("b");
}
fn fold_iface(
fold: fold::fold<astsrv::srv>,
doc: doc::ifacedoc
@ -346,30 +200,21 @@ fn merge_method_attrs(
docs: [doc::methoddoc]
) -> [doc::methoddoc] {
type method_attrs = (attr_parser::basic_attrs,
attr_parser::method_attrs);
// Create an assoc list from method name to attributes
let attrs: [(str, method_attrs)] = astsrv::exec(srv) {|ctxt|
let attrs: [(str, option<str>)] = astsrv::exec(srv) {|ctxt|
alt ctxt.ast_map.get(item_id) {
ast_map::node_item(@{
node: ast::item_iface(_, methods), _
}, _) {
par::seqmap(methods) {|method|
(method.ident,
(attr_parser::parse_basic(method.attrs),
attr_parser::parse_method(method.attrs)
))
(method.ident, attr_parser::parse_desc(method.attrs))
}
}
ast_map::node_item(@{
node: ast::item_impl(_, _, _, methods), _
}, _) {
par::seqmap(methods) {|method|
(method.ident,
(attr_parser::parse_basic(method.attrs),
attr_parser::parse_method(method.attrs)
))
(method.ident, attr_parser::parse_desc(method.attrs))
}
}
_ { fail "unexpected item" }
@ -378,15 +223,10 @@ fn merge_method_attrs(
vec::map2(docs, attrs) {|doc, attrs|
assert doc.name == tuple::first(attrs);
let basic_attrs = tuple::first(tuple::second(attrs));
let method_attrs = tuple::second(tuple::second(attrs));
let desc = tuple::second(attrs);
{
brief: basic_attrs.brief,
desc: basic_attrs.desc,
args: merge_arg_attrs(doc.args, method_attrs.args),
return: merge_ret_attrs(doc.return, method_attrs.return),
failure: method_attrs.failure
desc: desc
with doc
}
}
@ -402,20 +242,10 @@ fn should_extract_iface_docs() {
fn should_extract_iface_method_docs() {
let doc = test::mk_doc(
"iface i {\
#[doc(\
brief = \"brief\",\
desc = \"desc\",\
args(a = \"a\"),\
return = \"return\",\
failure = \"failure\")]\
#[doc = \"desc\"]\
fn f(a: bool) -> bool;\
}");
assert doc.cratemod().ifaces()[0].methods[0].brief == some("brief");
assert doc.cratemod().ifaces()[0].methods[0].desc == some("desc");
assert doc.cratemod().ifaces()[0].methods[0].args[0].desc == some("a");
assert doc.cratemod().ifaces()[0].methods[0].return.desc
== some("return");
assert doc.cratemod().ifaces()[0].methods[0].failure == some("failure");
}
@ -443,28 +273,10 @@ fn should_extract_impl_docs() {
fn should_extract_impl_method_docs() {
let doc = test::mk_doc(
"impl i for int {\
#[doc(\
brief = \"brief\",\
desc = \"desc\",\
args(a = \"a\"),\
return = \"return\",\
failure = \"failure\")]\
#[doc = \"desc\"]\
fn f(a: bool) -> bool { }\
}");
assert doc.cratemod().impls()[0].methods[0].brief == some("brief");
assert doc.cratemod().impls()[0].methods[0].desc == some("desc");
assert doc.cratemod().impls()[0].methods[0].args[0].desc == some("a");
assert doc.cratemod().impls()[0].methods[0].return.desc == some("return");
assert doc.cratemod().impls()[0].methods[0].failure == some("failure");
}
#[test]
fn should_extract_type_docs() {
let doc = test::mk_doc(
"#[doc(brief = \"brief\", desc = \"desc\")]\
type t = int;");
assert doc.cratemod().types()[0].brief() == some("brief");
assert doc.cratemod().types()[0].desc() == some("desc");
}
#[cfg(test)]

View File

@ -33,106 +33,94 @@ fn take_my_order_please(
_order: [omnomnomy]
) -> uint {
#[doc(
desc = "OMG would you take my order already?",
args(_waitress = "The waitress that you want to bother",
_order = "The order vector. It should be filled with food."),
return = "The price of the order, including tax",
failure = "This function is full of fail"
)];
#[doc = "
OMG would you take my order already?
fail;
}
# Arguments
fn take_my_order_now(
_waitress: waitress,
_order: [omnomnomy]
) -> uint {
* _waitress - The waitress that you want to bother
* _order - The order vector. It should be filled with food
#[doc(
desc = "OMG would you take my order already?",
args(_waitress = "The waitress that you want to bother",
_order = "The order vector. It should be filled with food."),
return = "
# Return
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
nec molestie nisl. Duis massa risus, pharetra a scelerisque a,
molestie eu velit. Donec mattis ligula at ante imperdiet ut
dapibus mauris malesuada.
The price of the order, including tax
Sed gravida nisi a metus elementum sit amet hendrerit dolor
bibendum. Aenean sit amet neque massa, sed tempus tortor. Sed
ut lobortis enim. Proin a mauris quis nunc fermentum ultrices
eget a erat. Mauris in lectus vitae metus sodales
auctor. Morbi nunc quam, ultricies at venenatis non,
pellentesque ac dui.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec
molestie nisl. Duis massa risus, pharetra a scelerisque a,
molestie eu velit. Donec mattis ligula at ante imperdiet ut
dapibus mauris malesuada.
",
failure = "This function is full of fail"
)];
Sed gravida nisi a metus elementum sit amet hendrerit dolor
bibendum. Aenean sit amet neque massa, sed tempus tortor. Sed ut
lobortis enim. Proin a mauris quis nunc fermentum ultrices eget a
erat. Mauris in lectus vitae metus sodales auctor. Morbi nunc
quam, ultricies at venenatis non, pellentesque ac dui.
# Failure
This function is full of fail
"];
fail;
}
mod fortress_of_solitude {
#[doc(
brief = "Superman's vacation home",
desc = "
#[doc = "
Superman's vacation home
The fortress of solitude is located in the Arctic and it is
cold. What you may not know about the fortress of solitude
though is that it contains two separate bowling alleys. One of
them features bumper-bowling and is kind of lame.
The fortress of solitude is located in the Arctic and it is
cold. What you may not know about the fortress of solitude
though is that it contains two separate bowling alleys. One of
them features bumper-bowling and is kind of lame.
Really, it's pretty cool.
Really, it's pretty cool.
")];
"];
}
mod blade_runner {
#[doc(
brief = "Blade Runner is probably the best movie ever",
desc = "I like that in the world of Blade Runner it is always
raining, and that it's always night time. And Aliens
was also a really good movie.
#[doc = "
Blade Runner is probably the best movie ever
Alien 3 was crap though."
)];
I like that in the world of Blade Runner it is always
raining, and that it's always night time. And Aliens
was also a really good movie.
Alien 3 was crap though.
"];
}
#[doc(
brief = "Bored",
desc = "
#[doc = "
Bored
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec
molestie nisl. Duis massa risus, pharetra a scelerisque a,
molestie eu velit. Donec mattis ligula at ante imperdiet ut
dapibus mauris malesuada. Sed gravida nisi a metus elementum sit
amet hendrerit dolor bibendum. Aenean sit amet neque massa, sed
tempus tortor. Sed ut lobortis enim. Proin a mauris quis nunc
fermentum ultrices eget a erat. Mauris in lectus vitae metus
sodales auctor. Morbi nunc quam, ultricies at venenatis non,
pellentesque ac dui.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec
molestie nisl. Duis massa risus, pharetra a scelerisque a,
molestie eu velit. Donec mattis ligula at ante imperdiet ut
dapibus mauris malesuada. Sed gravida nisi a metus elementum sit
amet hendrerit dolor bibendum. Aenean sit amet neque massa, sed
tempus tortor. Sed ut lobortis enim. Proin a mauris quis nunc
fermentum ultrices eget a erat. Mauris in lectus vitae metus
sodales auctor. Morbi nunc quam, ultricies at venenatis non,
pellentesque ac dui.
Quisque vitae est id eros placerat laoreet sit amet eu
nisi. Curabitur suscipit neque porttitor est euismod
lacinia. Curabitur non quam vitae ipsum adipiscing
condimentum. Mauris ut ante eget metus sollicitudin
blandit. Aliquam erat volutpat. Morbi sed nisl mauris. Nulla
facilisi. Phasellus at mollis ipsum. Maecenas sed convallis
sapien. Nullam in ligula turpis. Pellentesque a neque augue. Sed
eget ante feugiat tortor congue auctor ac quis ante. Proin
condimentum lacinia tincidunt.
Quisque vitae est id eros placerat laoreet sit amet eu
nisi. Curabitur suscipit neque porttitor est euismod
lacinia. Curabitur non quam vitae ipsum adipiscing
condimentum. Mauris ut ante eget metus sollicitudin
blandit. Aliquam erat volutpat. Morbi sed nisl mauris. Nulla
facilisi. Phasellus at mollis ipsum. Maecenas sed convallis
sapien. Nullam in ligula turpis. Pellentesque a neque augue. Sed
eget ante feugiat tortor congue auctor ac quis ante. Proin
condimentum lacinia tincidunt.
")]
"]
resource bored(bored: bool) {
log(error, bored);
}
#[doc(
brief = "The Shunned House",
desc = "
#[doc = "
The Shunned House
From even the greatest of horrors irony is seldom absent. Sometimes it
enters directly into the composition of the events, while sometimes it
@ -147,11 +135,9 @@ northward along the same street to Mrs. Whitman's home and the
neighboring hillside churchyard of St. John's, whose hidden expanse of
Eighteenth Century gravestones had for him a peculiar fascination.
")]
"]
iface the_shunned_house {
#[doc(
desc = "
#[doc = "
Now the irony is this. In this walk, so many times repeated, the
world's greatest master of the terrible and the bizarre was
obliged to pass a particular house on the eastern side of the
@ -165,17 +151,14 @@ iface the_shunned_house {
unknowingly, and stands starkly leering as a symbol of all that is
unutterably hideous.
",
args(
a =
"A yard dating from a time when the region was partly
open country"
))]
# Arguments
* unkempt_yard - A yard dating from a time when the region was partly
open country
"]
fn dingy_house(unkempt_yard: int);
#[doc(
desc = "
#[doc = "
The house was--and for that matter still is--of a kind to attract
the attention of the curious. Originally a farm or semi-farm
building, it followed the average New England colonial lines of
@ -191,17 +174,12 @@ iface the_shunned_house {
the graveyards of the first settlers, and straightened only when
the removal of the bodies to the North Burial Ground made it
decently possible to cut through the old family plots.
",
return = "A dingy house with an unkempt yard",
failure = "Will fail if bodies are removed from premises"
)]
"]
fn construct() -> bool;
}
#[doc = "Whatever"]
impl of the_shunned_house for omnomnomy {
#[doc(args(_unkempt_yard = "Whatever"))]
fn dingy_house(_unkempt_yard: int) {
}

View File

@ -31,11 +31,9 @@ fn run(
fn fold_item(fold: fold::fold<()>, doc: doc::itemdoc) -> doc::itemdoc {
let doc = fold::default_seq_fold_item(fold, doc);
let (brief, desc) = modify(doc.brief, doc.desc);
{
brief: brief,
desc: desc
brief: extract(doc.desc)
with doc
}
}
@ -45,11 +43,8 @@ fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
{
methods: par::anymap(doc.methods) {|doc|
let (brief, desc) = modify(doc.brief, doc.desc);
{
brief: brief,
desc: desc
brief: extract(doc.desc)
with doc
}
}
@ -62,11 +57,8 @@ fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
{
methods: par::anymap(doc.methods) {|doc|
let (brief, desc) = modify(doc.brief, doc.desc);
{
brief: brief,
desc: desc
brief: extract(doc.desc)
with doc
}
}
@ -75,76 +67,22 @@ fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
}
#[test]
fn should_promote_mod_desc() {
let doc = test::mk_doc("#[doc(desc = \"desc\")] mod m { }");
fn should_promote_desc() {
let doc = test::mk_doc("#[doc = \"desc\"] mod m { }");
assert doc.cratemod().mods()[0].brief() == some("desc");
assert doc.cratemod().mods()[0].desc() == none;
}
#[test]
fn should_promote_const_desc() {
let doc = test::mk_doc("#[doc(desc = \"desc\")] const a: bool = true;");
assert doc.cratemod().consts()[0].brief() == some("desc");
assert doc.cratemod().consts()[0].desc() == none;
}
#[test]
fn should_promote_fn_desc() {
let doc = test::mk_doc("#[doc(desc = \"desc\")] fn a() { }");
assert doc.cratemod().fns()[0].brief() == some("desc");
assert doc.cratemod().fns()[0].desc() == none;
}
#[test]
fn should_promote_enum_desc() {
let doc = test::mk_doc("#[doc(desc = \"desc\")] enum a { b }");
assert doc.cratemod().enums()[0].brief() == some("desc");
assert doc.cratemod().enums()[0].desc() == none;
}
#[test]
fn should_promote_resource_desc() {
let doc = test::mk_doc(
"#[doc(desc = \"desc\")] resource r(a: bool) { }");
assert doc.cratemod().resources()[0].brief() == some("desc");
assert doc.cratemod().resources()[0].desc() == none;
}
#[test]
fn should_promote_iface_desc() {
let doc = test::mk_doc("#[doc(desc = \"desc\")] iface i { fn a(); }");
assert doc.cratemod().ifaces()[0].brief() == some("desc");
assert doc.cratemod().ifaces()[0].desc() == none;
}
#[test]
fn should_promote_iface_method_desc() {
let doc = test::mk_doc("iface i { #[doc(desc = \"desc\")] fn a(); }");
let doc = test::mk_doc("iface i { #[doc = \"desc\"] fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].brief == some("desc");
assert doc.cratemod().ifaces()[0].methods[0].desc == none;
}
#[test]
fn should_promote_impl_desc() {
let doc = test::mk_doc(
"#[doc(desc = \"desc\")] impl i for int { fn a() { } }");
assert doc.cratemod().impls()[0].brief() == some("desc");
assert doc.cratemod().impls()[0].desc() == none;
}
#[test]
fn should_promote_impl_method_desc() {
let doc = test::mk_doc(
"impl i for int { #[doc(desc = \"desc\")] fn a() { } }");
"impl i for int { #[doc = \"desc\"] fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].brief == some("desc");
assert doc.cratemod().impls()[0].methods[0].desc == none;
}
#[test]
fn should_promote_type_desc() {
let doc = test::mk_doc("#[doc(desc = \"desc\")] type t = int;");
assert doc.cratemod().types()[0].brief() == some("desc");
assert doc.cratemod().types()[0].desc() == none;
}
#[cfg(test)]
@ -158,42 +96,44 @@ mod test {
}
}
fn modify(
brief: option<str>,
desc: option<str>
) -> (option<str>, option<str>) {
if option::is_some(brief) || option::is_none(desc) {
ret (brief, desc);
fn extract(desc: option<str>) -> option<str> {
if option::is_none(desc) {
ret none
}
parse_desc(option::get(desc))
}
fn parse_desc(desc: str) -> (option<str>, option<str>) {
fn parse_desc(desc: str) -> option<str> {
const max_brief_len: uint = 120u;
let paras = paragraphs(desc);
if check vec::is_not_empty(paras) {
let maybe_brief = vec::head(paras);
if str::len(maybe_brief) <= max_brief_len {
let desc_paras = vec::tail(paras);
let desc = if vec::is_not_empty(desc_paras) {
some(str::connect(desc_paras, "\n\n"))
} else {
none
};
(some(maybe_brief), desc)
alt first_sentence(desc) {
some(first_sentence) {
if str::len(first_sentence) <= max_brief_len {
some(first_sentence)
} else {
(none, some(desc))
none
}
} else {
(none, none)
}
none { none }
}
}
fn first_sentence(s: str) -> option<str> {
let paras = paragraphs(s);
if vec::is_not_empty(paras) {
let first = vec::head(sentences(vec::head(paras)));
some(str::replace(first, "\n", " "))
} else {
none
}
}
fn sentences(s: str) -> [str] {
str::split_char(s, '.')
}
fn paragraphs(s: str) -> [str] {
let lines = str::lines_any(s);
let whitespace_lines = 0;
@ -244,42 +184,36 @@ fn test_paragraphs_2() {
#[test]
fn should_promote_short_descs() {
let brief = none;
let desc = some("desc");
let (newbrief, newdesc) = modify(brief, desc);
assert newbrief == desc;
assert newdesc == none;
let brief = extract(desc);
assert brief == desc;
}
#[test]
fn should_not_promote_long_descs() {
let brief = none;
let desc = some("Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland.
The town and castle occupy a loop of the River Coquet, less than a mile
in the town of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
let (newbrief, _) = modify(brief, desc);
assert newbrief == none;
let brief = extract(desc);
assert brief == none;
}
#[test]
fn should_not_promote_descs_over_brief() {
let brief = some("brief");
let desc = some("desc");
let (newbrief, newdesc) = modify(brief, desc);
assert newbrief == brief;
assert newdesc == desc;
}
#[test]
fn should_extract_brief_from_desc() {
let brief = none;
let desc = some("brief\n\ndesc");
let (newbrief, newdesc) = modify(brief, desc);
assert newbrief == some("brief");
assert newdesc == some("desc");
}
fn should_promote_first_sentence() {
let desc = some("Warkworth Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
let brief = extract(desc);
assert brief == some(
"Warkworth Castle is a ruined medieval building in the town");
}

View File

@ -11,6 +11,15 @@ enum page {
itempage(itemtag)
}
#[doc = "
Most rustdocs can be parsed into 'sections' according to their markdown
headers
"]
type section = {
header: str,
body: str
};
// FIXME: We currently give topmod the name of the crate. There would
// probably be fewer special cases if the crate had its own name and
// topmod's name was the empty string.
@ -36,10 +45,16 @@ type itemdoc = {
path: [str],
brief: option<str>,
desc: option<str>,
sections: [section],
// Indicates that this node is a reexport of a different item
reexport: bool
};
type simpleitemdoc = {
item: itemdoc,
sig: option<str>
};
type moddoc = {
item: itemdoc,
items: [itemtag],
@ -51,27 +66,9 @@ type nmoddoc = {
fns: [fndoc]
};
type constdoc = {
item: itemdoc,
ty: option<str>
};
type constdoc = simpleitemdoc;
type fndoc = {
item: itemdoc,
args: [argdoc],
return: retdoc,
failure: option<str>,
sig: option<str>
};
type argdoc = {
name: str,
desc: option<str>
};
type retdoc = {
desc: option<str>
};
type fndoc = simpleitemdoc;
type enumdoc = {
item: itemdoc,
@ -84,11 +81,7 @@ type variantdoc = {
sig: option<str>
};
type resdoc = {
item: itemdoc,
args: [argdoc],
sig: option<str>
};
type resdoc = simpleitemdoc;
type ifacedoc = {
item: itemdoc,
@ -99,9 +92,7 @@ type methoddoc = {
name: str,
brief: option<str>,
desc: option<str>,
args: [argdoc],
return: retdoc,
failure: option<str>,
sections: [section],
sig: option<str>
};
@ -112,10 +103,7 @@ type impldoc = {
methods: [methoddoc]
};
type tydoc = {
item: itemdoc,
sig: option<str>
};
type tydoc = simpleitemdoc;
type index = {
entries: [index_entry]
@ -344,6 +332,10 @@ impl of item for itemtag {
}
}
impl of item for simpleitemdoc {
fn item() -> itemdoc { self.item }
}
impl of item for moddoc {
fn item() -> itemdoc { self.item }
}
@ -352,22 +344,10 @@ impl of item for nmoddoc {
fn item() -> itemdoc { self.item }
}
impl of item for fndoc {
fn item() -> itemdoc { self.item }
}
impl of item for constdoc {
fn item() -> itemdoc { self.item }
}
impl of item for enumdoc {
fn item() -> itemdoc { self.item }
}
impl of item for resdoc {
fn item() -> itemdoc { self.item }
}
impl of item for ifacedoc {
fn item() -> itemdoc { self.item }
}
@ -376,10 +356,6 @@ impl of item for impldoc {
fn item() -> itemdoc { self.item }
}
impl of item for tydoc {
fn item() -> itemdoc { self.item }
}
impl util<A:item> for A {
fn id() -> ast_id {
self.item().id
@ -400,4 +376,8 @@ impl util<A:item> for A {
fn desc() -> option<str> {
self.item().desc
}
fn sections() -> [section] {
self.item().sections
}
}

View File

@ -44,6 +44,7 @@ fn mk_itemdoc(id: ast::node_id, name: ast::ident) -> doc::itemdoc {
path: [],
brief: none,
desc: none,
sections: [],
reexport: false
}
}
@ -67,9 +68,9 @@ fn moddoc_from_mod(
nmoddoc_from_mod(itemdoc, nm)
))
}
ast::item_fn(decl, _, _) {
ast::item_fn(_, _, _) {
some(doc::fntag(
fndoc_from_fn(itemdoc, decl)
fndoc_from_fn(itemdoc)
))
}
ast::item_const(_, _) {
@ -82,9 +83,9 @@ fn moddoc_from_mod(
enumdoc_from_enum(itemdoc, variants)
))
}
ast::item_res(decl, _, _, _, _) {
ast::item_res(_, _, _, _, _) {
some(doc::restag(
resdoc_from_resource(itemdoc, decl)
resdoc_from_resource(itemdoc)
))
}
ast::item_iface(_, methods) {
@ -120,54 +121,25 @@ fn nmoddoc_from_mod(
fns: par::seqmap(module.items) {|item|
let itemdoc = mk_itemdoc(item.id, item.ident);
alt item.node {
ast::native_item_fn(decl, _) {
fndoc_from_fn(itemdoc, decl)
ast::native_item_fn(_, _) {
fndoc_from_fn(itemdoc)
}
}
}
}
}
fn fndoc_from_fn(
itemdoc: doc::itemdoc,
decl: ast::fn_decl
) -> doc::fndoc {
fn fndoc_from_fn(itemdoc: doc::itemdoc) -> doc::fndoc {
{
item: itemdoc,
args: argdocs_from_args(decl.inputs),
return: {
desc: none
},
failure: none,
sig: none
}
}
#[test]
fn should_extract_fn_args() {
let source = "fn a(b: int, c: int) { }";
let ast = parse::from_str(source);
let doc = extract(ast, "");
let fn_ = doc.cratemod().fns()[0];
assert fn_.args[0].name == "b";
assert fn_.args[1].name == "c";
}
fn argdocs_from_args(args: [ast::arg]) -> [doc::argdoc] {
par::seqmap(args, argdoc_from_arg)
}
fn argdoc_from_arg(arg: ast::arg) -> doc::argdoc {
{
name: arg.ident,
desc: none
}
}
fn constdoc_from_const(itemdoc: doc::itemdoc) -> doc::constdoc {
{
item: itemdoc,
ty: none
sig: none
}
}
@ -215,13 +187,9 @@ fn should_extract_enum_variants() {
assert doc.cratemod().enums()[0].variants[0].name == "v";
}
fn resdoc_from_resource(
itemdoc: doc::itemdoc,
decl: ast::fn_decl
) -> doc::resdoc {
fn resdoc_from_resource(itemdoc: doc::itemdoc) -> doc::resdoc {
{
item: itemdoc,
args: argdocs_from_args(decl.inputs),
sig: none
}
}
@ -233,12 +201,6 @@ fn should_extract_resources() {
assert doc.cratemod().resources()[0].name() == "r";
}
#[test]
fn should_extract_resource_args() {
let doc = test::mk_doc("resource r(b: bool) { }");
assert doc.cratemod().resources()[0].args[0].name == "b";
}
fn ifacedoc_from_iface(
itemdoc: doc::itemdoc,
methods: [ast::ty_method]
@ -250,11 +212,7 @@ fn ifacedoc_from_iface(
name: method.ident,
brief: none,
desc: none,
args: argdocs_from_args(method.decl.inputs),
return: {
desc: none
},
failure: none,
sections: [],
sig: none
}
}
@ -273,12 +231,6 @@ fn should_extract_iface_methods() {
assert doc.cratemod().ifaces()[0].methods[0].name == "f";
}
#[test]
fn should_extract_iface_method_args() {
let doc = test::mk_doc("iface i { fn f(a: bool); }");
assert doc.cratemod().ifaces()[0].methods[0].args[0].name == "a";
}
fn impldoc_from_impl(
itemdoc: doc::itemdoc,
methods: [@ast::method]
@ -292,11 +244,7 @@ fn impldoc_from_impl(
name: method.ident,
brief: none,
desc: none,
args: argdocs_from_args(method.decl.inputs),
return: {
desc: none
},
failure: none,
sections: [],
sig: none
}
}
@ -321,12 +269,6 @@ fn should_extract_impl_methods() {
assert doc.cratemod().impls()[0].methods[0].name == "f";
}
#[test]
fn should_extract_impl_method_args() {
let doc = test::mk_doc("impl i for int { fn f(a: bool) { } }");
assert doc.cratemod().impls()[0].methods[0].args[0].name == "a";
}
fn tydoc_from_ty(
itemdoc: doc::itemdoc
) -> doc::tydoc {

View File

@ -145,7 +145,7 @@ fn should_index_mod_contents_multi_page() {
fn should_add_brief_desc_to_index() {
let doc = test::mk_doc(
config::doc_per_mod,
"#[doc(brief = \"test\")] mod a { }"
"#[doc = \"test\"] mod a { }"
);
assert option::get(doc.cratemod().index).entries[0].brief == some("test");
}
@ -160,6 +160,7 @@ mod test {
};
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
let doc = desc_to_brief_pass::mk_pass().f(srv, doc);
let doc = path_pass::mk_pass().f(srv, doc);
run(srv, doc, config)
}

View File

@ -120,7 +120,8 @@ fn should_request_new_writer_for_each_page() {
enum hlvl {
h1 = 1,
h2 = 2,
h3 = 3
h3 = 3,
h4 = 4
}
fn write_header(ctxt: ctxt, lvl: hlvl, doc: doc::itemtag) {
@ -238,12 +239,55 @@ fn should_write_full_path_to_mod() {
assert str::contains(markdown, "# Module `a::b::c`");
}
fn write_common(
ctxt: ctxt,
desc: option<str>,
sections: [doc::section]
) {
write_desc(ctxt, desc);
write_sections(ctxt, sections);
}
fn write_desc(
ctxt: ctxt,
desc: option<str>
) {
alt desc {
some(desc) {
ctxt.w.write_line(desc);
ctxt.w.write_line("");
}
none { }
}
}
fn write_sections(ctxt: ctxt, sections: [doc::section]) {
vec::iter(sections) {|section|
write_section(ctxt, section);
}
}
fn write_section(ctxt: ctxt, section: doc::section) {
write_header_(ctxt, h4, section.header);
ctxt.w.write_line(section.body);
ctxt.w.write_line("");
}
#[test]
fn should_write_sections() {
let markdown = test::render(
"#[doc = \"\
# Header\n\
Body\"]\
mod a { }");
assert str::contains(markdown, "#### Header\n\nBody\n\n");
}
fn write_mod_contents(
ctxt: ctxt,
doc: doc::moddoc
) {
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_common(ctxt, doc.desc(), doc.sections());
if option::is_some(doc.index) {
write_index(ctxt, option::get(doc.index));
}
@ -267,12 +311,6 @@ fn write_item(ctxt: ctxt, doc: doc::itemtag) {
}
}
#[test]
fn should_write_crate_brief_description() {
let markdown = test::render("#[doc(brief = \"this is the crate\")];");
assert str::contains(markdown, "this is the crate");
}
#[test]
fn should_write_crate_description() {
let markdown = test::render("#[doc = \"this is the crate\"];");
@ -309,7 +347,7 @@ fn should_write_index() {
#[test]
fn should_write_index_brief() {
let markdown = test::render("#[doc(brief = \"test\")] mod a { }");
let markdown = test::render("#[doc = \"test\"] mod a { }");
assert str::contains(markdown, "(#module-a) - test\n");
}
@ -321,9 +359,7 @@ fn should_not_write_index_if_no_entries() {
fn write_nmod(ctxt: ctxt, doc: doc::nmoddoc) {
write_header(ctxt, h1, doc::nmodtag(doc));
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_common(ctxt, doc.desc(), doc.sections());
for fndoc in doc.fns {
write_fn(ctxt, fndoc);
@ -351,29 +387,19 @@ fn write_fn(
write_fnlike(
ctxt,
doc.sig,
doc.brief(),
doc.desc(),
doc.args,
doc.return,
doc.failure
doc.sections()
);
}
fn write_fnlike(
ctxt: ctxt,
sig: option<str>,
brief: option<str>,
desc: option<str>,
args: [doc::argdoc],
return: doc::retdoc,
failure: option<str>
sections: [doc::section]
) {
write_sig(ctxt, sig);
write_brief(ctxt, brief);
write_desc(ctxt, desc);
write_args(ctxt, args);
write_return(ctxt, return);
write_failure(ctxt, failure);
write_common(ctxt, desc, sections);
}
fn write_sig(ctxt: ctxt, sig: option<str>) {
@ -433,167 +459,8 @@ fn should_correctly_indent_fn_signature() {
#[test]
fn should_leave_blank_line_between_fn_header_and_sig() {
let markdown = test::render("#[doc(brief = \"brief\")] fn a() { }");
assert str::contains(markdown, "Function `a`\n\n fn a()");
}
fn write_brief(
ctxt: ctxt,
brief: option<str>
) {
alt brief {
some(brief) {
ctxt.w.write_line(brief);
ctxt.w.write_line("");
}
none { }
}
}
#[test]
fn should_leave_blank_line_after_brief() {
let markdown = test::render("#[doc(brief = \"brief\")] fn a() { }");
assert str::contains(markdown, "brief\n\n");
}
#[test]
fn should_leave_blank_line_between_brief_and_desc() {
let markdown = test::render(
"#[doc(brief = \"brief\", desc = \"desc\")] fn a() { }"
);
assert str::contains(markdown, "brief\n\ndesc");
}
fn write_desc(
ctxt: ctxt,
desc: option<str>
) {
alt desc {
some(desc) {
ctxt.w.write_line(desc);
ctxt.w.write_line("");
}
none { }
}
}
fn write_args(
ctxt: ctxt,
args: [doc::argdoc]
) {
if vec::is_not_empty(args) {
write_lead(ctxt, "Arguments");
ctxt.w.write_line("");
ctxt.w.write_line("");
vec::iter(args) {|arg| write_arg(ctxt, arg) };
ctxt.w.write_line("");
}
}
fn write_arg(ctxt: ctxt, arg: doc::argdoc) {
ctxt.w.write_str(#fmt(
"* `%s`",
arg.name
));
alt arg.desc {
some(desc) {
ctxt.w.write_str(#fmt(" - %s", desc));
}
none { }
}
ctxt.w.write_line("");
}
#[test]
fn should_write_argument_list() {
let source = "fn a(b: int, c: int) { }";
let markdown = test::render(source);
assert str::contains(
markdown,
"__Arguments__: \n\
\n\
* `b`\n\
* `c`\n\
\n"
);
}
#[test]
fn should_not_write_arguments_if_none() {
let source = "fn a() { } fn b() { }";
let markdown = test::render(source);
assert !str::contains(markdown, "Arguments");
}
#[test]
fn should_write_argument_description() {
let source = "#[doc(args(a = \"milk\"))] fn f(a: bool) { }";
let markdown = test::render(source);
assert str::contains(markdown, "`a` - milk");
}
fn write_return(
ctxt: ctxt,
doc: doc::retdoc
) {
alt doc.desc {
some(d) {
write_lead(ctxt, "Return value");
ctxt.w.write_line(d);
ctxt.w.write_line("");
}
none { }
}
}
#[test]
fn should_write_return_type_on_new_line() {
let markdown = test::render(
"#[doc(return = \"test\")] fn a() -> int { }");
assert str::contains(markdown, "\n__Return value__: test");
}
#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
let markdown = test::render(
"#[doc(return = \"test\")] fn a() -> int { } \
fn b() -> int { }"
);
assert str::contains(markdown, "__Return value__: test\n\n##");
}
#[test]
fn should_not_write_return_type_when_there_is_none() {
let markdown = test::render("fn a() { }");
assert !str::contains(markdown, "Return value");
}
#[test]
fn should_write_blank_line_after_return_description() {
let markdown = test::render(
"#[doc(return = \"blorp\")] fn a() -> int { }"
);
assert str::contains(markdown, "blorp\n\n");
}
fn write_failure(ctxt: ctxt, str: option<str>) {
alt str {
some(str) {
write_lead(ctxt, "Failure conditions");
ctxt.w.write_line(str);
ctxt.w.write_line("");
}
none { }
}
}
#[test]
fn should_write_failure_conditions() {
let markdown = test::render(
"#[doc(failure = \"it's the fail\")] fn a () { }");
assert str::contains(
markdown,
"\n\n__Failure conditions__: it's the fail\n\n");
assert str::contains(markdown, "Function `a`\n\n fn a()");
}
fn write_const(
@ -601,9 +468,8 @@ fn write_const(
doc: doc::constdoc
) {
write_header(ctxt, h2, doc::consttag(doc));
write_sig(ctxt, doc.ty);
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_sig(ctxt, doc.sig);
write_common(ctxt, doc.desc(), doc.sections());
}
#[test]
@ -615,9 +481,9 @@ fn should_write_const_header() {
#[test]
fn should_write_const_description() {
let markdown = test::render(
"#[doc(brief = \"a\", desc = \"b\")]\
"#[doc = \"b\"]\
const a: bool = true;");
assert str::contains(markdown, "\n\na\n\nb\n\n");
assert str::contains(markdown, "\n\nb\n\n");
}
fn write_enum(
@ -625,8 +491,7 @@ fn write_enum(
doc: doc::enumdoc
) {
write_header(ctxt, h2, doc::enumtag(doc));
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_common(ctxt, doc.desc(), doc.sections());
write_variants(ctxt, doc.variants);
}
@ -639,8 +504,8 @@ fn should_write_enum_header() {
#[test]
fn should_write_enum_description() {
let markdown = test::render(
"#[doc(brief = \"a\", desc = \"b\")] enum a { b }");
assert str::contains(markdown, "\n\na\n\nb\n\n");
"#[doc = \"b\"] enum a { b }");
assert str::contains(markdown, "\n\nb\n\n");
}
fn write_variants(
@ -651,8 +516,7 @@ fn write_variants(
ret;
}
ctxt.w.write_line("Variants:");
ctxt.w.write_line("");
write_header_(ctxt, h4, "Variants");
vec::iter(docs, {|variant| write_variant(ctxt, variant) });
@ -680,7 +544,7 @@ fn should_write_variant_list() {
#[doc = \"test\"] c }");
assert str::contains(
markdown,
"\n\nVariants:\n\
"\n\n#### Variants\n\
\n* `b` - test\
\n* `c` - test\n\n");
}
@ -690,7 +554,7 @@ fn should_write_variant_list_without_descs() {
let markdown = test::render("enum a { b, c }");
assert str::contains(
markdown,
"\n\nVariants:\n\
"\n\n#### Variants\n\
\n* `b`\
\n* `c`\n\n");
}
@ -700,7 +564,7 @@ fn should_write_variant_list_with_signatures() {
let markdown = test::render("enum a { b(int), #[doc = \"a\"] c(int) }");
assert str::contains(
markdown,
"\n\nVariants:\n\
"\n\n#### Variants\n\
\n* `b(int)`\
\n* `c(int)` - a\n\n");
}
@ -708,9 +572,7 @@ fn should_write_variant_list_with_signatures() {
fn write_res(ctxt: ctxt, doc: doc::resdoc) {
write_header(ctxt, h2, doc::restag(doc));
write_sig(ctxt, doc.sig);
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_args(ctxt, doc.args);
write_common(ctxt, doc.desc(), doc.sections());
}
#[test]
@ -725,17 +587,9 @@ fn should_write_resource_signature() {
assert str::contains(markdown, "\n resource r(a: bool)\n");
}
#[test]
fn should_write_resource_args() {
let markdown = test::render("#[doc(args(a = \"b\"))]\
resource r(a: bool) { }");
assert str::contains(markdown, "__Arguments__: \n\n* `a` - b");
}
fn write_iface(ctxt: ctxt, doc: doc::ifacedoc) {
write_header(ctxt, h2, doc::ifacetag(doc));
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_common(ctxt, doc.desc(), doc.sections());
write_methods(ctxt, doc.methods);
}
@ -748,11 +602,8 @@ fn write_method(ctxt: ctxt, doc: doc::methoddoc) {
write_fnlike(
ctxt,
doc.sig,
doc.brief,
doc.desc,
doc.args,
doc.return,
doc.failure
doc.sections
);
}
@ -762,17 +613,10 @@ fn should_write_iface_header() {
assert str::contains(markdown, "## Interface `i`");
}
#[test]
fn should_write_iface_brief() {
let markdown = test::render(
"#[doc(brief = \"brief\")] iface i { fn a(); }");
assert str::contains(markdown, "brief");
}
#[test]
fn should_write_iface_desc() {
let markdown = test::render(
"#[doc(desc = \"desc\")] iface i { fn a(); }");
"#[doc = \"desc\"] iface i { fn a(); }");
assert str::contains(markdown, "desc");
}
@ -790,45 +634,9 @@ fn should_write_iface_method_signature() {
assert str::contains(markdown, "\n fn a()");
}
#[test]
fn should_write_iface_method_argument_header() {
let markdown = test::render(
"iface a { fn a(b: int); }");
assert str::contains(markdown, "\n\n__Arguments__: \n\n");
}
#[test]
fn should_write_iface_method_arguments() {
let markdown = test::render(
"iface a { fn a(b: int); }");
assert str::contains(markdown, "* `b`\n");
}
#[test]
fn should_not_write_iface_method_arguments_if_none() {
let markdown = test::render(
"iface a { fn a(); }");
assert !str::contains(markdown, "Arguments");
}
#[test]
fn should_write_iface_method_return_info() {
let markdown = test::render(
"iface a { #[doc(return = \"test\")] fn a() -> int; }");
assert str::contains(markdown, "__Return value__: test");
}
#[test]
fn should_write_iface_method_failure_conditions() {
let markdown = test::render(
"iface a { #[doc(failure = \"nuked\")] fn a(); }");
assert str::contains(markdown, "__Failure conditions__: nuked");
}
fn write_impl(ctxt: ctxt, doc: doc::impldoc) {
write_header(ctxt, h2, doc::impltag(doc));
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_common(ctxt, doc.desc(), doc.sections());
write_methods(ctxt, doc.methods);
}
@ -844,17 +652,10 @@ fn should_write_impl_header_with_iface() {
assert str::contains(markdown, "## Implementation `i of j for int`");
}
#[test]
fn should_write_impl_brief() {
let markdown = test::render(
"#[doc(brief = \"brief\")] impl i for int { fn a() { } }");
assert str::contains(markdown, "brief");
}
#[test]
fn should_write_impl_desc() {
let markdown = test::render(
"#[doc(desc = \"desc\")] impl i for int { fn a() { } }");
"#[doc = \"desc\"] impl i for int { fn a() { } }");
assert str::contains(markdown, "desc");
}
@ -872,49 +673,13 @@ fn should_write_impl_method_signature() {
assert str::contains(markdown, "\n fn a()");
}
#[test]
fn should_write_impl_method_argument_header() {
let markdown = test::render(
"impl a for int { fn a(b: int) { } }");
assert str::contains(markdown, "\n\n__Arguments__: \n\n");
}
#[test]
fn should_write_impl_method_arguments() {
let markdown = test::render(
"impl a for int { fn a(b: int) { } }");
assert str::contains(markdown, "* `b`\n");
}
#[test]
fn should_not_write_impl_method_arguments_if_none() {
let markdown = test::render(
"impl a for int { fn a() { } }");
assert !str::contains(markdown, "Arguments");
}
#[test]
fn should_write_impl_method_return_info() {
let markdown = test::render(
"impl a for int { #[doc(return = \"test\")] fn a() -> int { } }");
assert str::contains(markdown, "__Return value__: test");
}
#[test]
fn should_write_impl_method_failure_conditions() {
let markdown = test::render(
"impl a for int { #[doc(failure = \"nuked\")] fn a() { } }");
assert str::contains(markdown, "__Failure conditions__: nuked");
}
fn write_type(
ctxt: ctxt,
doc: doc::tydoc
) {
write_header(ctxt, h2, doc::tytag(doc));
write_sig(ctxt, doc.sig);
write_brief(ctxt, doc.brief());
write_desc(ctxt, doc.desc());
write_common(ctxt, doc.desc(), doc.sections());
}
#[test]
@ -923,17 +688,10 @@ fn should_write_type_header() {
assert str::contains(markdown, "## Type `t`");
}
#[test]
fn should_write_type_brief() {
let markdown = test::render(
"#[doc(brief = \"brief\")] type t = int;");
assert str::contains(markdown, "\n\nbrief\n\n");
}
#[test]
fn should_write_type_desc() {
let markdown = test::render(
"#[doc(desc = \"desc\")] type t = int;");
"#[doc = \"desc\"] type t = int;");
assert str::contains(markdown, "\n\ndesc\n\n");
}
@ -968,6 +726,14 @@ mod test {
#debug("doc (path): %?", doc);
let doc = attr_pass::mk_pass().f(srv, doc);
#debug("doc (attr): %?", doc);
let doc = desc_to_brief_pass::mk_pass().f(srv, doc);
#debug("doc (desc_to_brief): %?", doc);
let doc = unindent_pass::mk_pass().f(srv, doc);
#debug("doc (unindent): %?", doc);
let doc = sectionalize_pass::mk_pass().f(srv, doc);
#debug("doc (trim): %?", doc);
let doc = trim_pass::mk_pass().f(srv, doc);
#debug("doc (sectionalize): %?", doc);
let doc = markdown_index_pass::mk_pass(config).f(srv, doc);
#debug("doc (index): %?", doc);
(srv, doc)

View File

@ -1,129 +0,0 @@
#[doc = "Prunes args, retvals of the document tree that \
contain no documentation"];
export mk_pass;
fn mk_pass() -> pass {
{
name: "prune_undoc_details",
f: run
}
}
fn run(
_srv: astsrv::srv,
doc: doc::doc
) -> doc::doc {
let fold = fold::fold({
fold_fn: fold_fn,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(())
});
fold.fold_doc(fold, doc)
}
fn fold_fn(
fold: fold::fold<()>,
doc: doc::fndoc
) -> doc::fndoc {
let doc = fold::default_seq_fold_fn(fold, doc);
{
args: prune_args(doc.args)
with doc
}
}
fn prune_args(docs: [doc::argdoc]) -> [doc::argdoc] {
vec::filter_map(docs) {|doc|
if option::is_some(doc.desc) {
some(doc)
} else {
none
}
}
}
#[test]
fn should_elide_undocumented_arguments() {
let doc = test::mk_doc("#[doc = \"hey\"] fn a(b: int) { }");
assert vec::is_empty(doc.cratemod().fns()[0].args);
}
fn fold_res(
fold: fold::fold<()>,
doc: doc::resdoc
) -> doc::resdoc {
let doc = fold::default_seq_fold_res(fold, doc);
{
args: prune_args(doc.args)
with doc
}
}
#[test]
fn should_elide_undocumented_resource_args() {
let doc = test::mk_doc("#[doc = \"drunk\"]\
resource r(a: bool) { }");
assert vec::is_empty(doc.cratemod().resources()[0].args);
}
fn fold_iface(
fold: fold::fold<()>,
doc: doc::ifacedoc
) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
{
methods: prune_methods(doc.methods)
with doc
}
}
fn prune_methods(docs: [doc::methoddoc]) -> [doc::methoddoc] {
par::anymap(docs) {|doc|
{
args: prune_args(doc.args)
with doc
}
}
}
#[test]
fn should_elide_undocumented_iface_method_args() {
let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
assert vec::is_empty(doc.cratemod().ifaces()[0].methods[0].args);
}
fn fold_impl(
fold: fold::fold<()>,
doc: doc::impldoc
) -> doc::impldoc {
let doc = fold::default_seq_fold_impl(fold, doc);
{
methods: prune_methods(doc.methods)
with doc
}
}
#[test]
fn should_elide_undocumented_impl_method_args() {
let doc = test::mk_doc(
"#[doc = \"hey\"] impl i for int { fn a(b: bool) { } }");
assert vec::is_empty(doc.cratemod().impls()[0].methods[0].args);
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
run(srv, doc)
}
}
}

View File

@ -1,377 +0,0 @@
#[doc = "Prunes items of the document tree that contain no documentation"];
export mk_pass;
fn mk_pass() -> pass {
{
name: "prune_undoc_items",
f: run
}
}
type ctxt = {
mutable have_docs: bool
};
fn run(
_srv: astsrv::srv,
doc: doc::doc
) -> doc::doc {
let ctxt = {
mutable have_docs: true
};
let fold = fold::fold({
fold_mod: fold_mod,
fold_fn: fold_fn,
fold_const: fold_const,
fold_enum: fold_enum,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl,
fold_type: fold_type
with *fold::default_any_fold(ctxt)
});
fold.fold_doc(fold, doc)
}
fn fold_mod(
fold: fold::fold<ctxt>,
doc: doc::moddoc
) -> doc::moddoc {
let doc = {
items: vec::filter_map(doc.items) {|itemtag|
alt itemtag {
doc::modtag(moddoc) {
let doc = fold.fold_mod(fold, moddoc);
if fold.ctxt.have_docs {
some(doc::modtag(doc))
} else {
none
}
}
doc::fntag(fndoc) {
let doc = fold.fold_fn(fold, fndoc);
if fold.ctxt.have_docs {
some(doc::fntag(doc))
} else {
none
}
}
doc::consttag(constdoc) {
let doc = fold.fold_const(fold, constdoc);
if fold.ctxt.have_docs {
some(doc::consttag(doc))
} else {
none
}
}
doc::enumtag(enumdoc) {
let doc = fold.fold_enum(fold, enumdoc);
if fold.ctxt.have_docs {
some(doc::enumtag(doc))
} else {
none
}
}
doc::restag(resdoc) {
let doc = fold.fold_res(fold, resdoc);
if fold.ctxt.have_docs {
some(doc::restag(doc))
} else {
none
}
}
doc::ifacetag(ifacedoc) {
let doc = fold.fold_iface(fold, ifacedoc);
if fold.ctxt.have_docs {
some(doc::ifacetag(doc))
} else {
none
}
}
doc::impltag(impldoc) {
let doc = fold.fold_impl(fold, impldoc);
if fold.ctxt.have_docs {
some(doc::impltag(doc))
} else {
none
}
}
doc::tytag(tydoc) {
let doc = fold.fold_type(fold, tydoc);
if fold.ctxt.have_docs {
some(doc::tytag(doc))
} else {
none
}
}
_ { some(itemtag) }
}
}
with fold::default_any_fold_mod(fold, doc)
};
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| vec::is_not_empty(doc.items);
ret doc;
}
fn fold_fn(
fold: fold::fold<ctxt>,
doc: doc::fndoc
) -> doc::fndoc {
let doc = fold::default_seq_fold_fn(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| args_have_docs(doc.args)
|| doc.return.desc != none
|| doc.failure != none;
ret doc;
}
fn args_have_docs(docs: [doc::argdoc]) -> bool {
vec::foldl(false, docs) {|accum, doc|
accum || doc.desc != none
}
}
#[test]
fn should_elide_fns_with_undocumented_arguments() {
let doc = test::mk_doc("fn a(a: int) { }");
assert vec::is_empty(doc.cratemod().fns());
}
#[test]
fn should_not_elide_fns_with_documented_arguments() {
let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn a(a: int) { }");
assert vec::is_not_empty(doc.cratemod().fns());
}
#[test]
fn should_not_elide_fns_with_documented_failure_conditions() {
let doc = test::mk_doc("#[doc(failure = \"yup\")] fn a() { }");
assert vec::is_not_empty(doc.cratemod().fns());
}
#[test]
fn should_elide_undocumented_mods() {
let doc = test::mk_doc("mod a { }");
assert vec::is_empty(doc.cratemod().mods());
}
#[test]
fn should_not_elide_undocument_mods_with_documented_mods() {
let doc = test::mk_doc("mod a { #[doc = \"b\"] mod b { } }");
assert vec::is_not_empty(doc.cratemod().mods());
}
#[test]
fn should_not_elide_undocument_mods_with_documented_fns() {
let doc = test::mk_doc("mod a { #[doc = \"b\"] fn b() { } }");
assert vec::is_not_empty(doc.cratemod().mods());
}
#[test]
fn should_elide_undocumented_fns() {
let doc = test::mk_doc("fn a() { }");
assert vec::is_empty(doc.cratemod().fns());
}
fn fold_const(
fold: fold::fold<ctxt>,
doc: doc::constdoc
) -> doc::constdoc {
let doc = fold::default_seq_fold_const(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none;
ret doc;
}
#[test]
fn should_elide_undocumented_consts() {
let doc = test::mk_doc("const a: bool = true;");
assert vec::is_empty(doc.cratemod().consts());
}
fn fold_enum(fold: fold::fold<ctxt>, doc: doc::enumdoc) -> doc::enumdoc {
let doc = {
variants: vec::filter_map(doc.variants) {|variant|
if variant.desc != none {
some(variant)
} else {
none
}
}
with fold::default_seq_fold_enum(fold, doc)
};
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| vec::is_not_empty(doc.variants);
ret doc;
}
#[test]
fn should_elide_undocumented_enums() {
let doc = test::mk_doc("enum a { b }");
assert vec::is_empty(doc.cratemod().enums());
}
#[test]
fn should_elide_undocumented_variants() {
let doc = test::mk_doc("#[doc = \"a\"] enum a { b }");
assert vec::is_empty(doc.cratemod().enums()[0].variants);
}
#[test]
fn should_not_elide_enums_with_documented_variants() {
let doc = test::mk_doc("enum a { #[doc = \"a\"] b }");
assert vec::is_not_empty(doc.cratemod().enums());
}
fn fold_res(fold: fold::fold<ctxt>, doc: doc::resdoc) -> doc::resdoc {
let doc = fold::default_seq_fold_res(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| args_have_docs(doc.args);
ret doc;
}
#[test]
fn should_elide_undocumented_resources() {
let doc = test::mk_doc("resource r(a: bool) { }");
assert vec::is_empty(doc.cratemod().resources());
}
#[test]
fn should_not_elide_resources_with_documented_args() {
let doc = test::mk_doc("#[doc(args(a = \"drunk\"))]\
resource r(a: bool) { }");
assert vec::is_not_empty(doc.cratemod().resources());
}
fn fold_iface(
fold: fold::fold<ctxt>,
doc: doc::ifacedoc
) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| methods_have_docs(doc.methods);
ret doc;
}
fn methods_have_docs(docs: [doc::methoddoc]) -> bool {
vec::foldl(false, docs) {|accum, doc|
accum
|| doc.brief != none
|| doc.desc != none
|| args_have_docs(doc.args)
|| doc.return.desc != none
|| doc.failure != none
}
}
#[test]
fn should_elide_undocumented_ifaces() {
let doc = test::mk_doc("iface i { fn a(); }");
assert vec::is_empty(doc.cratemod().ifaces());
}
#[test]
fn should_not_elide_documented_ifaces() {
let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
assert vec::is_not_empty(doc.cratemod().ifaces());
}
#[test]
fn should_elide_ifaces_with_undocumented_args() {
let doc = test::mk_doc("iface i { fn a(b: bool); }");
assert vec::is_empty(doc.cratemod().ifaces());
}
#[test]
fn should_not_elide_ifaces_with_documented_methods() {
let doc = test::mk_doc("iface i { #[doc = \"hey\"] fn a(); }");
assert vec::is_not_empty(doc.cratemod().ifaces());
}
#[test]
fn should_not_elide_undocumented_iface_methods() {
let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
assert vec::is_not_empty(doc.cratemod().ifaces()[0].methods);
}
fn fold_impl(
fold: fold::fold<ctxt>,
doc: doc::impldoc
) -> doc::impldoc {
let doc = fold::default_seq_fold_impl(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| methods_have_docs(doc.methods);
ret doc;
}
#[test]
fn should_elide_undocumented_impls() {
let doc = test::mk_doc("impl i for int { fn a() { } }");
assert vec::is_empty(doc.cratemod().impls());
}
#[test]
fn should_not_elide_documented_impls() {
let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }");
assert vec::is_not_empty(doc.cratemod().impls());
}
#[test]
fn should_not_elide_impls_with_documented_methods() {
let doc = test::mk_doc("impl i for int { #[doc = \"hey\"] fn a() { } }");
assert vec::is_not_empty(doc.cratemod().impls());
}
#[test]
fn should_not_elide_undocumented_impl_methods() {
let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }");
assert vec::is_not_empty(doc.cratemod().impls()[0].methods);
}
fn fold_type(
fold: fold::fold<ctxt>,
doc: doc::tydoc
) -> doc::tydoc {
let doc = fold::default_seq_fold_type(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none;
ret doc;
}
#[test]
fn should_elide_undocumented_types() {
let doc = test::mk_doc("type t = int;");
assert vec::is_empty(doc.cratemod().types());
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
run(srv, doc)
}
}
}

View File

@ -24,8 +24,6 @@ mod fold;
mod path_pass;
mod attr_pass;
mod tystr_pass;
mod prune_undoc_details_pass;
mod prune_undoc_items_pass;
mod prune_unexported_pass;
mod prune_hidden_pass;
mod desc_to_brief_pass;
@ -40,3 +38,4 @@ mod sort_item_type_pass;
mod reexport_pass;
mod par;
mod page_pass;
mod sectionalize_pass;

View File

@ -143,13 +143,11 @@ fn run(config: config::config) {
tystr_pass::mk_pass(),
path_pass::mk_pass(),
attr_pass::mk_pass(),
prune_undoc_details_pass::mk_pass(),
// FIXME: This pass should be optional
// prune_undoc_items_pass::mk_pass(),
prune_hidden_pass::mk_pass(),
desc_to_brief_pass::mk_pass(),
trim_pass::mk_pass(),
unindent_pass::mk_pass(),
sectionalize_pass::mk_pass(),
trim_pass::mk_pass(),
sort_item_name_pass::mk_pass(),
sort_item_type_pass::mk_pass(),
markdown_index_pass::mk_pass(config),

View File

@ -0,0 +1,237 @@
#[doc = "Breaks rustdocs into sections according to their headers"];
export mk_pass;
fn mk_pass() -> pass {
{
name: "sectionalize",
f: run
}
}
fn run(_srv: astsrv::srv, doc: doc::doc) -> doc::doc {
let fold = fold::fold({
fold_item: fold_item,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(())
});
fold.fold_doc(fold, doc)
}
fn fold_item(fold: fold::fold<()>, doc: doc::itemdoc) -> doc::itemdoc {
let doc = fold::default_seq_fold_item(fold, doc);
let (desc, sections) = sectionalize(doc.desc);
{
desc: desc,
sections: sections
with doc
}
}
fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
{
methods: par::anymap(doc.methods) {|method|
let (desc, sections) = sectionalize(method.desc);
{
desc: desc,
sections: sections
with method
}
}
with doc
}
}
fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
let doc = fold::default_seq_fold_impl(fold, doc);
{
methods: par::anymap(doc.methods) {|method|
let (desc, sections) = sectionalize(method.desc);
{
desc: desc,
sections: sections
with method
}
}
with doc
}
}
fn sectionalize(desc: option<str>) -> (option<str>, [doc::section]) {
#[doc = "
Take a description of the form
General text
# Section header
Section text
# Section header
Section text
and remove each header and accompanying text into section records.
"];
if option::is_none(desc) {
ret (none, []);
}
let lines = str::lines(option::get(desc));
let new_desc = none;
let current_section = none;
let sections = [];
for line in lines {
alt parse_header(line) {
some(header) {
if option::is_some(current_section) {
sections += [option::get(current_section)];
}
current_section = some({
header: header,
body: ""
});
}
none {
alt current_section {
some(section) {
current_section = some({
body: section.body + "\n" + line
with section
});
}
none {
alt new_desc {
some(desc) {
new_desc = some(desc + "\n" + line);
}
none {
new_desc = some(line);
}
}
}
}
}
}
}
if option::is_some(current_section) {
sections += [option::get(current_section)];
}
(new_desc, sections)
}
fn parse_header(line: str) -> option<str> {
if str::starts_with(line, "# ") {
some(str::slice(line, 2u, str::len(line)))
} else {
none
}
}
#[test]
fn should_create_section_headers() {
let doc = test::mk_doc(
"#[doc = \"\
# Header\n\
Body\"]\
mod a { }");
assert str::contains(
doc.cratemod().mods()[0].item.sections[0].header,
"Header");
}
#[test]
fn should_create_section_bodies() {
let doc = test::mk_doc(
"#[doc = \"\
# Header\n\
Body\"]\
mod a { }");
assert str::contains(
doc.cratemod().mods()[0].item.sections[0].body,
"Body");
}
#[test]
fn should_not_create_sections_from_indented_headers() {
let doc = test::mk_doc(
"#[doc = \"\n\
Text\n # Header\n\
Body\"]\
mod a { }");
assert vec::is_empty(doc.cratemod().mods()[0].item.sections);
}
#[test]
fn should_remove_section_text_from_main_desc() {
let doc = test::mk_doc(
"#[doc = \"\
Description\n\n\
# Header\n\
Body\"]\
mod a { }");
assert !str::contains(
option::get(doc.cratemod().mods()[0].desc()),
"Header");
assert !str::contains(
option::get(doc.cratemod().mods()[0].desc()),
"Body");
}
#[test]
fn should_eliminate_desc_if_it_is_just_whitespace() {
let doc = test::mk_doc(
"#[doc = \"\
# Header\n\
Body\"]\
mod a { }");
assert doc.cratemod().mods()[0].desc() == none;
}
#[test]
fn should_sectionalize_iface_methods() {
let doc = test::mk_doc(
"iface i {
#[doc = \"\
# Header\n\
Body\"]\
fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].sections.len() == 1u;
}
#[test]
fn should_sectionalize_impl_methods() {
let doc = test::mk_doc(
"impl i for bool {
#[doc = \"\
# Header\n\
Body\"]\
fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].sections.len() == 1u;
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
run(srv, doc)
}
}
}

View File

@ -20,9 +20,7 @@ fn run(
) -> doc::doc {
let fold = fold::fold({
fold_item: fold_item,
fold_fn: fold_fn,
fold_enum: fold_enum,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(op)
@ -39,28 +37,18 @@ fn fold_item(fold: fold::fold<op>, doc: doc::itemdoc) -> doc::itemdoc {
{
brief: maybe_apply_op(fold.ctxt, doc.brief),
desc: maybe_apply_op(fold.ctxt, doc.desc)
desc: maybe_apply_op(fold.ctxt, doc.desc),
sections: apply_to_sections(fold.ctxt, doc.sections)
with doc
}
}
fn fold_fn(fold: fold::fold<op>, doc: doc::fndoc) -> doc::fndoc {
let fold_ctxt = fold.ctxt;
let doc = fold::default_seq_fold_fn(fold, doc);
{
args: par::anymap(doc.args) {|doc|
{
desc: maybe_apply_op(fold_ctxt, doc.desc)
with doc
}
},
return: {
desc: maybe_apply_op(fold.ctxt, doc.return.desc)
with doc.return
},
failure: maybe_apply_op(fold.ctxt, doc.failure)
with doc
fn apply_to_sections(op: op, sections: [doc::section]) -> [doc::section] {
par::anymap(sections) {|section|
{
header: op(section.header),
body: op(section.body)
}
}
}
@ -79,21 +67,6 @@ fn fold_enum(fold: fold::fold<op>, doc: doc::enumdoc) -> doc::enumdoc {
}
}
fn fold_res(fold: fold::fold<op>, doc: doc::resdoc) -> doc::resdoc {
let fold_ctxt = fold.ctxt;
let doc = fold::default_seq_fold_res(fold, doc);
{
args: par::anymap(doc.args) {|arg|
{
desc: maybe_apply_op(fold_ctxt, arg.desc)
with arg
}
}
with doc
}
}
fn fold_iface(fold: fold::fold<op>, doc: doc::ifacedoc) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
@ -108,17 +81,7 @@ fn apply_to_methods(op: op, docs: [doc::methoddoc]) -> [doc::methoddoc] {
{
brief: maybe_apply_op(op, doc.brief),
desc: maybe_apply_op(op, doc.desc),
args: par::anymap(doc.args) {|doc|
{
desc: maybe_apply_op(op, doc.desc)
with doc
}
},
return: {
desc: maybe_apply_op(op, doc.return.desc)
with doc.return
},
failure: maybe_apply_op(op, doc.failure)
sections: apply_to_sections(op, doc.sections)
with doc
}
}
@ -135,13 +98,13 @@ fn fold_impl(fold: fold::fold<op>, doc: doc::impldoc) -> doc::impldoc {
#[test]
fn should_execute_op_on_enum_brief() {
let doc = test::mk_doc("#[doc(brief = \" a \")] enum a { b }");
let doc = test::mk_doc("#[doc = \" a \"] enum a { b }");
assert doc.cratemod().enums()[0].brief() == some("a");
}
#[test]
fn should_execute_op_on_enum_desc() {
let doc = test::mk_doc("#[doc(desc = \" a \")] enum a { b }");
let doc = test::mk_doc("#[doc = \" a \"] enum a { b }");
assert doc.cratemod().enums()[0].desc() == some("a");
}
@ -153,141 +116,160 @@ fn should_execute_op_on_variant_desc() {
#[test]
fn should_execute_op_on_resource_brief() {
let doc = test::mk_doc("#[doc(brief = \" a \")] resource r(a: bool) { }");
let doc = test::mk_doc("#[doc = \" a \"] resource r(a: bool) { }");
assert doc.cratemod().resources()[0].brief() == some("a");
}
#[test]
fn should_execute_op_on_resource_desc() {
let doc = test::mk_doc("#[doc(desc = \" a \")] resource r(a: bool) { }");
let doc = test::mk_doc("#[doc = \" a \"] resource r(a: bool) { }");
assert doc.cratemod().resources()[0].desc() == some("a");
}
#[test]
fn should_execute_op_on_resource_args() {
let doc = test::mk_doc(
"#[doc(args(a = \" a \"))] resource r(a: bool) { }");
assert doc.cratemod().resources()[0].args[0].desc == some("a");
}
#[test]
fn should_execute_op_on_iface_brief() {
let doc = test::mk_doc(
"#[doc(brief = \" a \")] iface i { fn a(); }");
"#[doc = \" a \"] iface i { fn a(); }");
assert doc.cratemod().ifaces()[0].brief() == some("a");
}
#[test]
fn should_execute_op_on_iface_desc() {
let doc = test::mk_doc(
"#[doc(desc = \" a \")] iface i { fn a(); }");
"#[doc = \" a \"] iface i { fn a(); }");
assert doc.cratemod().ifaces()[0].desc() == some("a");
}
#[test]
fn should_execute_op_on_iface_method_brief() {
let doc = test::mk_doc(
"iface i { #[doc(brief = \" a \")] fn a(); }");
"iface i { #[doc = \" a \"] fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].brief == some("a");
}
#[test]
fn should_execute_op_on_iface_method_desc() {
let doc = test::mk_doc(
"iface i { #[doc(desc = \" a \")] fn a(); }");
"iface i { #[doc = \" a \"] fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].desc == some("a");
}
#[test]
fn should_execute_op_on_iface_method_args() {
let doc = test::mk_doc(
"iface i { #[doc(args(a = \" a \"))] fn a(a: bool); }");
assert doc.cratemod().ifaces()[0].methods[0].args[0].desc == some("a");
}
#[test]
fn should_execute_op_on_iface_method_return() {
let doc = test::mk_doc(
"iface i { #[doc(return = \" a \")] fn a() -> int; }");
assert doc.cratemod().ifaces()[0].methods[0].return.desc == some("a");
}
#[test]
fn should_execute_op_on_iface_method_failure_condition() {
let doc = test::mk_doc("iface i { #[doc(failure = \" a \")] fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].failure == some("a");
}
#[test]
fn should_execute_op_on_impl_brief() {
let doc = test::mk_doc(
"#[doc(brief = \" a \")] impl i for int { fn a() { } }");
"#[doc = \" a \"] impl i for int { fn a() { } }");
assert doc.cratemod().impls()[0].brief() == some("a");
}
#[test]
fn should_execute_op_on_impl_desc() {
let doc = test::mk_doc(
"#[doc(desc = \" a \")] impl i for int { fn a() { } }");
"#[doc = \" a \"] impl i for int { fn a() { } }");
assert doc.cratemod().impls()[0].desc() == some("a");
}
#[test]
fn should_execute_op_on_impl_method_brief() {
let doc = test::mk_doc(
"impl i for int { #[doc(brief = \" a \")] fn a() { } }");
"impl i for int { #[doc = \" a \"] fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].brief == some("a");
}
#[test]
fn should_execute_op_on_impl_method_desc() {
let doc = test::mk_doc(
"impl i for int { #[doc(desc = \" a \")] fn a() { } }");
"impl i for int { #[doc = \" a \"] fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].desc == some("a");
}
#[test]
fn should_execute_op_on_impl_method_args() {
let doc = test::mk_doc(
"impl i for int { #[doc(args(a = \" a \"))] fn a(a: bool) { } }");
assert doc.cratemod().impls()[0].methods[0].args[0].desc == some("a");
}
#[test]
fn should_execute_op_on_impl_method_return() {
let doc = test::mk_doc(
"impl i for int { #[doc(return = \" a \")] fn a() -> int { fail } }");
assert doc.cratemod().impls()[0].methods[0].return.desc == some("a");
}
#[test]
fn should_execute_op_on_impl_method_failure_condition() {
let doc = test::mk_doc(
"impl i for int { #[doc(failure = \" a \")] fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].failure == some("a");
}
#[test]
fn should_execute_op_on_type_brief() {
let doc = test::mk_doc(
"#[doc(brief = \" a \")] type t = int;");
"#[doc = \" a \"] type t = int;");
assert doc.cratemod().types()[0].brief() == some("a");
}
#[test]
fn should_execute_op_on_type_desc() {
let doc = test::mk_doc(
"#[doc(desc = \" a \")] type t = int;");
"#[doc = \" a \"] type t = int;");
assert doc.cratemod().types()[0].desc() == some("a");
}
#[test]
fn should_execute_on_item_section_headers() {
let doc = test::mk_doc(
"#[doc = \"\
# Header \n\
Body\"]\
fn a() { }");
assert doc.cratemod().fns()[0].sections()[0].header == "Header";
}
#[test]
fn should_execute_on_item_section_bodies() {
let doc = test::mk_doc(
"#[doc = \"\
# Header\n\
Body \"]\
fn a() { }");
assert doc.cratemod().fns()[0].sections()[0].body == "Body";
}
#[test]
fn should_execute_on_iface_method_section_headers() {
let doc = test::mk_doc(
"iface i {
#[doc = \"\
# Header \n\
Body\"]\
fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].sections[0].header
== "Header";
}
#[test]
fn should_execute_on_iface_method_section_bodies() {
let doc = test::mk_doc(
"iface i {
#[doc = \"\
# Header\n\
Body \"]\
fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].sections[0].body == "Body";
}
#[test]
fn should_execute_on_impl_method_section_headers() {
let doc = test::mk_doc(
"impl i for bool {
#[doc = \"\
# Header \n\
Body\"]\
fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].sections[0].header
== "Header";
}
#[test]
fn should_execute_on_impl_method_section_bodies() {
let doc = test::mk_doc(
"impl i for bool {
#[doc = \"\
# Header\n\
Body \"]\
fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].sections[0].body == "Body";
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
let doc = desc_to_brief_pass::mk_pass().f(srv, doc);
let doc = sectionalize_pass::mk_pass().f(srv, doc);
mk_pass("", {|s| str::trim(s)}).f(srv, doc)
}
}

View File

@ -14,50 +14,12 @@ fn mk_pass() -> pass {
}
#[test]
fn should_trim_mod() {
let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \
desc = \"\ndesc\n\")] \
fn should_trim_text() {
let doc = test::mk_doc("#[doc = \" desc \"] \
mod m { }");
assert doc.cratemod().mods()[0].brief() == some("brief");
assert doc.cratemod().mods()[0].desc() == some("desc");
}
#[test]
fn should_trim_const() {
let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \
desc = \"\ndesc\n\")] \
const a: bool = true;");
assert doc.cratemod().consts()[0].brief() == some("brief");
assert doc.cratemod().consts()[0].desc() == some("desc");
}
#[test]
fn should_trim_fn() {
let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \
desc = \"\ndesc\n\")] \
fn a() { }");
assert doc.cratemod().fns()[0].brief() == some("brief");
assert doc.cratemod().fns()[0].desc() == some("desc");
}
#[test]
fn should_trim_args() {
let doc = test::mk_doc("#[doc(args(a = \"\na\n\"))] fn a(a: int) { }");
assert doc.cratemod().fns()[0].args[0].desc == some("a");
}
#[test]
fn should_trim_ret() {
let doc = test::mk_doc("#[doc(return = \"\na\n\")] fn a() -> int { }");
assert doc.cratemod().fns()[0].return.desc == some("a");
}
#[test]
fn should_trim_failure_conditions() {
let doc = test::mk_doc("#[doc(failure = \"\na\n\")] fn a() -> int { }");
assert doc.cratemod().fns()[0].failure == some("a");
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {

View File

@ -81,7 +81,7 @@ fn fold_const(
let srv = fold.ctxt;
{
ty: some(astsrv::exec(srv) {|ctxt|
sig: some(astsrv::exec(srv) {|ctxt|
alt check ctxt.ast_map.get(doc.id()) {
ast_map::node_item(@{
node: ast::item_const(ty, _), _
@ -97,7 +97,7 @@ fn fold_const(
#[test]
fn should_add_const_types() {
let doc = test::mk_doc("const a: bool = true;");
assert doc.cratemod().consts()[0].ty == some("bool");
assert doc.cratemod().consts()[0].sig == some("bool");
}
fn fold_enum(