rust/src/librustdoc/clean.rs

1121 lines
30 KiB
Rust
Raw Normal View History

// 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.
2013-08-15 16:28:54 -04:00
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.
use its = syntax::parse::token::ident_to_str;
use syntax;
use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttributeMethods;
2013-08-15 16:28:54 -04:00
use std;
use doctree;
use visit_ast;
use std::local_data;
pub trait Clean<T> {
fn clean(&self) -> T;
}
impl<T: Clean<U>, U> Clean<~[U]> for ~[T] {
fn clean(&self) -> ~[U] {
self.iter().map(|x| x.clean()).collect()
}
}
impl<T: Clean<U>, U> Clean<U> for @T {
fn clean(&self) -> U {
(**self).clean()
}
}
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
fn clean(&self) -> Option<U> {
match self {
&None => None,
&Some(ref v) => Some(v.clean())
}
}
}
impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
fn clean(&self) -> ~[U] {
match self {
&syntax::opt_vec::Empty => ~[],
&syntax::opt_vec::Vec(ref v) => v.clean()
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Crate {
name: ~str,
module: Option<Item>,
}
impl Clean<Crate> for visit_ast::RustdocVisitor {
fn clean(&self) -> Crate {
use syntax::attr::{find_linkage_metas, last_meta_item_value_str_by_name};
let maybe_meta = last_meta_item_value_str_by_name(find_linkage_metas(self.attrs), "name");
Crate {
name: match maybe_meta {
Some(x) => x.to_owned(),
None => fail!("rustdoc_ng requires a #[link(name=\"foo\")] crate attribute"),
},
module: Some(self.module.clean()),
}
}
}
/// Anything with a source location and set of attributes and, optionally, a
/// name. That is, anything that can be documented. This doesn't correspond
/// directly to the AST's concept of an item; it's a strict superset.
#[deriving(Clone, Encodable, Decodable)]
pub struct Item {
/// Stringified span
source: ~str,
/// Not everything has a name. E.g., impls
name: Option<~str>,
attrs: ~[Attribute],
inner: ItemEnum,
visibility: Option<Visibility>,
id: ast::NodeId,
}
impl Item {
/// Finds the `doc` attribute as a List and returns the list of attributes
/// nested inside.
pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
for attr in self.attrs.iter() {
match *attr {
List(~"doc", ref list) => { return Some(list.as_slice()); }
_ => {}
}
}
return None;
}
/// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found.
pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
for attr in self.attrs.iter() {
match *attr {
NameValue(~"doc", ref v) => { return Some(v.as_slice()); }
_ => {}
}
}
return None;
}
pub fn is_mod(&self) -> bool {
match self.inner { ModuleItem(*) => true, _ => false }
}
pub fn is_trait(&self) -> bool {
match self.inner { TraitItem(*) => true, _ => false }
}
pub fn is_struct(&self) -> bool {
match self.inner { StructItem(*) => true, _ => false }
}
pub fn is_enum(&self) -> bool {
match self.inner { EnumItem(*) => true, _ => false }
}
pub fn is_fn(&self) -> bool {
match self.inner { FunctionItem(*) => true, _ => false }
}
}
2013-08-15 16:28:54 -04:00
#[deriving(Clone, Encodable, Decodable)]
pub enum ItemEnum {
StructItem(Struct),
EnumItem(Enum),
FunctionItem(Function),
ModuleItem(Module),
TypedefItem(Typedef),
StaticItem(Static),
TraitItem(Trait),
ImplItem(Impl),
ViewItemItem(ViewItem),
TyMethodItem(TyMethod),
MethodItem(Method),
StructFieldItem(StructField),
VariantItem(Variant),
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Module {
items: ~[Item],
}
impl Clean<Item> for doctree::Module {
fn clean(&self) -> Item {
let name = if self.name.is_some() {
self.name.unwrap().clean()
} else {
~""
};
Item {
name: Some(name),
attrs: self.attrs.clean(),
source: self.where.clean(),
visibility: self.vis.clean(),
id: self.id,
inner: ModuleItem(Module {
items: std::vec::concat(&[self.structs.clean(),
self.enums.clean(), self.fns.clean(),
self.mods.clean(), self.typedefs.clean(),
self.statics.clean(), self.traits.clean(),
self.impls.clean(), self.view_items.clean()])
})
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum Attribute {
Word(~str),
List(~str, ~[Attribute]),
NameValue(~str, ~str)
}
impl Clean<Attribute> for ast::MetaItem {
fn clean(&self) -> Attribute {
match self.node {
ast::MetaWord(s) => Word(s.to_owned()),
ast::MetaList(ref s, ref l) => List(s.to_owned(), l.clean()),
ast::MetaNameValue(s, ref v) => NameValue(s.to_owned(), lit_to_str(v))
}
}
}
impl Clean<Attribute> for ast::Attribute {
fn clean(&self) -> Attribute {
self.desugar_doc().node.value.clean()
2013-08-15 16:28:54 -04:00
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct TyParam {
name: ~str,
id: ast::NodeId,
bounds: ~[TyParamBound]
}
impl Clean<TyParam> for ast::TyParam {
fn clean(&self) -> TyParam {
TyParam {
name: self.ident.clean(),
id: self.id,
bounds: self.bounds.clean(),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum TyParamBound {
RegionBound,
TraitBound(Type)
}
impl Clean<TyParamBound> for ast::TyParamBound {
fn clean(&self) -> TyParamBound {
match *self {
ast::RegionTyParamBound => RegionBound,
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Lifetime(~str);
impl Clean<Lifetime> for ast::Lifetime {
fn clean(&self) -> Lifetime {
Lifetime(self.ident.clean())
}
}
// maybe use a Generic enum and use ~[Generic]?
#[deriving(Clone, Encodable, Decodable)]
pub struct Generics {
lifetimes: ~[Lifetime],
type_params: ~[TyParam]
}
impl Generics {
fn new() -> Generics {
Generics {
lifetimes: ~[],
type_params: ~[]
}
}
}
impl Clean<Generics> for ast::Generics {
fn clean(&self) -> Generics {
Generics {
lifetimes: self.lifetimes.clean(),
type_params: self.ty_params.clean(),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Method {
generics: Generics,
self_: SelfTy,
purity: ast::purity,
decl: FnDecl,
}
impl Clean<Item> for ast::method {
fn clean(&self) -> Item {
Item {
name: Some(self.ident.clean()),
attrs: self.attrs.clean(),
source: self.span.clean(),
id: self.self_id.clone(),
visibility: self.vis.clean(),
2013-08-15 16:28:54 -04:00
inner: MethodItem(Method {
generics: self.generics.clean(),
self_: self.explicit_self.clean(),
purity: self.purity.clone(),
decl: self.decl.clean(),
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct TyMethod {
purity: ast::purity,
decl: FnDecl,
generics: Generics,
self_: SelfTy,
}
impl Clean<Item> for ast::TypeMethod {
fn clean(&self) -> Item {
Item {
name: Some(self.ident.clean()),
attrs: self.attrs.clean(),
source: self.span.clean(),
id: self.id,
visibility: None,
inner: TyMethodItem(TyMethod {
purity: self.purity.clone(),
decl: self.decl.clean(),
self_: self.explicit_self.clean(),
generics: self.generics.clean(),
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum SelfTy {
SelfStatic,
SelfValue,
SelfBorrowed(Option<Lifetime>, Mutability),
SelfManaged(Mutability),
SelfOwned,
}
impl Clean<SelfTy> for ast::explicit_self {
fn clean(&self) -> SelfTy {
match self.node {
ast::sty_static => SelfStatic,
ast::sty_value => SelfValue,
ast::sty_uniq => SelfOwned,
ast::sty_region(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
ast::sty_box(mt) => SelfManaged(mt.clean()),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Function {
decl: FnDecl,
generics: Generics,
purity: ast::purity,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Function {
fn clean(&self) -> Item {
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
visibility: self.vis.clean(),
id: self.id,
inner: FunctionItem(Function {
decl: self.decl.clean(),
generics: self.generics.clean(),
purity: self.purity,
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct ClosureDecl {
sigil: ast::Sigil,
region: Option<Lifetime>,
lifetimes: ~[Lifetime],
decl: FnDecl,
onceness: ast::Onceness,
purity: ast::purity,
bounds: ~[TyParamBound]
}
impl Clean<ClosureDecl> for ast::TyClosure {
fn clean(&self) -> ClosureDecl {
ClosureDecl {
sigil: self.sigil,
region: self.region.clean(),
lifetimes: self.lifetimes.clean(),
decl: self.decl.clean(),
onceness: self.onceness,
purity: self.purity,
bounds: match self.bounds {
Some(ref x) => x.clean(),
None => ~[]
},
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct FnDecl {
inputs: ~[Argument],
output: Type,
cf: RetStyle,
attrs: ~[Attribute]
}
impl Clean<FnDecl> for ast::fn_decl {
fn clean(&self) -> FnDecl {
FnDecl {
inputs: self.inputs.iter().map(|x| x.clean()).collect(),
output: (self.output.clean()),
cf: self.cf.clean(),
attrs: ~[]
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Argument {
type_: Type,
name: ~str,
id: ast::NodeId
}
impl Clean<Argument> for ast::arg {
fn clean(&self) -> Argument {
Argument {
name: name_from_pat(self.pat),
type_: (self.ty.clean()),
id: self.id
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum RetStyle {
NoReturn,
Return
}
impl Clean<RetStyle> for ast::ret_style {
fn clean(&self) -> RetStyle {
match *self {
ast::return_val => Return,
ast::noreturn => NoReturn
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Trait {
methods: ~[TraitMethod],
generics: Generics,
parents: ~[Type],
}
impl Clean<Item> for doctree::Trait {
fn clean(&self) -> Item {
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
visibility: self.vis.clean(),
inner: TraitItem(Trait {
methods: self.methods.clean(),
generics: self.generics.clean(),
parents: self.parents.clean(),
}),
}
}
}
impl Clean<Type> for ast::trait_ref {
fn clean(&self) -> Type {
resolve_type(self.path.clean(), None, self.ref_id)
2013-08-15 16:28:54 -04:00
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum TraitMethod {
Required(Item),
Provided(Item),
}
impl TraitMethod {
pub fn is_req(&self) -> bool {
2013-08-15 16:28:54 -04:00
match self {
&Required(*) => true,
_ => false,
}
}
pub fn is_def(&self) -> bool {
2013-08-15 16:28:54 -04:00
match self {
&Provided(*) => true,
_ => false,
}
}
pub fn item<'a>(&'a self) -> &'a Item {
match *self {
Required(ref item) => item,
Provided(ref item) => item,
}
}
2013-08-15 16:28:54 -04:00
}
impl Clean<TraitMethod> for ast::trait_method {
fn clean(&self) -> TraitMethod {
match self {
&ast::required(ref t) => Required(t.clean()),
&ast::provided(ref t) => Provided(t.clean()),
}
}
}
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
/// it does not preserve mutability or boxes.
#[deriving(Clone, Encodable, Decodable)]
pub enum Type {
/// structs/enums/traits (anything that'd be an ast::ty_path)
ResolvedPath { path: Path, typarams: Option<~[TyParamBound]>, id: ast::NodeId },
/// Reference to an item in an external crate (fully qualified path)
External(~str, ~str),
// I have no idea how to usefully use this.
TyParamBinder(ast::NodeId),
/// For parameterized types, so the consumer of the JSON don't go looking
/// for types which don't exist anywhere.
Generic(ast::NodeId),
/// For references to self
Self(ast::NodeId),
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
Primitive(ast::prim_ty),
Closure(~ClosureDecl),
/// extern "ABI" fn
BareFunction(~BareFunctionDecl),
Tuple(~[Type]),
Vector(~Type),
FixedVector(~Type, ~str),
String,
Bool,
/// aka ty_nil
Unit,
/// aka ty_bot
Bottom,
Unique(~Type),
Managed(Mutability, ~Type),
RawPointer(Mutability, ~Type),
BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: ~Type},
// region, raw, other boxes, mutable
}
impl Clean<Type> for ast::Ty {
fn clean(&self) -> Type {
use syntax::ast::*;
debug!("cleaning type `%?`", self);
let codemap = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess.codemap;
debug!("span corresponds to `%s`", codemap.span_to_str(self.span));
match self.node {
2013-08-15 16:28:54 -04:00
ty_nil => Unit,
ty_ptr(ref m) => RawPointer(m.mutbl.clean(), ~m.ty.clean()),
ty_rptr(ref l, ref m) =>
2013-08-15 16:28:54 -04:00
BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
type_: ~m.ty.clean()},
ty_box(ref m) => Managed(m.mutbl.clean(), ~m.ty.clean()),
ty_uniq(ref m) => Unique(~m.ty.clean()),
ty_vec(ref m) => Vector(~m.ty.clean()),
ty_fixed_length_vec(ref m, ref e) => FixedVector(~m.ty.clean(),
2013-08-15 16:28:54 -04:00
e.span.to_src()),
ty_tup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()),
ty_path(ref p, ref tpbs, id) =>
resolve_type(p.clean(), tpbs.clean(), id),
2013-08-15 16:28:54 -04:00
ty_closure(ref c) => Closure(~c.clean()),
ty_bare_fn(ref barefn) => BareFunction(~barefn.clean()),
ty_bot => Bottom,
ref x => fail!("Unimplemented type %?", x),
}
2013-08-15 16:28:54 -04:00
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct StructField {
type_: Type,
}
impl Clean<Item> for ast::struct_field {
fn clean(&self) -> Item {
let (name, vis) = match self.node.kind {
ast::named_field(id, vis) => (Some(id), Some(vis)),
_ => (None, None)
};
Item {
name: name.clean(),
attrs: self.node.attrs.clean(),
source: self.span.clean(),
visibility: vis,
id: self.node.id,
inner: StructFieldItem(StructField {
type_: self.node.ty.clean(),
}),
}
}
}
pub type Visibility = ast::visibility;
impl Clean<Option<Visibility>> for ast::visibility {
fn clean(&self) -> Option<Visibility> {
Some(*self)
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Struct {
struct_type: doctree::StructType,
generics: Generics,
fields: ~[Item],
}
impl Clean<Item> for doctree::Struct {
fn clean(&self) -> Item {
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
visibility: self.vis.clean(),
inner: StructItem(Struct {
struct_type: self.struct_type,
generics: self.generics.clean(),
fields: self.fields.clean(),
}),
}
}
}
/// This is a more limited form of the standard Struct, different in that it
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
#[deriving(Clone, Encodable, Decodable)]
pub struct VariantStruct {
struct_type: doctree::StructType,
fields: ~[Item],
}
impl Clean<VariantStruct> for syntax::ast::struct_def {
fn clean(&self) -> VariantStruct {
VariantStruct {
struct_type: doctree::struct_type_from_def(self),
fields: self.fields.clean(),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Enum {
variants: ~[Item],
generics: Generics,
}
impl Clean<Item> for doctree::Enum {
fn clean(&self) -> Item {
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
visibility: self.vis.clean(),
inner: EnumItem(Enum {
variants: self.variants.clean(),
generics: self.generics.clean(),
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Variant {
kind: VariantKind,
}
impl Clean<Item> for doctree::Variant {
fn clean(&self) -> Item {
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
visibility: self.vis.clean(),
id: self.id,
inner: VariantItem(Variant {
kind: self.kind.clean(),
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum VariantKind {
CLikeVariant,
TupleVariant(~[Type]),
StructVariant(VariantStruct),
}
impl Clean<VariantKind> for ast::variant_kind {
fn clean(&self) -> VariantKind {
match self {
&ast::tuple_variant_kind(ref args) => {
if args.len() == 0 {
CLikeVariant
} else {
TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
}
},
&ast::struct_variant_kind(ref sd) => StructVariant(sd.clean()),
}
}
}
2013-09-05 10:14:35 -04:00
impl Clean<~str> for syntax::codemap::Span {
2013-08-15 16:28:54 -04:00
fn clean(&self) -> ~str {
let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap;
cm.span_to_str(*self)
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Path {
global: bool,
segments: ~[PathSegment],
2013-08-15 16:28:54 -04:00
}
impl Clean<Path> for ast::Path {
fn clean(&self) -> Path {
Path {
global: self.global,
segments: self.segments.clean()
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct PathSegment {
name: ~str,
lifetime: Option<Lifetime>,
types: ~[Type],
}
impl Clean<PathSegment> for ast::PathSegment {
fn clean(&self) -> PathSegment {
PathSegment {
name: self.identifier.clean(),
lifetime: self.lifetime.clean(),
types: self.types.clean()
2013-08-15 16:28:54 -04:00
}
}
}
fn path_to_str(p: &ast::Path) -> ~str {
use syntax::parse::token::interner_get;
let mut s = ~"";
let mut first = true;
for i in p.segments.iter().map(|x| interner_get(x.identifier.name)) {
2013-08-15 16:28:54 -04:00
if !first || p.global {
s.push_str("::");
} else {
first = false;
}
s.push_str(i);
}
s
}
2013-09-05 10:14:35 -04:00
impl Clean<~str> for ast::Ident {
2013-08-15 16:28:54 -04:00
fn clean(&self) -> ~str {
its(self).to_owned()
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Typedef {
type_: Type,
generics: Generics,
}
impl Clean<Item> for doctree::Typedef {
fn clean(&self) -> Item {
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id.clone(),
visibility: self.vis.clean(),
inner: TypedefItem(Typedef {
type_: self.ty.clean(),
generics: self.gen.clean(),
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct BareFunctionDecl {
purity: ast::purity,
generics: Generics,
decl: FnDecl,
abi: ~str
}
impl Clean<BareFunctionDecl> for ast::TyBareFn {
fn clean(&self) -> BareFunctionDecl {
BareFunctionDecl {
purity: self.purity,
generics: Generics {
lifetimes: self.lifetimes.clean(),
type_params: ~[],
},
decl: self.decl.clean(),
abi: self.abis.to_str(),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Static {
type_: Type,
mutability: Mutability,
/// It's useful to have the value of a static documented, but I have no
/// desire to represent expressions (that'd basically be all of the AST,
/// which is huge!). So, have a string.
expr: ~str,
}
impl Clean<Item> for doctree::Static {
fn clean(&self) -> Item {
debug!("claning static %s: %?", self.name.clean(), self);
Item {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
visibility: self.vis.clean(),
inner: StaticItem(Static {
type_: self.type_.clean(),
mutability: self.mutability.clean(),
expr: self.expr.span.to_src(),
}),
}
}
}
#[deriving(ToStr, Clone, Encodable, Decodable)]
pub enum Mutability {
Mutable,
Immutable,
}
2013-09-05 10:14:35 -04:00
impl Clean<Mutability> for ast::Mutability {
2013-08-15 16:28:54 -04:00
fn clean(&self) -> Mutability {
match self {
2013-09-05 10:14:35 -04:00
&ast::MutMutable => Mutable,
&ast::MutImmutable => Immutable,
2013-08-15 16:28:54 -04:00
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Impl {
generics: Generics,
trait_: Option<Type>,
for_: Type,
methods: ~[Item],
}
impl Clean<Item> for doctree::Impl {
fn clean(&self) -> Item {
Item {
name: None,
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
visibility: self.vis.clean(),
inner: ImplItem(Impl {
generics: self.generics.clean(),
trait_: self.trait_.clean(),
for_: self.for_.clean(),
methods: self.methods.clean(),
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct ViewItem {
inner: ViewItemInner
}
impl Clean<Item> for ast::view_item {
fn clean(&self) -> Item {
Item {
name: None,
attrs: self.attrs.clean(),
source: self.span.clean(),
id: 0,
visibility: self.vis.clean(),
inner: ViewItemItem(ViewItem {
inner: self.node.clean()
}),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum ViewItemInner {
ExternMod(~str, Option<~str>, ~[Attribute], ast::NodeId),
Import(~[ViewPath])
}
impl Clean<ViewItemInner> for ast::view_item_ {
fn clean(&self) -> ViewItemInner {
match self {
&ast::view_item_extern_mod(ref i, ref p, ref mi, ref id) =>
ExternMod(i.clean(), p.map(|x| x.to_owned()), mi.clean(), *id),
&ast::view_item_use(ref vp) => Import(vp.clean())
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum ViewPath {
// use str = source;
SimpleImport(~str, ImportSource),
// use source::*;
GlobImport(ImportSource),
// use source::{a, b, c};
ImportList(ImportSource, ~[ViewListIdent]),
}
#[deriving(Clone, Encodable, Decodable)]
pub struct ImportSource {
path: Path,
did: Option<ast::DefId>,
2013-08-15 16:28:54 -04:00
}
impl Clean<ViewPath> for ast::view_path {
fn clean(&self) -> ViewPath {
match self.node {
ast::view_path_simple(ref i, ref p, id) =>
SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
ast::view_path_glob(ref p, id) =>
GlobImport(resolve_use_source(p.clean(), id)),
ast::view_path_list(ref p, ref pl, id) =>
ImportList(resolve_use_source(p.clean(), id), pl.clean()),
2013-08-15 16:28:54 -04:00
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct ViewListIdent {
name: ~str,
source: Option<ast::DefId>,
}
2013-08-15 16:28:54 -04:00
impl Clean<ViewListIdent> for ast::path_list_ident {
fn clean(&self) -> ViewListIdent {
ViewListIdent {
name: self.node.name.clean(),
source: resolve_def(self.node.id),
}
2013-08-15 16:28:54 -04:00
}
}
// Utilities
trait ToSource {
fn to_src(&self) -> ~str;
}
2013-09-05 10:14:35 -04:00
impl ToSource for syntax::codemap::Span {
2013-08-15 16:28:54 -04:00
fn to_src(&self) -> ~str {
debug!("converting span %s to snippet", self.clean());
let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap.clone();
let sn = match cm.span_to_snippet(*self) {
Some(x) => x,
None => ~""
};
debug!("got snippet %s", sn);
sn
}
}
fn lit_to_str(lit: &ast::lit) -> ~str {
match lit.node {
ast::lit_str(st) => st.to_owned(),
ast::lit_char(c) => ~"'" + std::char::from_u32(c).unwrap().to_str() + "'",
2013-08-15 16:28:54 -04:00
ast::lit_int(i, _t) => i.to_str(),
ast::lit_uint(u, _t) => u.to_str(),
ast::lit_int_unsuffixed(i) => i.to_str(),
ast::lit_float(f, _t) => f.to_str(),
ast::lit_float_unsuffixed(f) => f.to_str(),
ast::lit_bool(b) => b.to_str(),
ast::lit_nil => ~"",
}
}
2013-09-05 10:14:35 -04:00
fn name_from_pat(p: &ast::Pat) -> ~str {
2013-08-15 16:28:54 -04:00
use syntax::ast::*;
match p.node {
2013-09-05 10:14:35 -04:00
PatWild => ~"_",
PatIdent(_, ref p, _) => path_to_str(p),
PatEnum(ref p, _) => path_to_str(p),
PatStruct(*) => fail!("tried to get argument name from pat_struct, \
which is not allowed in function arguments"),
PatTup(*) => ~"(tuple arg NYI)",
PatBox(p) => name_from_pat(p),
PatUniq(p) => name_from_pat(p),
PatRegion(p) => name_from_pat(p),
PatLit(*) => fail!("tried to get argument name from pat_lit, \
which is not allowed in function arguments"),
PatRange(*) => fail!("tried to get argument name from pat_range, \
which is not allowed in function arguments"),
PatVec(*) => fail!("tried to get argument name from pat_vec, \
2013-08-15 16:28:54 -04:00
which is not allowed in function arguments")
}
}
fn remove_comment_tags(s: &str) -> ~str {
if s.starts_with("/") {
match s.slice(0,3) {
&"///" => return s.slice(3, s.len()).trim().to_owned(),
&"/**" | &"/*!" => return s.slice(3, s.len() - 2).trim().to_owned(),
_ => return s.trim().to_owned()
}
} else {
return s.to_owned();
}
}
/// Given a Type, resolve it using the def_map
fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
id: ast::NodeId) -> Type {
2013-08-15 16:28:54 -04:00
use syntax::ast::*;
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
debug!("searching for %? in defmap", id);
let d = match dm.find(&id) {
Some(k) => k,
None => {
let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
debug!("could not find %? in defmap (`%s`)", id,
syntax::ast_map::node_id_to_str(ctxt.tycx.items, id, ctxt.sess.intr()));
fail!("Unexpected failure: unresolved id not in defmap (this is a bug!)")
}
};
let def_id = match *d {
2013-09-05 10:14:35 -04:00
DefFn(i, _) => i,
DefSelf(i) | DefSelfTy(i) => return Self(i),
2013-09-05 10:14:35 -04:00
DefTy(i) => i,
DefTrait(i) => {
debug!("saw DefTrait in def_to_id");
2013-08-15 16:28:54 -04:00
i
},
2013-09-05 10:14:35 -04:00
DefPrimTy(p) => match p {
2013-08-15 16:28:54 -04:00
ty_str => return String,
ty_bool => return Bool,
_ => return Primitive(p)
},
2013-09-05 10:14:35 -04:00
DefTyParam(i, _) => return Generic(i.node),
DefStruct(i) => i,
DefTyParamBinder(i) => {
2013-08-15 16:28:54 -04:00
debug!("found a typaram_binder, what is it? %d", i);
return TyParamBinder(i);
},
x => fail!("resolved type maps to a weird def %?", x),
};
if def_id.crate != ast::CRATE_NODE_ID {
use rustc::metadata::decoder::*;
2013-08-15 16:28:54 -04:00
let sess = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess;
let cratedata = ::rustc::metadata::cstore::get_crate_data(sess.cstore, def_id.crate);
let doc = lookup_item(def_id.node, cratedata.data);
let path = syntax::ast_map::path_to_str_with_sep(item_path(doc), "::", sess.intr());
let ty = match def_like_to_def(item_to_def_like(doc, def_id, def_id.crate)) {
DefFn(*) => ~"fn",
DefTy(*) => ~"enum",
DefTrait(*) => ~"trait",
DefPrimTy(p) => match p {
ty_str => ~"str",
ty_bool => ~"bool",
ty_int(t) => match t.to_str() {
~"" => ~"i",
s => s
2013-08-15 16:28:54 -04:00
},
ty_uint(t) => t.to_str(),
ty_float(t) => t.to_str(),
ty_char => ~"char",
},
DefTyParam(*) => ~"generic",
DefStruct(*) => ~"struct",
DefTyParamBinder(*) => ~"typaram_binder",
x => fail!("resolved external maps to a weird def %?", x),
2013-08-15 16:28:54 -04:00
};
let cname = cratedata.name.to_owned();
2013-08-15 16:28:54 -04:00
External(cname + "::" + path, ty)
} else {
ResolvedPath {path: path.clone(), typarams: tpbs, id: def_id.node}
2013-08-15 16:28:54 -04:00
}
}
fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
ImportSource {
path: path,
did: resolve_def(id),
}
}
fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
dm.find(&id).map_move(|&d| ast_util::def_id_of_def(d))
}