auto merge of #8540 : cmr/rust/rustdoc_ng, r=catamorphism
This doesn't enable it by default yet, or include the frontend. But the tool is pretty much done, and it'd be nice to stave off bitrot. I couldn't get it to actually build with the Makefile though. I don't really understand what is going on in that makefile at all. Could @graydon or @pnkfelix lend a hand?
This commit is contained in:
commit
3e1803f3af
@ -214,6 +214,7 @@ CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
|
||||
CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
|
||||
CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
|
||||
CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
|
||||
CFG_LIBRUSTDOCNG_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc_ng)
|
||||
CFG_LIBRUSTI_$(1) :=$(call CFG_LIB_NAME_$(1),rusti)
|
||||
CFG_LIBRUST_$(1) :=$(call CFG_LIB_NAME_$(1),rust)
|
||||
|
||||
@ -223,6 +224,7 @@ LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
|
||||
LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
|
||||
LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
|
||||
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
|
||||
LIBRUSTDOCNG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc_ng)
|
||||
LIBRUSTI_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rusti)
|
||||
LIBRUST_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rust)
|
||||
EXTRALIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),extra)
|
||||
@ -231,6 +233,7 @@ LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
|
||||
LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
|
||||
LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
|
||||
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
|
||||
LIBRUSTDOCNG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc_ng)
|
||||
LIBRUSTI_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rusti)
|
||||
LIBRUST_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rust)
|
||||
|
||||
@ -443,6 +446,7 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(HBIN$(1)_H_$(3))/rust$$(X_$(3)) \
|
||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
|
||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOC_$(3)) \
|
||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(3)) \
|
||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTI_$(3)) \
|
||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUST_$(3)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
|
||||
@ -451,6 +455,7 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(2)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUST_$(2))
|
||||
|
||||
|
@ -72,6 +72,7 @@ clean$(1)_H_$(2):
|
||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOCNG_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_STDLIB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_EXTRALIB_$(2))
|
||||
@ -85,6 +86,7 @@ clean$(1)_H_$(2):
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOCNG_GLOB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUST_GLOB_$(2))
|
||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM_$(2))
|
||||
@ -107,6 +109,7 @@ clean$(1)_T_$(2)_H_$(3):
|
||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
|
||||
@ -120,6 +123,7 @@ clean$(1)_T_$(2)_H_$(3):
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOCNG_GLOB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTI_GLOB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUST_GLOB_$(2))
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(2))
|
||||
|
@ -104,6 +104,7 @@ install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
|
||||
$$(Q)$$(call INSTALL_LIB,$$(LIBSYNTAX_GLOB_$(1)))
|
||||
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTPKG_GLOB_$(1)))
|
||||
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTDOC_GLOB_$(1)))
|
||||
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTDOCNG_GLOB_$(1)))
|
||||
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTI_GLOB_$(1)))
|
||||
$$(Q)$$(call INSTALL_LIB,$$(LIBRUST_GLOB_$(1)))
|
||||
$$(Q)$$(call INSTALL_LIB,libmorestack.a)
|
||||
@ -149,6 +150,7 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE))
|
||||
$(Q)$(call INSTALL_LIB,$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||
$(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||
$(Q)$(call INSTALL_LIB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||
$(Q)$(call INSTALL_LIB,$(LIBRUSTDOCNG_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE)))
|
||||
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE)))
|
||||
$(Q)$(call INSTALL,$(S)/man, $(PREFIX_ROOT)/share/man/man1,rust.1)
|
||||
|
37
mk/tools.mk
37
mk/tools.mk
@ -23,6 +23,11 @@ RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*.rs)
|
||||
RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rs
|
||||
RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs)
|
||||
|
||||
# rustdoc_ng, the next generation documentation tool
|
||||
|
||||
RUSTDOCNG_LIB := $(S)src/rustdoc_ng/lib.rs
|
||||
RUSTDOCNG_INPUTS := $(wildcard $(S)src/rustdoc_ng/*.rs)
|
||||
|
||||
# Rusti, the JIT REPL
|
||||
RUSTI_LIB := $(S)src/librusti/rusti.rs
|
||||
RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs)
|
||||
@ -78,6 +83,24 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
|
||||
@$$(call E, compile_and_link: $$@)
|
||||
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustdoc -o $$@ $$<
|
||||
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)): \
|
||||
$$(RUSTDOCNG_LIB) $$(RUSTDOCNG_INPUTS) \
|
||||
$$(SREQ$(1)_T_$(4)_H_$(3)) \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
|
||||
| $$(TLIB$(1)_T_$(4)_H_$(3))/
|
||||
@$$(call E, compile_and_link: $$@)
|
||||
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
|
||||
$$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
|
||||
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
|
||||
|
||||
$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc_ng$$(X_$(4)): \
|
||||
$$(DRIVER_CRATE) \
|
||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)) \
|
||||
| $$(TBIN$(1)_T_$(4)_H_$(3))/
|
||||
@$$(call E, compile_and_link: $$@)
|
||||
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustdoc_ng -o $$@ $$<
|
||||
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \
|
||||
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
|
||||
$$(SREQ$(1)_T_$(4)_H_$(3)) \
|
||||
@ -102,6 +125,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)): \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)) \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
|
||||
| $$(TLIB$(1)_T_$(4)_H_$(3))/
|
||||
@$$(call E, compile_and_link: $$@)
|
||||
@ -171,6 +195,19 @@ $$(HBIN$(2)_H_$(4))/rustdoc$$(X_$(4)): \
|
||||
@$$(call E, cp: $$@)
|
||||
$$(Q)cp $$< $$@
|
||||
|
||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOCNG_$(4)): \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)) \
|
||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
|
||||
$$(HSREQ$(2)_H_$(4)) \
|
||||
| $$(HLIB$(2)_H_$(4))/
|
||||
@$$(call E, cp: $$@)
|
||||
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
|
||||
$$(Q)cp $$< $$@
|
||||
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
|
||||
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOCNG_GLOB_$(4)) \
|
||||
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOCNG_DSYM_GLOB_$(4))) \
|
||||
$$(HLIB$(2)_H_$(4))
|
||||
|
||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTI_$(4)): \
|
||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
|
||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
|
||||
|
2
src/rustdoc_ng/.gitignore
vendored
Normal file
2
src/rustdoc_ng/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.swp
|
||||
main
|
1069
src/rustdoc_ng/clean.rs
Normal file
1069
src/rustdoc_ng/clean.rs
Normal file
File diff suppressed because it is too large
Load Diff
78
src/rustdoc_ng/core.rs
Normal file
78
src/rustdoc_ng/core.rs
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc;
|
||||
use rustc::{driver, middle};
|
||||
|
||||
use syntax;
|
||||
use syntax::parse;
|
||||
use syntax::ast;
|
||||
|
||||
use std::os;
|
||||
use std::local_data;
|
||||
|
||||
use visit_ast::RustdocVisitor;
|
||||
use clean;
|
||||
use clean::Clean;
|
||||
|
||||
pub struct DocContext {
|
||||
crate: @ast::Crate,
|
||||
tycx: middle::ty::ctxt,
|
||||
sess: driver::session::Session
|
||||
}
|
||||
|
||||
/// Parses, resolves, and typechecks the given crate
|
||||
fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
|
||||
use syntax::codemap::dummy_spanned;
|
||||
use rustc::driver::driver::*;
|
||||
|
||||
let parsesess = parse::new_parse_sess(None);
|
||||
let input = file_input(cpath.clone());
|
||||
|
||||
let sessopts = @driver::session::options {
|
||||
binary: @"rustdoc",
|
||||
maybe_sysroot: Some(@os::self_exe_path().unwrap().pop()),
|
||||
addl_lib_search_paths: @mut libs,
|
||||
.. (*rustc::driver::session::basic_options()).clone()
|
||||
};
|
||||
|
||||
|
||||
let diagnostic_handler = syntax::diagnostic::mk_handler(None);
|
||||
let span_diagnostic_handler =
|
||||
syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
|
||||
|
||||
let sess = driver::driver::build_session_(sessopts, parsesess.cm,
|
||||
syntax::diagnostic::emit,
|
||||
span_diagnostic_handler);
|
||||
|
||||
let mut cfg = build_configuration(sess);
|
||||
cfg.push(@dummy_spanned(ast::MetaWord(@"stage2")));
|
||||
|
||||
let mut crate = phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
crate = phase_2_configure_and_expand(sess, cfg, crate);
|
||||
let analysis = phase_3_run_analysis_passes(sess, crate);
|
||||
|
||||
debug!("crate: %?", crate);
|
||||
DocContext { crate: crate, tycx: analysis.ty_cx, sess: sess }
|
||||
}
|
||||
|
||||
pub fn run_core (libs: ~[Path], path: &Path) -> clean::Crate {
|
||||
let ctxt = @get_ast_and_resolve(path, libs);
|
||||
debug!("defmap:");
|
||||
for (k, v) in ctxt.tycx.def_map.iter() {
|
||||
debug!("%?: %?", k, v);
|
||||
}
|
||||
local_data::set(super::ctxtkey, ctxt);
|
||||
|
||||
let v = @mut RustdocVisitor::new();
|
||||
v.visit(ctxt.crate);
|
||||
|
||||
v.clean()
|
||||
}
|
168
src/rustdoc_ng/doctree.rs
Normal file
168
src/rustdoc_ng/doctree.rs
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This module is used to store stuff from Rust's AST in a more convenient
|
||||
//! manner (and with prettier names) before cleaning.
|
||||
|
||||
use syntax;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{Ident, NodeId};
|
||||
|
||||
pub struct Module {
|
||||
name: Option<Ident>,
|
||||
attrs: ~[ast::Attribute],
|
||||
where: Span,
|
||||
structs: ~[Struct],
|
||||
enums: ~[Enum],
|
||||
fns: ~[Function],
|
||||
mods: ~[Module],
|
||||
id: NodeId,
|
||||
typedefs: ~[Typedef],
|
||||
statics: ~[Static],
|
||||
traits: ~[Trait],
|
||||
vis: ast::visibility,
|
||||
impls: ~[Impl],
|
||||
view_items: ~[ast::view_item],
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn new(name: Option<Ident>) -> Module {
|
||||
Module {
|
||||
name : name,
|
||||
id: 0,
|
||||
vis: ast::private,
|
||||
where: syntax::codemap::dummy_sp(),
|
||||
attrs : ~[],
|
||||
structs : ~[],
|
||||
enums : ~[],
|
||||
fns : ~[],
|
||||
mods : ~[],
|
||||
typedefs : ~[],
|
||||
statics : ~[],
|
||||
traits : ~[],
|
||||
impls : ~[],
|
||||
view_items : ~[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(ToStr, Clone, Encodable, Decodable)]
|
||||
pub enum StructType {
|
||||
/// A normal struct
|
||||
Plain,
|
||||
/// A tuple struct
|
||||
Tuple,
|
||||
/// A newtype struct (tuple struct with one element)
|
||||
Newtype,
|
||||
/// A unit struct
|
||||
Unit
|
||||
}
|
||||
|
||||
pub enum TypeBound {
|
||||
RegionBound,
|
||||
TraitBound(ast::trait_ref)
|
||||
}
|
||||
|
||||
pub struct Struct {
|
||||
vis: ast::visibility,
|
||||
id: NodeId,
|
||||
struct_type: StructType,
|
||||
name: Ident,
|
||||
generics: ast::Generics,
|
||||
attrs: ~[ast::Attribute],
|
||||
fields: ~[@ast::struct_field],
|
||||
where: Span,
|
||||
}
|
||||
|
||||
pub struct Enum {
|
||||
vis: ast::visibility,
|
||||
variants: ~[Variant],
|
||||
generics: ast::Generics,
|
||||
attrs: ~[ast::Attribute],
|
||||
id: NodeId,
|
||||
where: Span,
|
||||
name: Ident,
|
||||
}
|
||||
|
||||
pub struct Variant {
|
||||
name: Ident,
|
||||
attrs: ~[ast::Attribute],
|
||||
kind: ast::variant_kind,
|
||||
id: ast::NodeId,
|
||||
vis: ast::visibility,
|
||||
where: Span,
|
||||
}
|
||||
|
||||
pub struct Function {
|
||||
decl: ast::fn_decl,
|
||||
attrs: ~[ast::Attribute],
|
||||
id: NodeId,
|
||||
name: Ident,
|
||||
vis: ast::visibility,
|
||||
where: Span,
|
||||
generics: ast::Generics,
|
||||
}
|
||||
|
||||
pub struct Typedef {
|
||||
ty: ast::Ty,
|
||||
gen: ast::Generics,
|
||||
name: Ident,
|
||||
id: ast::NodeId,
|
||||
attrs: ~[ast::Attribute],
|
||||
where: Span,
|
||||
vis: ast::visibility,
|
||||
}
|
||||
|
||||
pub struct Static {
|
||||
type_: ast::Ty,
|
||||
mutability: ast::Mutability,
|
||||
expr: @ast::Expr,
|
||||
name: Ident,
|
||||
attrs: ~[ast::Attribute],
|
||||
vis: ast::visibility,
|
||||
id: ast::NodeId,
|
||||
where: Span,
|
||||
}
|
||||
|
||||
pub struct Trait {
|
||||
name: Ident,
|
||||
methods: ~[ast::trait_method], //should be TraitMethod
|
||||
generics: ast::Generics,
|
||||
parents: ~[ast::trait_ref],
|
||||
attrs: ~[ast::Attribute],
|
||||
id: ast::NodeId,
|
||||
where: Span,
|
||||
vis: ast::visibility,
|
||||
}
|
||||
|
||||
pub struct Impl {
|
||||
generics: ast::Generics,
|
||||
trait_: Option<ast::trait_ref>,
|
||||
for_: ast::Ty,
|
||||
methods: ~[@ast::method],
|
||||
attrs: ~[ast::Attribute],
|
||||
where: Span,
|
||||
vis: ast::visibility,
|
||||
id: ast::NodeId,
|
||||
}
|
||||
|
||||
pub fn struct_type_from_def(sd: &ast::struct_def) -> StructType {
|
||||
if sd.ctor_id.is_some() {
|
||||
// We are in a tuple-struct
|
||||
match sd.fields.len() {
|
||||
0 => Unit,
|
||||
1 => Newtype,
|
||||
_ => Tuple
|
||||
}
|
||||
} else {
|
||||
Plain
|
||||
}
|
||||
}
|
111
src/rustdoc_ng/fold.rs
Normal file
111
src/rustdoc_ng/fold.rs
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std;
|
||||
use clean::*;
|
||||
use std::iter::Extendable;
|
||||
|
||||
pub trait DocFolder {
|
||||
fn fold_item(&mut self, item: Item) -> Option<Item> {
|
||||
self.fold_item_recur(item)
|
||||
}
|
||||
|
||||
/// don't override!
|
||||
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
|
||||
use std::util::swap;
|
||||
let Item { attrs, name, source, visibility, id, inner } = item;
|
||||
let inner = inner;
|
||||
let c = |x| self.fold_item(x);
|
||||
let inner = match inner {
|
||||
StructItem(i) => {
|
||||
let mut i = i;
|
||||
let mut foo = ~[]; swap(&mut foo, &mut i.fields);
|
||||
i.fields.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
|
||||
StructItem(i)
|
||||
},
|
||||
ModuleItem(i) => {
|
||||
ModuleItem(self.fold_mod(i))
|
||||
},
|
||||
EnumItem(i) => {
|
||||
let mut i = i;
|
||||
let mut foo = ~[]; swap(&mut foo, &mut i.variants);
|
||||
i.variants.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
|
||||
EnumItem(i)
|
||||
},
|
||||
TraitItem(i) => {
|
||||
fn vtrm<T: DocFolder>(this: &mut T, trm: TraitMethod) -> Option<TraitMethod> {
|
||||
match trm {
|
||||
Required(it) => {
|
||||
match this.fold_item(it) {
|
||||
Some(x) => return Some(Required(x)),
|
||||
None => return None,
|
||||
}
|
||||
},
|
||||
Provided(it) => {
|
||||
match this.fold_item(it) {
|
||||
Some(x) => return Some(Provided(x)),
|
||||
None => return None,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let mut i = i;
|
||||
let mut foo = ~[]; swap(&mut foo, &mut i.methods);
|
||||
i.methods.extend(&mut foo.move_iter().filter_map(|x| vtrm(self, x)));
|
||||
TraitItem(i)
|
||||
},
|
||||
ImplItem(i) => {
|
||||
let mut i = i;
|
||||
let mut foo = ~[]; swap(&mut foo, &mut i.methods);
|
||||
i.methods.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
|
||||
ImplItem(i)
|
||||
},
|
||||
VariantItem(i) => {
|
||||
let i2 = i.clone(); // this clone is small
|
||||
match i.kind {
|
||||
StructVariant(j) => {
|
||||
let mut j = j;
|
||||
let mut foo = ~[]; swap(&mut foo, &mut j.fields);
|
||||
j.fields.extend(&mut foo.move_iter().filter_map(c));
|
||||
VariantItem(Variant {kind: StructVariant(j), ..i2})
|
||||
},
|
||||
_ => VariantItem(i2)
|
||||
}
|
||||
},
|
||||
x => x
|
||||
};
|
||||
|
||||
Some(Item { attrs: attrs, name: name, source: source, inner: inner,
|
||||
visibility: visibility, id: id })
|
||||
}
|
||||
|
||||
fn fold_mod(&mut self, m: Module) -> Module {
|
||||
Module { items: m.items.move_iter().filter_map(|i| self.fold_item(i)).collect() }
|
||||
}
|
||||
|
||||
fn fold_crate(&mut self, mut c: Crate) -> Crate {
|
||||
let mut mod_ = None;
|
||||
std::util::swap(&mut mod_, &mut c.module);
|
||||
let mod_ = mod_.unwrap();
|
||||
c.module = self.fold_item(mod_);
|
||||
let Crate { name, module } = c;
|
||||
match module {
|
||||
Some(Item { inner: ModuleItem(m), name: name_, attrs: attrs_,
|
||||
source, visibility: vis, id }) => {
|
||||
return Crate { module: Some(Item { inner:
|
||||
ModuleItem(self.fold_mod(m)),
|
||||
name: name_, attrs: attrs_,
|
||||
source: source, id: id, visibility: vis }), name: name};
|
||||
},
|
||||
Some(_) => fail!("non-module item set as module of crate"),
|
||||
None => return Crate { module: None, name: name},
|
||||
}
|
||||
}
|
||||
}
|
37
src/rustdoc_ng/lib.rs
Normal file
37
src/rustdoc_ng/lib.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[link(name = "rustdoc_ng",
|
||||
vers = "0.1.0",
|
||||
uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6")];
|
||||
#[desc = "rustdoc, the Rust documentation extractor"];
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[deny(warnings)];
|
||||
|
||||
extern mod syntax;
|
||||
extern mod rustc;
|
||||
|
||||
extern mod extra;
|
||||
|
||||
use extra::serialize::Encodable;
|
||||
|
||||
pub mod core;
|
||||
pub mod doctree;
|
||||
pub mod clean;
|
||||
pub mod visit_ast;
|
||||
pub mod fold;
|
||||
pub mod plugins;
|
||||
pub mod passes;
|
||||
|
||||
pub static SCHEMA_VERSION: &'static str = "0.8.0";
|
||||
|
||||
pub static ctxtkey: std::local_data::Key<@core::DocContext> = &std::local_data::Key;
|
104
src/rustdoc_ng/main.rs
Normal file
104
src/rustdoc_ng/main.rs
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[link(name = "rustdoc_ng",
|
||||
vers = "0.1.0",
|
||||
uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6")];
|
||||
#[desc = "rustdoc, the Rust documentation extractor"];
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "bin"];
|
||||
|
||||
extern mod extra;
|
||||
extern mod rustdoc_ng;
|
||||
|
||||
use rustdoc_ng::*;
|
||||
use std::cell::Cell;
|
||||
|
||||
use extra::serialize::Encodable;
|
||||
|
||||
fn main() {
|
||||
use extra::getopts::*;
|
||||
use extra::getopts::groups::*;
|
||||
|
||||
let args = std::os::args();
|
||||
let opts = ~[
|
||||
optmulti("L", "library-path", "directory to add to crate search path", "DIR"),
|
||||
optmulti("p", "plugin", "plugin to load and run", "NAME"),
|
||||
optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
|
||||
// auxillary pass (defaults to hidden_strip
|
||||
optmulti("a", "pass", "auxillary pass to run", "NAME"),
|
||||
optflag("n", "no-defult-passes", "do not run the default passes"),
|
||||
optflag("h", "help", "show this help message"),
|
||||
];
|
||||
|
||||
let matches = getopts(args.tail(), opts).unwrap();
|
||||
|
||||
if opt_present(&matches, "h") || opt_present(&matches, "help") {
|
||||
println(usage(args[0], opts));
|
||||
return;
|
||||
}
|
||||
|
||||
let libs = Cell::new(opt_strs(&matches, "L").map(|s| Path(*s)));
|
||||
|
||||
let mut passes = if opt_present(&matches, "n") {
|
||||
~[]
|
||||
} else {
|
||||
~[~"collapse-docs", ~"clean-comments", ~"collapse-privacy" ]
|
||||
};
|
||||
|
||||
opt_strs(&matches, "a").map(|x| passes.push(x.clone()));
|
||||
|
||||
if matches.free.len() != 1 {
|
||||
println(usage(args[0], opts));
|
||||
return;
|
||||
}
|
||||
|
||||
let cr = Cell::new(Path(matches.free[0]));
|
||||
|
||||
let crate = std::task::try(|| {let cr = cr.take(); core::run_core(libs.take(), &cr)}).unwrap();
|
||||
|
||||
// { "schema": version, "crate": { parsed crate ... }, "plugins": { output of plugins ... }}
|
||||
let mut json = ~extra::treemap::TreeMap::new();
|
||||
json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
|
||||
|
||||
let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
|
||||
|
||||
for pass in passes.iter() {
|
||||
pm.add_plugin(match pass.as_slice() {
|
||||
"strip-hidden" => passes::strip_hidden,
|
||||
"clean-comments" => passes::clean_comments,
|
||||
"collapse-docs" => passes::collapse_docs,
|
||||
"collapse-privacy" => passes::collapse_privacy,
|
||||
s => { error!("unknown pass %s, skipping", s); passes::noop },
|
||||
})
|
||||
}
|
||||
|
||||
for pname in opt_strs(&matches, "p").move_iter() {
|
||||
pm.load_plugin(pname);
|
||||
}
|
||||
|
||||
let (crate, res) = pm.run_plugins(crate);
|
||||
let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
|
||||
|
||||
// FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
|
||||
// straight to the Rust JSON representation.
|
||||
let crate_json_str = do std::io::with_str_writer |w| {
|
||||
crate.encode(&mut extra::json::Encoder(w));
|
||||
};
|
||||
let crate_json = match extra::json::from_str(crate_json_str) {
|
||||
Ok(j) => j,
|
||||
Err(_) => fail!("Rust generated JSON is invalid??")
|
||||
};
|
||||
|
||||
json.insert(~"crate", crate_json);
|
||||
json.insert(~"plugins", extra::json::Object(plugins_json));
|
||||
|
||||
println(extra::json::Object(json).to_str());
|
||||
}
|
203
src/rustdoc_ng/passes.rs
Normal file
203
src/rustdoc_ng/passes.rs
Normal file
@ -0,0 +1,203 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std;
|
||||
use clean;
|
||||
use syntax::ast;
|
||||
use clean::Item;
|
||||
use plugins;
|
||||
use fold;
|
||||
use fold::DocFolder;
|
||||
|
||||
/// A sample pass showing the minimum required work for a plugin.
|
||||
pub fn noop(crate: clean::Crate) -> plugins::PluginResult {
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
/// Strip items marked `#[doc(hidden)]`
|
||||
pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct Stripper;
|
||||
impl fold::DocFolder for Stripper {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
for attr in i.attrs.iter() {
|
||||
match attr {
|
||||
&clean::List(~"doc", ref l) => {
|
||||
for innerattr in l.iter() {
|
||||
match innerattr {
|
||||
&clean::Word(ref s) if "hidden" == *s => {
|
||||
info!("found one in strip_hidden; removing");
|
||||
return None;
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut stripper = Stripper;
|
||||
let crate = stripper.fold_crate(crate);
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn clean_comments(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct CommentCleaner;
|
||||
impl fold::DocFolder for CommentCleaner {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
let mut i = i;
|
||||
let mut avec: ~[clean::Attribute] = ~[];
|
||||
for attr in i.attrs.iter() {
|
||||
match attr {
|
||||
&clean::NameValue(~"doc", ref s) => avec.push(
|
||||
clean::NameValue(~"doc", clean_comment_body(s.clone()))),
|
||||
x => avec.push(x.clone())
|
||||
}
|
||||
}
|
||||
i.attrs = avec;
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut cleaner = CommentCleaner;
|
||||
let crate = cleaner.fold_crate(crate);
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn collapse_privacy(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct PrivacyCollapser {
|
||||
stack: ~[clean::Visibility]
|
||||
}
|
||||
impl fold::DocFolder for PrivacyCollapser {
|
||||
fn fold_item(&mut self, mut i: Item) -> Option<Item> {
|
||||
if i.visibility.is_some() {
|
||||
if i.visibility == Some(ast::inherited) {
|
||||
i.visibility = Some(self.stack.last().clone());
|
||||
} else {
|
||||
self.stack.push(i.visibility.clone().unwrap());
|
||||
}
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut privacy = PrivacyCollapser { stack: ~[] };
|
||||
let crate = privacy.fold_crate(crate);
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn collapse_docs(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct Collapser;
|
||||
impl fold::DocFolder for Collapser {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
let mut docstr = ~"";
|
||||
let mut i = i;
|
||||
for attr in i.attrs.iter() {
|
||||
match *attr {
|
||||
clean::NameValue(~"doc", ref s) => {
|
||||
docstr.push_str(s.clone());
|
||||
docstr.push_char('\n');
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
let mut a: ~[clean::Attribute] = i.attrs.iter().filter(|&a| match a {
|
||||
&clean::NameValue(~"doc", _) => false,
|
||||
_ => true
|
||||
}).map(|x| x.clone()).collect();
|
||||
if "" != docstr {
|
||||
a.push(clean::NameValue(~"doc", docstr.trim().to_owned()));
|
||||
}
|
||||
i.attrs = a;
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut collapser = Collapser;
|
||||
let crate = collapser.fold_crate(crate);
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
//Utility
|
||||
enum CleanCommentStates {
|
||||
Collect,
|
||||
Strip,
|
||||
Stripped,
|
||||
}
|
||||
|
||||
/// Returns the index of the last character all strings have common in their
|
||||
/// prefix.
|
||||
fn longest_common_prefix(s: ~[~str]) -> uint {
|
||||
// find the longest common prefix
|
||||
|
||||
debug!("lcp: looking into %?", s);
|
||||
// index of the last character all the strings share
|
||||
let mut index = 0u;
|
||||
|
||||
if s.len() <= 1 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// whether one of the strings has been exhausted of characters yet
|
||||
let mut exhausted = false;
|
||||
|
||||
// character iterators for all the lines
|
||||
let mut lines = s.iter().filter(|x| x.len() != 0).map(|x| x.iter()).to_owned_vec();
|
||||
|
||||
'outer: loop {
|
||||
// because you can't label a while loop
|
||||
if exhausted == true {
|
||||
break;
|
||||
}
|
||||
debug!("lcp: index %u", index);
|
||||
let mut lines = lines.mut_iter();
|
||||
let ch = match lines.next().unwrap().next() {
|
||||
Some(c) => c,
|
||||
None => { exhausted = true; loop },
|
||||
};
|
||||
debug!("looking for char %c", ch);
|
||||
for line in lines {
|
||||
match line.next() {
|
||||
Some(c) => if c == ch { loop } else { exhausted = true; loop 'outer },
|
||||
None => { exhausted = true; loop 'outer }
|
||||
}
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
debug!("lcp: last index %u", index);
|
||||
index
|
||||
}
|
||||
|
||||
fn clean_comment_body(s: ~str) -> ~str {
|
||||
// FIXME #31: lots of copies in here.
|
||||
let lines = s.line_iter().to_owned_vec();
|
||||
match lines.len() {
|
||||
0 => return ~"",
|
||||
1 => return lines[0].slice_from(2).trim().to_owned(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let mut ol = std::vec::with_capacity(lines.len());
|
||||
for line in lines.clone().move_iter() {
|
||||
// replace meaningless things with a single newline
|
||||
match line {
|
||||
x if ["/**", "/*!", "///", "//!", "*/"].contains(&x.trim()) => ol.push(~""),
|
||||
x if x.trim() == "" => ol.push(~""),
|
||||
x => ol.push(x.to_owned())
|
||||
}
|
||||
}
|
||||
let li = longest_common_prefix(ol.clone());
|
||||
|
||||
let x = ol.iter()
|
||||
.filter(|x| { debug!("cleaning line: %s", **x); true })
|
||||
.map(|x| if x.len() == 0 { ~"" } else { x.slice_chars(li, x.char_len()).to_owned() })
|
||||
.to_owned_vec().connect("\n");
|
||||
x.trim().to_owned()
|
||||
}
|
90
src/rustdoc_ng/plugins.rs
Normal file
90
src/rustdoc_ng/plugins.rs
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use clean;
|
||||
|
||||
use extra;
|
||||
use dl = std::unstable::dynamic_lib;
|
||||
|
||||
pub type PluginJson = Option<(~str, extra::json::Json)>;
|
||||
pub type PluginResult = (clean::Crate, PluginJson);
|
||||
pub type plugin_callback = extern fn (clean::Crate) -> PluginResult;
|
||||
|
||||
/// Manages loading and running of plugins
|
||||
pub struct PluginManager {
|
||||
priv dylibs: ~[dl::DynamicLibrary],
|
||||
priv callbacks: ~[plugin_callback],
|
||||
/// The directory plugins will be loaded from
|
||||
prefix: Path,
|
||||
}
|
||||
|
||||
impl PluginManager {
|
||||
/// Create a new plugin manager
|
||||
pub fn new(prefix: Path) -> PluginManager {
|
||||
PluginManager {
|
||||
dylibs: ~[],
|
||||
callbacks: ~[],
|
||||
prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
/// Load a plugin with the given name.
|
||||
///
|
||||
/// Turns `name` into the proper dynamic library filename for the given
|
||||
/// platform. On windows, it turns into name.dll, on OS X, name.dylib, and
|
||||
/// elsewhere, libname.so.
|
||||
pub fn load_plugin(&mut self, name: ~str) {
|
||||
let x = self.prefix.push(libname(name));
|
||||
let lib_result = dl::DynamicLibrary::open(Some(&x));
|
||||
let lib = lib_result.unwrap();
|
||||
let plugin = unsafe { lib.symbol("rustdoc_plugin_entrypoint") }.unwrap();
|
||||
self.dylibs.push(lib);
|
||||
self.callbacks.push(plugin);
|
||||
}
|
||||
|
||||
/// Load a normal Rust function as a plugin.
|
||||
///
|
||||
/// This is to run passes over the cleaned crate. Plugins run this way
|
||||
/// correspond to the A-aux tag on Github.
|
||||
pub fn add_plugin(&mut self, plugin: plugin_callback) {
|
||||
self.callbacks.push(plugin);
|
||||
}
|
||||
/// Run all the loaded plugins over the crate, returning their results
|
||||
pub fn run_plugins(&self, crate: clean::Crate) -> (clean::Crate, ~[PluginJson]) {
|
||||
let mut out_json = ~[];
|
||||
let mut crate = crate;
|
||||
for &callback in self.callbacks.iter() {
|
||||
let (c, res) = callback(crate);
|
||||
crate = c;
|
||||
out_json.push(res);
|
||||
}
|
||||
(crate, out_json)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os="win32")]
|
||||
fn libname(mut n: ~str) -> ~str {
|
||||
n.push_str(".dll");
|
||||
n
|
||||
}
|
||||
|
||||
#[cfg(target_os="macos")]
|
||||
fn libname(mut n: ~str) -> ~str {
|
||||
n.push_str(".dylib");
|
||||
n
|
||||
}
|
||||
|
||||
#[cfg(not(target_os="win32"), not(target_os="macos"))]
|
||||
fn libname(n: ~str) -> ~str {
|
||||
let mut i = ~"lib";
|
||||
i.push_str(n);
|
||||
i.push_str(".so");
|
||||
i
|
||||
}
|
183
src/rustdoc_ng/visit_ast.rs
Normal file
183
src/rustdoc_ng/visit_ast.rs
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Rust AST Visitor. Extracts useful information and massages it into a form
|
||||
//! usable for clean
|
||||
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::{ast, ast_map};
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use doctree::*;
|
||||
use std::local_data;
|
||||
|
||||
pub struct RustdocVisitor {
|
||||
module: Module,
|
||||
attrs: ~[ast::Attribute],
|
||||
}
|
||||
|
||||
impl RustdocVisitor {
|
||||
pub fn new() -> RustdocVisitor {
|
||||
RustdocVisitor {
|
||||
module: Module::new(None),
|
||||
attrs: ~[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustdocVisitor {
|
||||
pub fn visit(@mut self, crate: &ast::Crate) {
|
||||
self.attrs = crate.attrs.clone();
|
||||
fn visit_struct_def(item: &ast::item, sd: @ast::struct_def, generics:
|
||||
&ast::Generics) -> Struct {
|
||||
debug!("Visiting struct");
|
||||
let struct_type = struct_type_from_def(sd);
|
||||
Struct {
|
||||
id: item.id,
|
||||
struct_type: struct_type,
|
||||
name: item.ident,
|
||||
vis: item.vis,
|
||||
attrs: item.attrs.clone(),
|
||||
generics: generics.clone(),
|
||||
fields: sd.fields.iter().map(|x| (*x).clone()).to_owned_vec(),
|
||||
where: item.span
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_enum_def(it: &ast::item, def: &ast::enum_def, params: &ast::Generics) -> Enum {
|
||||
debug!("Visiting enum");
|
||||
let mut vars: ~[Variant] = ~[];
|
||||
for x in def.variants.iter() {
|
||||
vars.push(Variant {
|
||||
name: x.node.name,
|
||||
attrs: x.node.attrs.clone(),
|
||||
vis: x.node.vis,
|
||||
id: x.node.id,
|
||||
kind: x.node.kind.clone(),
|
||||
where: x.span,
|
||||
});
|
||||
}
|
||||
Enum {
|
||||
name: it.ident,
|
||||
variants: vars,
|
||||
vis: it.vis,
|
||||
generics: params.clone(),
|
||||
attrs: it.attrs.clone(),
|
||||
id: it.id,
|
||||
where: it.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(item: &ast::item, fd: &ast::fn_decl, _purity: &ast::purity,
|
||||
_abi: &AbiSet, gen: &ast::Generics) -> Function {
|
||||
debug!("Visiting fn");
|
||||
Function {
|
||||
id: item.id,
|
||||
vis: item.vis,
|
||||
attrs: item.attrs.clone(),
|
||||
decl: fd.clone(),
|
||||
name: item.ident,
|
||||
where: item.span,
|
||||
generics: gen.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mod_contents(span: Span, attrs: ~[ast::Attribute], vis:
|
||||
ast::visibility, id: ast::NodeId, m: &ast::_mod) -> Module {
|
||||
let am = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.items;
|
||||
let name = match am.find(&id) {
|
||||
Some(m) => match m {
|
||||
&ast_map::node_item(ref it, _) => Some(it.ident),
|
||||
_ => fail!("mod id mapped to non-item in the ast map")
|
||||
},
|
||||
None => None
|
||||
};
|
||||
let mut om = Module::new(name);
|
||||
om.view_items = m.view_items.clone();
|
||||
om.where = span;
|
||||
om.attrs = attrs;
|
||||
om.vis = vis;
|
||||
om.id = id;
|
||||
for i in m.items.iter() {
|
||||
visit_item(*i, &mut om);
|
||||
}
|
||||
om
|
||||
}
|
||||
|
||||
fn visit_item(item: &ast::item, om: &mut Module) {
|
||||
debug!("Visiting item %?", item);
|
||||
match item.node {
|
||||
ast::item_mod(ref m) => {
|
||||
om.mods.push(visit_mod_contents(item.span, item.attrs.clone(),
|
||||
item.vis, item.id, m));
|
||||
},
|
||||
ast::item_enum(ref ed, ref gen) => om.enums.push(visit_enum_def(item, ed, gen)),
|
||||
ast::item_struct(sd, ref gen) => om.structs.push(visit_struct_def(item, sd, gen)),
|
||||
ast::item_fn(ref fd, ref pur, ref abi, ref gen, _) =>
|
||||
om.fns.push(visit_fn(item, fd, pur, abi, gen)),
|
||||
ast::item_ty(ref ty, ref gen) => {
|
||||
let t = Typedef {
|
||||
ty: ty.clone(),
|
||||
gen: gen.clone(),
|
||||
name: item.ident,
|
||||
id: item.id,
|
||||
attrs: item.attrs.clone(),
|
||||
where: item.span,
|
||||
vis: item.vis,
|
||||
};
|
||||
om.typedefs.push(t);
|
||||
},
|
||||
ast::item_static(ref ty, ref mut_, ref exp) => {
|
||||
let s = Static {
|
||||
type_: ty.clone(),
|
||||
mutability: mut_.clone(),
|
||||
expr: exp.clone(),
|
||||
id: item.id,
|
||||
name: item.ident,
|
||||
attrs: item.attrs.clone(),
|
||||
where: item.span,
|
||||
vis: item.vis,
|
||||
};
|
||||
om.statics.push(s);
|
||||
},
|
||||
ast::item_trait(ref gen, ref tr, ref met) => {
|
||||
let t = Trait {
|
||||
name: item.ident,
|
||||
methods: met.clone(),
|
||||
generics: gen.clone(),
|
||||
parents: tr.clone(),
|
||||
id: item.id,
|
||||
attrs: item.attrs.clone(),
|
||||
where: item.span,
|
||||
vis: item.vis,
|
||||
};
|
||||
om.traits.push(t);
|
||||
},
|
||||
ast::item_impl(ref gen, ref tr, ref ty, ref meths) => {
|
||||
let i = Impl {
|
||||
generics: gen.clone(),
|
||||
trait_: tr.clone(),
|
||||
for_: ty.clone(),
|
||||
methods: meths.clone(),
|
||||
attrs: item.attrs.clone(),
|
||||
id: item.id,
|
||||
where: item.span,
|
||||
vis: item.vis,
|
||||
};
|
||||
om.impls.push(i);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
self.module = visit_mod_contents(crate.span, crate.attrs.clone(),
|
||||
ast::public, ast::CRATE_NODE_ID, &crate.module);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user