CFG_CLANG_VERSION=$("$CFG_CLANG" \
--version \
| grep version \
- | cut -d ' ' -f 3)
+ | sed 's/.*\(version .*\)/\1/' \
+ | cut -d ' ' -f 2)
case $CFG_CLANG_VERSION in
(3.0svn | 3.0 | 3.1)
CC=clang
CXX=clang++
CPP=cpp
- CFG_GCCISH_CFLAGS += -Wall -Werror -fno-rtti -g
+ # -Wno-c++11-compat allows us to use 'alignof' as an identifier in the runtime
+ CFG_GCCISH_CFLAGS += -Wall -Werror -Wno-c++11-compat -fno-rtti -g
CFG_GCCISH_LINK_FLAGS += -g
CFG_DEPEND_C = $(CFG_GCCISH_CROSS)$(CXX) $(CFG_GCCISH_CFLAGS) -MT "$(1)" \
-MM $(2)
}
}
+fn cargo_suggestion(c: cargo, syncing: bool, fallback: fn())
+{
+ if c.sources.size() == 0u {
+ error("No sources defined. You may wish to run " +
+ "\"cargo init\" then \"cargo sync\".");
+ ret;
+ }
+ if !syncing {
+ let npkg = 0u;
+ c.sources.values({ |v| npkg += vec::len(v.packages) });
+ if npkg == 0u {
+ error("No packages known. You may wish to run " +
+ "\"cargo sync\".");
+ ret;
+ }
+ }
+ fallback();
+}
+
fn install_uuid(c: cargo, wd: str, uuid: str) {
let ps = [];
for_each_package(c, { |s, p|
install_package(c, wd, p);
ret;
} else if vec::len(ps) == 0u {
- error("No packages.");
+ cargo_suggestion(c, false, { || error("No packages match uuid."); });
ret;
}
error("Found multiple packages:");
install_package(c, wd, p);
ret;
} else if vec::len(ps) == 0u {
- error("No packages.");
+ cargo_suggestion(c, false, { || error("No packages match name."); });
ret;
}
error("Found multiple packages:");
if vec::len(argv) == 3u {
sync_one(c, argv[2], c.sources.get(argv[2]));
} else {
+ cargo_suggestion(c, true, { || } );
c.sources.items { |k, v|
sync_one(c, k, v);
}
import syntax::ast;
import util::common::*;
-export cstore;
+export cstore::{};
export cnum_map;
export crate_metadata;
export mk_cstore;
export send;
export recv;
-export chan;
-export port;
+export chan::{};
+export port::{};
#[abi = "cdecl"]
native mod rustrt {
// warn-and-below.
export error, warn, info, debug;
+
+#[doc = "The error log level"]
const error : u32 = 0_u32;
+#[doc = "The warning log level"]
const warn : u32 = 1_u32;
+#[doc = "The info log level"]
const info : u32 = 2_u32;
+#[doc = "The debug log level"]
const debug : u32 = 3_u32;
// A curious inner-module that's not exported that contains the binding
export c_int, c_uint, long, longlong, unsigned, ulong, ulonglong;
export intptr_t, uintptr_t;
export uint32_t;
-export void;
+export void::{};
export c_float, c_double;
export size_t, ssize_t;
export off_t, fd_t, pid_t;
push_char, is_utf8, from_chars, to_chars, char_len, char_len_range,
char_at, bytes, is_ascii, shift_byte, pop_byte,
unsafe_from_byte, unsafe_from_bytes, from_char, char_range_at,
+ from_bytes,
from_cstr, sbuf, as_buf, push_byte, utf8_char_width, safe_slice,
- contains, iter_chars, loop_chars, loop_chars_sub,
- escape;
+ contains, iter_chars, chars_iter, bytes_iter, words_iter, lines_iter,
+ loop_chars, loop_chars_sub, escape, any, all, map, windowed;
#[abi = "cdecl"]
native mod rustrt {
ret scopy;
}
+/*
+Function: from_bytes
+
+Safely convert a vector of bytes to a UTF-8 string, or error
+*/
+fn from_bytes(vv: [u8]) -> result::t<str, str> {
+ if is_utf8(vv) {
+ ret result::ok(unsafe_from_bytes(vv));
+ } else {
+ ret result::err("vector doesn't contain valid UTF-8");
+ }
+}
+
/*
Function: unsafe_from_byte
Iterate over the characters in a string
*/
-
fn iter_chars(s: str, it: fn(char)) {
let pos = 0u, len = byte_len(s);
while (pos < len) {
}
}
+/*
+Function: chars_iter
+
+Iterate over the characters in a string
+
+FIXME: A synonym to iter_chars
+*/
+fn chars_iter(ss: str, it: fn(char)) {
+ iter_chars(ss, it)
+}
+
+/*
+Function: bytes_iter
+
+Iterate over the bytes in a string
+
+FIXME: Should it really include the last byte '\0'?
+*/
+fn bytes_iter(ss: str, it: fn(u8)) {
+ let pos = 0u;
+ let len = byte_len(ss);
+
+ while (pos < len) {
+ it(ss[pos]);
+ pos += 1u;
+ }
+}
+
/*
Function: loop_chars
FIXME: will be renamed to split.
*/
-fn split_func(ss: str, sepfn: fn&(cc: char)->bool) -> [str] {
+fn split_func(ss: str, sepfn: fn(cc: char)->bool) -> [str] {
let vv: [str] = [];
let accum: str = "";
let ends_with_sep: bool = false;
{|w| 0u < str::char_len(w)});
}
+/*
+Function: words_iter
+
+Apply a function to each word
+*/
+fn words_iter(ss: str, ff: fn(&&str)) {
+ vec::iter(words(ss), ff)
+}
+
+/*
+Function: lines_iter
+
+Apply a function to each lines (by '\n')
+*/
+fn lines_iter(ss: str, ff: fn(&&str)) {
+ vec::iter(lines(ss), ff)
+}
+
/*
Function: concat
r
}
+/*
+Function: all
+
+Return true if a predicate matches all characters or
+if the string contains no characters
+
+// FIXME: a synonym to loop_chars
+*/
+fn all(ss: str, ff: fn(char) -> bool) -> bool {
+ str::loop_chars(ss, ff)
+}
+
+/*
+Function: any
+
+Return true if a predicate matches any character
+(and false if it matches none or there are no characters)
+*/
+fn any(ss: str, pred: fn(char) -> bool) -> bool {
+ !all(ss, {|cc| !pred(cc)})
+}
+
+/*
+Function: map
+
+Apply a function to each character
+*/
+fn map(ss: str, ff: fn(char) -> char) -> str {
+ let result = "";
+
+ str::iter_chars(ss, {|cc|
+ str::push_char(result, ff(cc));
+ });
+
+ ret result;
+}
+
+/*
+Function: windowed
+
+Create a vector of substrings of size `nn`
+*/
+fn windowed(nn: uint, ss: str) -> [str] {
+ let ww = [];
+ let len = str::char_len(ss);
+
+ assert 1u <= nn;
+
+ let ii = 0u;
+ while ii+nn <= len {
+ let w = char_slice( ss, ii, ii+nn );
+ vec::push(ww,w);
+ ii += 1u;
+ }
+
+ ret ww;
+}
+
#[cfg(test)]
mod tests {
assert (b == "AAAAAAA");
}
+ #[test]
+ fn test_from_bytes() {
+ let ss = "ศไทย中华Việt Nam";
+ let bb = [0xe0_u8, 0xb8_u8, 0xa8_u8,
+ 0xe0_u8, 0xb9_u8, 0x84_u8,
+ 0xe0_u8, 0xb8_u8, 0x97_u8,
+ 0xe0_u8, 0xb8_u8, 0xa2_u8,
+ 0xe4_u8, 0xb8_u8, 0xad_u8,
+ 0xe5_u8, 0x8d_u8, 0x8e_u8,
+ 0x56_u8, 0x69_u8, 0xe1_u8,
+ 0xbb_u8, 0x87_u8, 0x74_u8,
+ 0x20_u8, 0x4e_u8, 0x61_u8,
+ 0x6d_u8];
+
+ assert ss == result::get(from_bytes(bb));
+ }
+
#[test]
fn test_from_cstr() unsafe {
let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8];
}
i += 1;
}
+
+ iter_chars("") {|_ch| fail; } // should not fail
+ }
+
+ #[test]
+ fn test_chars_iter() {
+ let i = 0;
+ chars_iter("x\u03c0y") {|ch|
+ alt i {
+ 0 { assert ch == 'x'; }
+ 1 { assert ch == '\u03c0'; }
+ 2 { assert ch == 'y'; }
+ }
+ i += 1;
+ }
+
+ chars_iter("") {|_ch| fail; } // should not fail
+ }
+
+ #[test]
+ fn test_bytes_iter() {
+ let i = 0;
+
+ bytes_iter("xyz") {|bb|
+ alt i {
+ 0 { assert bb == 'x' as u8; }
+ 1 { assert bb == 'y' as u8; }
+ 2 { assert bb == 'z' as u8; }
+ }
+ i += 1;
+ }
+
+ bytes_iter("") {|bb| assert bb == 0u8; }
+ }
+
+ #[test]
+ fn test_words_iter() {
+ let data = "\nMary had a little lamb\nLittle lamb\n";
+
+ let ii = 0;
+
+ words_iter(data) {|ww|
+ alt ii {
+ 0 { assert "Mary" == ww; }
+ 1 { assert "had" == ww; }
+ 2 { assert "a" == ww; }
+ 3 { assert "little" == ww; }
+ _ { () }
+ }
+ ii += 1;
+ }
+
+ words_iter("") {|_x| fail; } // should not fail
+ }
+
+ #[test]
+ fn test_lines_iter () {
+ let lf = "\nMary had a little lamb\nLittle lamb\n";
+
+ let ii = 0;
+
+ lines_iter(lf) {|x|
+ alt ii {
+ 0 { assert "" == x; }
+ 1 { assert "Mary had a little lamb" == x; }
+ 2 { assert "Little lamb" == x; }
+ 3 { assert "" == x; }
+ _ { () }
+ }
+ ii += 1;
+ }
}
#[test]
assert(escape("abc\ndef") == "abc\\ndef");
assert(escape("abc\"def") == "abc\\\"def");
}
-}
\ No newline at end of file
+
+ #[test]
+ fn test_map() {
+ assert "" == map("", char::to_upper);
+ assert "YMCA" == map("ymca", char::to_upper);
+ }
+
+ #[test]
+ fn test_all() {
+ assert true == all("", char::is_uppercase);
+ assert false == all("ymca", char::is_uppercase);
+ assert true == all("YMCA", char::is_uppercase);
+ assert false == all("yMCA", char::is_uppercase);
+ assert false == all("YMCy", char::is_uppercase);
+ }
+
+ #[test]
+ fn test_any() {
+ assert false == any("", char::is_uppercase);
+ assert false == any("ymca", char::is_uppercase);
+ assert true == any("YMCA", char::is_uppercase);
+ assert true == any("yMCA", char::is_uppercase);
+ assert true == any("Ymcy", char::is_uppercase);
+ }
+
+ #[test]
+ fn test_windowed() {
+ let data = "ประเทศไทย中";
+
+ assert ["ประ", "ระเ", "ะเท", "เทศ", "ทศไ", "ศไท", "ไทย", "ทย中"]
+ == windowed(3u, data);
+
+ assert [data] == windowed(10u, data);
+
+ assert [] == windowed(6u, "abcd");
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_windowed_() {
+ let _x = windowed(0u, "abcd");
+ }
+}
}
}
+fn windowed <TT: copy> (nn: uint, xx: [TT]) -> [[TT]] {
+ let ww = [];
+
+ assert 1u <= nn;
+
+ vec::iteri (xx, {|ii, _x|
+ let len = vec::len(xx);
+
+ if ii+nn <= len {
+ let w = vec::slice ( xx, ii, ii+nn );
+ vec::push (ww, w);
+ }
+ });
+
+ ret ww;
+}
+
/*
Function: to_ptr
assert concat([[1], [2,3]]) == [1, 2, 3];
}
+ #[test]
+ fn test_windowed () {
+ assert [[1u,2u,3u],[2u,3u,4u],[3u,4u,5u],[4u,5u,6u]]
+ == windowed (3u, [1u,2u,3u,4u,5u,6u]);
+
+ assert [[1u,2u,3u,4u],[2u,3u,4u,5u],[3u,4u,5u,6u]]
+ == windowed (4u, [1u,2u,3u,4u,5u,6u]);
+
+ assert [] == windowed (7u, [1u,2u,3u,4u,5u,6u]);
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_windowed_() {
+ let _x = windowed (0u, [1u,2u,3u,4u,5u,6u]);
+ }
}
// Local Variables:
#if (defined __APPLE__) || (defined __clang__)
+#ifndef __FreeBSD__
+
typedef int _Unwind_Action;
typedef void _Unwind_Exception;
#endif
+#endif
+
import rustc::front::attr;
import core::tuple;
-export crate_attrs, mod_attrs, fn_attrs, arg_attrs;
-export parse_crate, parse_mod, parse_fn;
+export crate_attrs, mod_attrs, fn_attrs, arg_attrs, const_attrs;
+export parse_crate, parse_mod, parse_fn, parse_const;
type crate_attrs = {
name: option<str>
desc: str
};
+type const_attrs = {
+ brief: option<str>,
+ desc: option<str>
+};
+
fn doc_meta(
attrs: [ast::attribute]
) -> option<@ast::meta_item> {
assert attrs.args[1] == {name: "b", desc: "arg b"};
}
+fn parse_const(attrs: [ast::attribute]) -> const_attrs {
+ parse_short_doc_or(
+ attrs,
+ {|desc|
+ {
+ brief: none,
+ desc: desc
+ }
+ },
+ parse_const_long_doc
+ )
+}
+
+fn parse_const_long_doc(
+ _items: [@ast::meta_item],
+ brief: option<str>,
+ desc: option<str>
+) -> const_attrs {
+ {
+ brief: brief,
+ desc: desc
+ }
+}
+
+#[test]
+fn should_parse_const_short_doc() {
+ let source = "#[doc = \"description\"]";
+ let attrs = test::parse_attributes(source);
+ let attrs = parse_fn(attrs);
+ assert attrs.desc == some("description");
+}
+
+#[test]
+fn should_parse_const_long_doc() {
+ let source = "#[doc(brief = \"a\", desc = \"b\")]";
+ let attrs = test::parse_attributes(source);
+ let attrs = parse_fn(attrs);
+ assert attrs.brief == some("a");
+ assert attrs.desc == some("b");
+}
+
#[cfg(test)]
mod test {
let fold = fold::fold({
fold_crate: fold_crate,
fold_mod: fold_mod,
- fold_fn: fold_fn
+ fold_fn: fold_fn,
+ fold_const: fold_const
with *fold::default_seq_fold(srv)
});
fold.fold_crate(fold, doc)
assert doc.topmod.name == "bond";
}
+fn parse_item_attrs<T>(
+ srv: astsrv::srv,
+ id: doc::ast_id,
+ parse_attrs: fn~([ast::attribute]) -> T) -> T {
+ astsrv::exec(srv) {|ctxt|
+ let attrs = alt ctxt.map.get(id) {
+ ast_map::node_item(item) { item.attrs }
+ };
+ parse_attrs(attrs)
+ }
+}
+
fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
let srv = fold.ctxt;
let attrs = if doc.id == ast::crate_node_id {
attr_parser::parse_mod(ctxt.ast.node.attrs)
}
} else {
- astsrv::exec(srv) {|ctxt|
- let attrs = alt ctxt.map.get(doc.id) {
- ast_map::node_item(item) { item.attrs }
- };
- attr_parser::parse_mod(attrs)
- }
+ parse_item_attrs(srv, doc.id, attr_parser::parse_mod)
};
let doc = fold::default_seq_fold_mod(fold, doc);
ret merge_mod_attrs(doc, attrs);
let srv = fold.ctxt;
- let attrs = astsrv::exec(srv) {|ctxt|
- let attrs = alt ctxt.map.get(doc.id) {
- ast_map::node_item(item) { item.attrs }
- };
- attr_parser::parse_fn(attrs)
- };
+ let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);
ret merge_fn_attrs(doc, attrs);
fn merge_fn_attrs(
let fold = fold::default_seq_fold(srv);
let doc = fold_fn(fold, doc.topmod.fns[0]);
assert doc.sig == some("fn a() -> int");
-}
\ No newline at end of file
+}
+
+fn fold_const(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::constdoc
+) -> doc::constdoc {
+ let srv = fold.ctxt;
+ let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_mod);
+
+ ~{
+ brief: attrs.brief,
+ desc: attrs.desc
+ with *doc
+ }
+}
+
+#[test]
+fn fold_const_should_extract_docs() {
+ let source = "#[doc(brief = \"foo\", desc = \"bar\")]\
+ const a: bool = true;";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let fold = fold::default_seq_fold(srv);
+ let doc = fold_const(fold, doc.topmod.consts[0]);
+ assert doc.brief == some("foo");
+ assert doc.desc == some("bar");
+}
brief: option<str>,
desc: option<str>,
mods: modlist,
- fns: fnlist
+ fns: fnlist,
+ consts: constlist
+};
+
+type constdoc = ~{
+ id: ast_id,
+ name: str,
+ brief: option<str>,
+ desc: option<str>,
+ ty: option<str>
};
type fndoc = ~{
// Just to break the structural recursive types
enum modlist = [moddoc];
+enum constlist = [constdoc];
enum fnlist = [fndoc];
none
}
}
+ }),
+ consts: doc::constlist(
+ vec::filter_map(module.items) {|item|
+ alt item.node {
+ ast::item_const(_, _) {
+ some(constdoc_from_const(item.ident, item.id))
+ }
+ _ {
+ none
+ }
+ }
})
}
}
}
}
+fn constdoc_from_const(
+ name: ast::ident,
+ id: ast::node_id
+) -> doc::constdoc {
+ ~{
+ id: id,
+ name: name,
+ brief: none,
+ desc: none,
+ ty: none
+ }
+}
+
+#[test]
+fn should_extract_const_name_and_id() {
+ let source = "const a: int = 0;";
+ let ast = parse::from_str(source);
+ let doc = extract(ast, "");
+ assert doc.topmod.consts[0].id != 0;
+ assert doc.topmod.consts[0].name == "a";
+}
+
#[cfg(test)]
mod tests {
+// FIXME: Random import to solve the mystery resolve bug
+import std;
+
export fold;
export fold_crate, fold_mod, fold_fn, fold_modlist, fold_fnlist;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_mod;
export default_seq_fold_fn;
+export default_seq_fold_const;
export default_seq_fold_fnlist;
enum fold<T> = t<T>;
type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
-type fold_modlist<T> = fn~(fold: fold<T>,list: doc::modlist) -> doc::modlist;
-type fold_fnlist<T> = fn~(fold: fold<T>,list: doc::fnlist) -> doc::fnlist;
+type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
+type fold_modlist<T> = fn~(fold: fold<T>, list: doc::modlist) -> doc::modlist;
+type fold_fnlist<T> = fn~(fold: fold<T>, list: doc::fnlist) -> doc::fnlist;
+type fold_constlist<T> = fn~(
+ fold: fold<T>,
+ list: doc::constlist
+) -> doc::constlist;
type t<T> = {
ctxt: T,
fold_crate: fold_crate<T>,
fold_mod: fold_mod<T>,
fold_fn: fold_fn<T>,
+ fold_const: fold_const<T>,
fold_modlist: fold_modlist<T>,
- fold_fnlist: fold_fnlist<T>
+ fold_fnlist: fold_fnlist<T>,
+ fold_constlist: fold_constlist<T>
};
fold_crate: fold_crate<T>,
fold_mod: fold_mod<T>,
fold_fn: fold_fn<T>,
+ fold_const: fold_const<T>,
fold_modlist: fold_modlist<T>,
- fold_fnlist: fold_fnlist<T>
+ fold_fnlist: fold_fnlist<T>,
+ fold_constlist: fold_constlist<T>
) -> fold<T> {
fold({
ctxt: ctxt,
fold_crate: fold_crate,
fold_mod: fold_mod,
fold_fn: fold_fn,
+ fold_const: fold_const,
fold_modlist: fold_modlist,
- fold_fnlist: fold_fnlist
+ fold_fnlist: fold_fnlist,
+ fold_constlist: fold_constlist
})
}
{|f, d| default_seq_fold_crate(f, d)},
{|f, d| default_seq_fold_mod(f, d)},
{|f, d| default_seq_fold_fn(f, d)},
+ {|f, d| default_seq_fold_const(f, d)},
{|f, d| default_seq_fold_modlist(f, d)},
- {|f, d| default_seq_fold_fnlist(f, d)}
+ {|f, d| default_seq_fold_fnlist(f, d)},
+ {|f, d| default_seq_fold_constlist(f, d)}
)
}
) -> doc::moddoc {
~{
mods: fold.fold_modlist(fold, doc.mods),
- fns: fold.fold_fnlist(fold, doc.fns)
+ fns: fold.fold_fnlist(fold, doc.fns),
+ consts: fold.fold_constlist(fold, doc.consts)
with *doc
}
}
doc
}
+fn default_seq_fold_const<T>(
+ _fold: fold<T>,
+ doc: doc::constdoc
+) -> doc::constdoc {
+ doc
+}
+
fn default_seq_fold_modlist<T>(
fold: fold<T>,
list: doc::modlist
})
}
-#[cfg(test)]
-mod tests {
- #[test]
- fn default_fold_should_produce_same_doc() {
- let source = "mod a { fn b() { } mod c { fn d() { } } }";
- let ast = parse::from_str(source);
- let doc = extract::extract(ast, "");
- let fld = default_seq_fold(());
- let folded = fld.fold_crate(fld, doc);
- assert doc == folded;
- }
+fn default_seq_fold_constlist<T>(
+ fold: fold<T>,
+ list: doc::constlist
+) -> doc::constlist {
+ doc::constlist(vec::map(*list) {|doc|
+ fold.fold_const(fold, doc)
+ })
+}
+
+#[test]
+fn default_fold_should_produce_same_doc() {
+ let source = "mod a { fn b() { } mod c { fn d() { } } }";
+ let ast = parse::from_str(source);
+ let doc = extract::extract(ast, "");
+ let fld = default_seq_fold(());
+ let folded = fld.fold_crate(fld, doc);
+ assert doc == folded;
+}
+
+#[test]
+fn default_fold_should_produce_same_consts() {
+ let source = "const a: int = 0;";
+ let ast = parse::from_str(source);
+ let doc = extract::extract(ast, "");
+ let fld = default_seq_fold(());
+ let folded = fld.fold_crate(fld, doc);
+ assert doc == folded;
}
\ No newline at end of file
write_brief(ctxt, doc.brief);
write_desc(ctxt, doc.desc);
+ for constdoc in *doc.consts {
+ write_const(ctxt, constdoc);
+ }
+
for fndoc in *doc.fns {
write_fn(ctxt, fndoc);
}
assert str::contains(markdown, "Returns `int` - blorp");
}
+fn write_const(
+ ctxt: ctxt,
+ doc: doc::constdoc
+) {
+ write_header(ctxt, h3, #fmt("Const `%s`", doc.name));
+ write_sig(ctxt, doc.ty);
+ write_brief(ctxt, doc.brief);
+ write_desc(ctxt, doc.desc);
+}
+
+#[test]
+fn should_write_const_header() {
+ let markdown = test::render("const a: bool = true;");
+ assert str::contains(markdown, "### Const `a`\n\n");
+}
+
+#[test]
+fn should_write_const_description() {
+ let markdown = test::render(
+ "#[doc(brief = \"a\", desc = \"b\")]\
+ const a: bool = true;");
+ assert str::contains(markdown, "\n\na\n\nb\n\n");
+}
+
#[cfg(test)]
mod test {
fn render(source: str) -> str {
#[test]
fn write_markdown_should_write_function_header() {
let markdown = render("fn func() { }");
- assert str::contains(markdown, "## Function `func`");
+ assert str::contains(markdown, "### Function `func`");
}
#[test]
let fold = fold::fold({
fold_mod: fold_mod,
fold_fn: fold_fn,
+ fold_const: fold_const,
fold_modlist: fold_modlist,
- fold_fnlist: fold_fnlist
+ fold_fnlist: fold_fnlist,
+ fold_constlist: fold_constlist
with *fold::default_seq_fold(ctxt)
});
fold.fold_crate(fold, doc)
list: doc::modlist
) -> doc::modlist {
doc::modlist(vec::filter_map(*list) {|doc|
- let doc = fold_mod(fold, doc);
+ let doc = fold.fold_mod(fold, doc);
if fold.ctxt.have_docs {
some(doc)
} else {
list: doc::fnlist
) -> doc::fnlist {
doc::fnlist(vec::filter_map(*list) {|doc|
- let doc = fold_fn(fold, doc);
+ let doc = fold.fold_fn(fold, doc);
if fold.ctxt.have_docs {
some(doc)
} else {
let doc = run(srv, doc);
assert vec::is_empty(*doc.topmod.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;
+}
+
+fn fold_constlist(
+ fold: fold::fold<ctxt>,
+ list: doc::constlist
+) -> doc::constlist {
+ doc::constlist(vec::filter_map(*list) {|doc|
+ let doc = fold.fold_const(fold, doc);
+ if fold.ctxt.have_docs {
+ some(doc)
+ } else {
+ none
+ }
+ })
+}
+
+#[test]
+fn should_elide_undocumented_consts() {
+ let source = "const a: bool = true;";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::is_empty(*doc.topmod.consts);
+}
--- /dev/null
+#[doc = "Prunes branches of the tree that are not exported"];
+
+import rustc::syntax::ast;
+import rustc::syntax::ast_util;
+import rustc::middle::ast_map;
+
+export mk_pass;
+
+fn mk_pass() -> pass {
+ run
+}
+
+fn run(srv: astsrv::srv, doc: doc::cratedoc) -> doc::cratedoc {
+ let fold = fold::fold({
+ fold_mod: fold_mod
+ with *fold::default_seq_fold(srv)
+ });
+ fold.fold_crate(fold, doc)
+}
+
+fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
+ let doc = fold::default_seq_fold_mod(fold, doc);
+ ~{
+ mods: doc::modlist(exported_mods(fold.ctxt, doc)),
+ fns: doc::fnlist(exported_fns(fold.ctxt, doc)),
+ consts: doc::constlist(exported_consts(fold.ctxt, doc))
+ with *doc
+ }
+}
+
+fn exported_mods(srv: astsrv::srv, doc: doc::moddoc) -> [doc::moddoc] {
+ exported_things(
+ srv, doc,
+ exported_mods_from_crate,
+ exported_mods_from_mod
+ )
+}
+
+fn exported_fns(srv: astsrv::srv, doc: doc::moddoc) -> [doc::fndoc] {
+ exported_things(
+ srv, doc,
+ exported_fns_from_crate,
+ exported_fns_from_mod
+ )
+}
+
+fn exported_consts(srv: astsrv::srv, doc: doc::moddoc) -> [doc::constdoc] {
+ exported_things(
+ srv, doc,
+ exported_consts_from_crate,
+ exported_consts_from_mod
+ )
+}
+
+fn exported_things<T>(
+ srv: astsrv::srv,
+ doc: doc::moddoc,
+ from_crate: fn(astsrv::srv, doc::moddoc) -> [T],
+ from_mod: fn(astsrv::srv, doc::moddoc) -> [T]
+) -> [T] {
+ if doc.id == ast::crate_node_id {
+ from_crate(srv, doc)
+ } else {
+ from_mod(srv, doc)
+ }
+}
+
+fn exported_mods_from_crate(
+ srv: astsrv::srv,
+ doc: doc::moddoc
+) -> [doc::moddoc] {
+ exported_mods_from(srv, doc, is_exported_from_crate)
+}
+
+fn exported_mods_from_mod(
+ srv: astsrv::srv,
+ doc: doc::moddoc
+) -> [doc::moddoc] {
+ exported_mods_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
+}
+
+fn exported_fns_from_crate(
+ srv: astsrv::srv,
+ doc: doc::moddoc
+) -> [doc::fndoc] {
+ exported_fns_from(srv, doc, is_exported_from_crate)
+}
+
+fn exported_fns_from_mod(
+ srv: astsrv::srv,
+ doc: doc::moddoc
+) -> [doc::fndoc] {
+ exported_fns_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
+}
+
+fn exported_consts_from_crate(
+ srv: astsrv::srv,
+ doc: doc::moddoc
+) -> [doc::constdoc] {
+ exported_consts_from(srv, doc, is_exported_from_crate)
+}
+
+fn exported_consts_from_mod(
+ srv: astsrv::srv,
+ doc: doc::moddoc
+) -> [doc::constdoc] {
+ exported_consts_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
+}
+
+fn exported_fns_from(
+ srv: astsrv::srv,
+ doc: doc::moddoc,
+ is_exported: fn(astsrv::srv, str) -> bool
+) -> [doc::fndoc] {
+ vec::filter_map(*doc.fns) { |doc|
+ if is_exported(srv, doc.name) {
+ some(doc)
+ } else {
+ none
+ }
+ }
+}
+
+fn exported_mods_from(
+ srv: astsrv::srv,
+ doc: doc::moddoc,
+ is_exported: fn(astsrv::srv, str) -> bool
+) -> [doc::moddoc] {
+ vec::filter_map(*doc.mods) { |doc|
+ if is_exported(srv, doc.name) {
+ some(doc)
+ } else {
+ none
+ }
+ }
+}
+
+fn exported_consts_from(
+ srv: astsrv::srv,
+ doc: doc::moddoc,
+ is_exported: fn(astsrv::srv, str) -> bool
+) -> [doc::constdoc] {
+ vec::filter_map(*doc.consts) { |doc|
+ if is_exported(srv, doc.name) {
+ some(doc)
+ } else {
+ none
+ }
+ }
+}
+
+fn is_exported_from_mod(
+ srv: astsrv::srv,
+ mod_id: doc::ast_id,
+ item_name: str
+) -> bool {
+ astsrv::exec(srv) {|ctxt|
+ alt ctxt.map.get(mod_id) {
+ ast_map::node_item(item) {
+ alt item.node {
+ ast::item_mod(m) {
+ ast_util::is_exported(item_name, m)
+ }
+ }
+ }
+ }
+ }
+}
+
+fn is_exported_from_crate(
+ srv: astsrv::srv,
+ item_name: str
+) -> bool {
+ astsrv::exec(srv) {|ctxt|
+ ast_util::is_exported(item_name, ctxt.ast.node.module)
+ }
+}
+
+#[test]
+fn should_prune_unexported_fns() {
+ let source = "mod b { export a; fn a() { } fn b() { } }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::len(*doc.topmod.mods[0].fns) == 1u;
+}
+
+#[test]
+fn should_prune_unexported_fns_from_top_mod() {
+ let source = "export a; fn a() { } fn b() { }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::len(*doc.topmod.fns) == 1u;
+}
+
+#[test]
+fn should_prune_unexported_modules() {
+ let source = "mod a { export a; mod a { } mod b { } }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::len(*doc.topmod.mods[0].mods) == 1u;
+}
+
+#[test]
+fn should_prune_unexported_modules_from_top_mod() {
+ let source = "export a; mod a { } mod b { }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::len(*doc.topmod.mods) == 1u;
+}
+
+#[test]
+fn should_prune_unexported_consts() {
+ let source = "mod a { export a; \
+ const a: bool = true; \
+ const b: bool = true; }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::len(*doc.topmod.mods[0].consts) == 1u;
+}
+
+#[test]
+fn should_prune_unexported_consts_from_top_mod() {
+ let source = "export a; const a: bool = true; const b: bool = true;";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert vec::len(*doc.topmod.consts) == 1u;
+}
mod attr_pass;
mod tystr_pass;
mod prune_undoc_pass;
+mod prune_unexported_pass;
mod astsrv;
brief: none,
desc: none,
mods: doc::modlist([]),
- fns: doc::fnlist([])
+ fns: doc::fnlist([]),
+ consts: doc::constlist([])
}
}
}
brief: none,
desc: none,
mods: doc::modlist([]),
- fns: doc::fnlist([])
+ fns: doc::fnlist([]),
+ consts: doc::constlist([])
}
}
}
let srv = astsrv::mk_srv_from_file(source_file);
let doc = extract::from_srv(srv, default_name);
run_passes(srv, doc, [
+ prune_unexported_pass::mk_pass(),
tystr_pass::mk_pass(),
path_pass::mk_pass(),
attr_pass::mk_pass(),
doc: doc::cratedoc
) -> doc::cratedoc {
let fold = fold::fold({
- fold_fn: fold_fn
+ fold_fn: fold_fn,
+ fold_const: fold_const
with *fold::default_seq_fold(srv)
});
fold.fold_crate(fold, doc)
let fn_ = doc.topmod.fns[0];
assert fn_.args[0].ty == some("int");
assert fn_.args[1].ty == some("bool");
+}
+
+fn fold_const(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::constdoc
+) -> doc::constdoc {
+ let srv = fold.ctxt;
+
+ ~{
+ ty: some(astsrv::exec(srv) {|ctxt|
+ alt ctxt.map.get(doc.id) {
+ ast_map::node_item(@{
+ node: ast::item_const(ty, _), _
+ }) {
+ pprust::ty_to_str(ty)
+ }
+ }
+ })
+ with *doc
+ }
+}
+
+#[test]
+fn should_add_const_types() {
+ let source = "const a: bool = true;";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = run(srv, doc);
+ assert doc.topmod.consts[0].ty == some("bool");
}
\ No newline at end of file
+S 2012-01-23 6db688e
+ winnt-i386 e2e854ea3b53c39c348ecff56c46ec2e742930ef
+ linux-i386 ec28f47ea12512c79d110209d7278cbdb9db826c
+ macos-i386 e2fae898344cbbfd52a8cdd21063b8aadc9ca12e
+ linux-x86_64 b8492ad26d3ad9fbf91e7e1983bec484f76aeb49
+ macos-x86_64 8a8ecedc8ab6e02881395394a8ca6cb3aca3dece
+
S 2012-01-21 ec82735
winnt-i386 b77e911a0651199b2459fc429c3ab05d623cd1e1
linux-i386 177e2a4d6996f704af9e5676352278d52cfe0d18