From 52156cd51adbb798d1ddb6b036249a73fd6393c5 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 23 Dec 2015 10:26:53 -0500 Subject: [PATCH] feat(rustup): Sync with rust nightly (4ce1da --- syntex_syntax/src/ast.rs | 201 +- syntex_syntax/src/ast_util.rs | 163 +- syntex_syntax/src/attr.rs | 109 +- syntex_syntax/src/codemap.rs | 204 ++ syntex_syntax/src/config.rs | 18 +- .../src/{diagnostic.rs => errors/emitter.rs} | 678 +++---- syntex_syntax/src/errors/mod.rs | 338 ++++ syntex_syntax/src/ext/asm.rs | 239 --- syntex_syntax/src/ext/base.rs | 51 +- syntex_syntax/src/ext/build.rs | 40 +- syntex_syntax/src/ext/cfg.rs | 45 - syntex_syntax/src/ext/concat.rs | 66 - syntex_syntax/src/ext/concat_idents.rs | 73 - syntex_syntax/src/ext/deriving/bounds.rs | 49 - syntex_syntax/src/ext/deriving/clone.rs | 114 -- syntex_syntax/src/ext/deriving/cmp/eq.rs | 72 - syntex_syntax/src/ext/deriving/cmp/ord.rs | 135 -- .../src/ext/deriving/cmp/partial_eq.rs | 96 - .../src/ext/deriving/cmp/partial_ord.rs | 232 --- syntex_syntax/src/ext/deriving/debug.rs | 155 -- syntex_syntax/src/ext/deriving/decodable.rs | 223 --- syntex_syntax/src/ext/deriving/default.rs | 84 - syntex_syntax/src/ext/deriving/encodable.rs | 288 --- syntex_syntax/src/ext/deriving/generic/mod.rs | 1704 ----------------- syntex_syntax/src/ext/deriving/generic/ty.rs | 283 --- syntex_syntax/src/ext/deriving/hash.rs | 99 - syntex_syntax/src/ext/deriving/mod.rs | 201 -- syntex_syntax/src/ext/deriving/primitive.rs | 141 -- syntex_syntax/src/ext/env.rs | 106 - syntex_syntax/src/ext/expand.rs | 37 +- syntex_syntax/src/ext/format.rs | 715 ------- syntex_syntax/src/ext/log_syntax.rs | 34 - syntex_syntax/src/ext/quote.rs | 4 +- syntex_syntax/src/ext/trace_macros.rs | 43 - syntex_syntax/src/ext/tt/macro_parser.rs | 11 +- syntex_syntax/src/ext/tt/transcribe.rs | 14 +- syntex_syntax/src/feature_gate.rs | 61 +- syntex_syntax/src/fold.rs | 34 +- syntex_syntax/src/lib.rs | 20 +- syntex_syntax/src/owned_slice.rs | 101 +- syntex_syntax/src/parse/lexer/comments.rs | 4 +- syntex_syntax/src/parse/lexer/mod.rs | 89 +- syntex_syntax/src/parse/mod.rs | 34 +- syntex_syntax/src/parse/obsolete.rs | 3 +- syntex_syntax/src/parse/parser.rs | 82 +- syntex_syntax/src/parse/token.rs | 2 +- syntex_syntax/src/print/pprust.rs | 57 +- syntex_syntax/src/ptr.rs | 131 +- syntex_syntax/src/show_span.rs | 6 +- syntex_syntax/src/test.rs | 15 +- syntex_syntax/src/util/lev_distance.rs | 54 +- syntex_syntax/src/util/move_map.rs | 6 +- syntex_syntax/src/util/parser.rs | 16 +- syntex_syntax/src/util/small_vector.rs | 7 - syntex_syntax/src/visit.rs | 6 +- 55 files changed, 1509 insertions(+), 6284 deletions(-) rename syntex_syntax/src/{diagnostic.rs => errors/emitter.rs} (52%) create mode 100644 syntex_syntax/src/errors/mod.rs delete mode 100644 syntex_syntax/src/ext/asm.rs delete mode 100644 syntex_syntax/src/ext/cfg.rs delete mode 100644 syntex_syntax/src/ext/concat.rs delete mode 100644 syntex_syntax/src/ext/concat_idents.rs delete mode 100644 syntex_syntax/src/ext/deriving/bounds.rs delete mode 100644 syntex_syntax/src/ext/deriving/clone.rs delete mode 100644 syntex_syntax/src/ext/deriving/cmp/eq.rs delete mode 100644 syntex_syntax/src/ext/deriving/cmp/ord.rs delete mode 100644 syntex_syntax/src/ext/deriving/cmp/partial_eq.rs delete mode 100644 syntex_syntax/src/ext/deriving/cmp/partial_ord.rs delete mode 100644 syntex_syntax/src/ext/deriving/debug.rs delete mode 100644 syntex_syntax/src/ext/deriving/decodable.rs delete mode 100644 syntex_syntax/src/ext/deriving/default.rs delete mode 100644 syntex_syntax/src/ext/deriving/encodable.rs delete mode 100644 syntex_syntax/src/ext/deriving/generic/mod.rs delete mode 100644 syntex_syntax/src/ext/deriving/generic/ty.rs delete mode 100644 syntex_syntax/src/ext/deriving/hash.rs delete mode 100644 syntex_syntax/src/ext/deriving/mod.rs delete mode 100644 syntex_syntax/src/ext/deriving/primitive.rs delete mode 100644 syntex_syntax/src/ext/env.rs delete mode 100644 syntex_syntax/src/ext/format.rs delete mode 100644 syntex_syntax/src/ext/log_syntax.rs delete mode 100644 syntex_syntax/src/ext/trace_macros.rs diff --git a/syntex_syntax/src/ast.rs b/syntex_syntax/src/ast.rs index f11291fc..0ad655ce 100644 --- a/syntex_syntax/src/ast.rs +++ b/syntex_syntax/src/ast.rs @@ -10,7 +10,6 @@ // The Rust abstract syntax tree. -pub use self::BindingMode::*; pub use self::BinOp_::*; pub use self::BlockCheckMode::*; pub use self::CaptureClause::*; @@ -48,11 +47,9 @@ pub use self::PathParameters::*; use attr::ThinAttributes; use codemap::{Span, Spanned, DUMMY_SP, ExpnId}; use abi::Abi; -use ast_util; use ext::base; use ext::tt::macro_parser; -use owned_slice::OwnedSlice; -use parse::token::{InternedString, str_to_ident}; +use parse::token::InternedString; use parse::token; use parse::lexer; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; @@ -262,8 +259,8 @@ impl PathParameters { pub fn none() -> PathParameters { AngleBracketedParameters(AngleBracketedParameterData { lifetimes: Vec::new(), - types: OwnedSlice::empty(), - bindings: OwnedSlice::empty(), + types: P::empty(), + bindings: P::empty(), }) } @@ -335,10 +332,10 @@ pub struct AngleBracketedParameterData { /// The lifetime parameters for this path segment. pub lifetimes: Vec, /// The type parameters for this path segment, if present. - pub types: OwnedSlice>, + pub types: P<[P]>, /// Bindings (equality constraints) on associated types, if present. /// E.g., `Foo`. - pub bindings: OwnedSlice>, + pub bindings: P<[P]>, } impl AngleBracketedParameterData { @@ -395,7 +392,7 @@ pub enum TraitBoundModifier { Maybe, } -pub type TyParamBounds = OwnedSlice; +pub type TyParamBounds = P<[TyParamBound]>; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TyParam { @@ -411,7 +408,7 @@ pub struct TyParam { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Generics { pub lifetimes: Vec, - pub ty_params: OwnedSlice, + pub ty_params: P<[TyParam]>, pub where_clause: WhereClause, } @@ -427,6 +424,19 @@ impl Generics { } } +impl Default for Generics { + fn default() -> Generics { + Generics { + lifetimes: Vec::new(), + ty_params: P::empty(), + where_clause: WhereClause { + id: DUMMY_NODE_ID, + predicates: Vec::new(), + } + } + } +} + /// A `where` clause in a definition #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereClause { @@ -454,7 +464,7 @@ pub struct WhereBoundPredicate { /// The type being bounded pub bounded_ty: P, /// Trait and lifetime bounds (`Clone+Send+'static`) - pub bounds: OwnedSlice, + pub bounds: TyParamBounds, } /// A lifetime predicate, e.g. `'a: 'b+'c` @@ -563,8 +573,8 @@ pub struct FieldPat { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum BindingMode { - BindByRef(Mutability), - BindByValue(Mutability), + ByRef(Mutability), + ByValue(Mutability), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -657,6 +667,57 @@ pub enum BinOp_ { BiGt, } +impl BinOp_ { + pub fn to_string(&self) -> &'static str { + match *self { + BiAdd => "+", + BiSub => "-", + BiMul => "*", + BiDiv => "/", + BiRem => "%", + BiAnd => "&&", + BiOr => "||", + BiBitXor => "^", + BiBitAnd => "&", + BiBitOr => "|", + BiShl => "<<", + BiShr => ">>", + BiEq => "==", + BiLt => "<", + BiLe => "<=", + BiNe => "!=", + BiGe => ">=", + BiGt => ">" + } + } + pub fn lazy(&self) -> bool { + match *self { + BiAnd | BiOr => true, + _ => false + } + } + + pub fn is_shift(&self) -> bool { + match *self { + BiShl | BiShr => true, + _ => false + } + } + pub fn is_comparison(&self) -> bool { + match *self { + BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => + true, + BiAnd | BiOr | BiAdd | BiSub | BiMul | BiDiv | BiRem | + BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => + false, + } + } + /// Returns `true` if the binary operator takes its arguments by value + pub fn is_by_value(&self) -> bool { + !BinOp_::is_comparison(self) + } +} + pub type BinOp = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -669,13 +730,31 @@ pub enum UnOp { UnNeg } +impl UnOp { + /// Returns `true` if the unary operator takes its argument by value + pub fn is_by_value(u: UnOp) -> bool { + match u { + UnNeg | UnNot => true, + _ => false, + } + } + + pub fn to_string(op: UnOp) -> &'static str { + match op { + UnDeref => "*", + UnNot => "!", + UnNeg => "-", + } + } +} + /// A statement pub type Stmt = Spanned; impl fmt::Debug for Stmt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "stmt({}: {})", - ast_util::stmt_id(self) + self.node.id() .map_or(Cow::Borrowed(""),|id|Cow::Owned(id.to_string())), pprust::stmt_to_string(self)) } @@ -697,6 +776,15 @@ pub enum Stmt_ { } impl Stmt_ { + pub fn id(&self) -> Option { + match *self { + StmtDecl(_, id) => Some(id), + StmtExpr(_, id) => Some(id), + StmtSemi(_, id) => Some(id), + StmtMac(..) => None, + } + } + pub fn attrs(&self) -> &[Attribute] { match *self { StmtDecl(ref d, _) => d.attrs(), @@ -853,6 +941,7 @@ pub enum Expr_ { ExprLit(P), /// A cast (`foo as f64`) ExprCast(P, P), + ExprType(P, P), /// An `if` block, with an optional else block /// /// `if expr { block } else { expr }` @@ -1226,6 +1315,16 @@ pub enum Lit_ { LitBool(bool), } +impl Lit_ { + /// Returns true if this literal is a string and false otherwise. + pub fn is_str(&self) -> bool { + match *self { + LitStr(..) => true, + _ => false, + } + } +} + // NB: If you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1301,11 +1400,37 @@ impl fmt::Debug for IntTy { impl fmt::Display for IntTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", ast_util::int_ty_to_string(*self)) + write!(f, "{}", self.ty_to_string()) } } impl IntTy { + pub fn ty_to_string(&self) -> &'static str { + match *self { + TyIs => "isize", + TyI8 => "i8", + TyI16 => "i16", + TyI32 => "i32", + TyI64 => "i64" + } + } + + pub fn val_to_string(&self, val: i64) -> String { + // cast to a u64 so we can correctly print INT64_MIN. All integral types + // are parsed as u64, so we wouldn't want to print an extra negative + // sign. + format!("{}{}", val as u64, self.ty_to_string()) + } + + pub fn ty_max(&self) -> u64 { + match *self { + TyI8 => 0x80, + TyI16 => 0x8000, + TyIs | TyI32 => 0x80000000, // actually ni about TyIs + TyI64 => 0x8000000000000000 + } + } + pub fn bit_width(&self) -> Option { Some(match *self { TyIs => return None, @@ -1327,6 +1452,29 @@ pub enum UintTy { } impl UintTy { + pub fn ty_to_string(&self) -> &'static str { + match *self { + TyUs => "usize", + TyU8 => "u8", + TyU16 => "u16", + TyU32 => "u32", + TyU64 => "u64" + } + } + + pub fn val_to_string(&self, val: u64) -> String { + format!("{}{}", val, self.ty_to_string()) + } + + pub fn ty_max(&self) -> u64 { + match *self { + TyU8 => 0xff, + TyU16 => 0xffff, + TyUs | TyU32 => 0xffffffff, // actually ni about TyUs + TyU64 => 0xffffffffffffffff + } + } + pub fn bit_width(&self) -> Option { Some(match *self { TyUs => return None, @@ -1346,7 +1494,7 @@ impl fmt::Debug for UintTy { impl fmt::Display for UintTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", ast_util::uint_ty_to_string(*self)) + write!(f, "{}", self.ty_to_string()) } } @@ -1364,11 +1512,18 @@ impl fmt::Debug for FloatTy { impl fmt::Display for FloatTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", ast_util::float_ty_to_string(*self)) + write!(f, "{}", self.ty_to_string()) } } impl FloatTy { + pub fn ty_to_string(&self) -> &'static str { + match *self { + TyF32 => "f32", + TyF64 => "f64", + } + } + pub fn bit_width(&self) -> usize { match *self { TyF32 => 32, @@ -1458,11 +1613,19 @@ pub enum AsmDialect { Intel, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct InlineAsmOutput { + pub constraint: InternedString, + pub expr: P, + pub is_rw: bool, + pub is_indirect: bool, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct InlineAsm { pub asm: InternedString, pub asm_str_style: StrStyle, - pub outputs: Vec<(InternedString, P, bool)>, + pub outputs: Vec, pub inputs: Vec<(InternedString, P)>, pub clobbers: Vec, pub volatile: bool, @@ -1491,7 +1654,7 @@ impl Arg { }), pat: P(Pat { id: DUMMY_NODE_ID, - node: PatIdent(BindByValue(mutability), path, None), + node: PatIdent(BindingMode::ByValue(mutability), path, None), span: span }), id: DUMMY_NODE_ID diff --git a/syntex_syntax/src/ast_util.rs b/syntex_syntax/src/ast_util.rs index 489c61b8..70561b1e 100644 --- a/syntex_syntax/src/ast_util.rs +++ b/syntex_syntax/src/ast_util.rs @@ -10,10 +10,8 @@ use ast::*; use ast; -use ast_util; use codemap; use codemap::Span; -use owned_slice::OwnedSlice; use parse::token; use print::pprust; use ptr::P; @@ -28,144 +26,10 @@ pub fn path_name_i(idents: &[Ident]) -> String { idents.iter().map(|i| i.to_string()).collect::>().join("::") } -pub fn stmt_id(s: &Stmt) -> Option { - match s.node { - StmtDecl(_, id) => Some(id), - StmtExpr(_, id) => Some(id), - StmtSemi(_, id) => Some(id), - StmtMac(..) => None, - } -} - -pub fn binop_to_string(op: BinOp_) -> &'static str { - match op { - BiAdd => "+", - BiSub => "-", - BiMul => "*", - BiDiv => "/", - BiRem => "%", - BiAnd => "&&", - BiOr => "||", - BiBitXor => "^", - BiBitAnd => "&", - BiBitOr => "|", - BiShl => "<<", - BiShr => ">>", - BiEq => "==", - BiLt => "<", - BiLe => "<=", - BiNe => "!=", - BiGe => ">=", - BiGt => ">" - } -} - -pub fn lazy_binop(b: BinOp_) -> bool { - match b { - BiAnd => true, - BiOr => true, - _ => false - } -} - -pub fn is_shift_binop(b: BinOp_) -> bool { - match b { - BiShl => true, - BiShr => true, - _ => false - } -} - -pub fn is_comparison_binop(b: BinOp_) -> bool { - match b { - BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => - true, - BiAnd | BiOr | BiAdd | BiSub | BiMul | BiDiv | BiRem | - BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => - false, - } -} - -/// Returns `true` if the binary operator takes its arguments by value -pub fn is_by_value_binop(b: BinOp_) -> bool { - !is_comparison_binop(b) -} - -/// Returns `true` if the unary operator takes its argument by value -pub fn is_by_value_unop(u: UnOp) -> bool { - match u { - UnNeg | UnNot => true, - _ => false, - } -} - -pub fn unop_to_string(op: UnOp) -> &'static str { - match op { - UnDeref => "*", - UnNot => "!", - UnNeg => "-", - } -} - pub fn is_path(e: P) -> bool { match e.node { ExprPath(..) => true, _ => false } } -pub fn int_ty_to_string(t: IntTy) -> &'static str { - match t { - TyIs => "isize", - TyI8 => "i8", - TyI16 => "i16", - TyI32 => "i32", - TyI64 => "i64" - } -} - -pub fn int_val_to_string(t: IntTy, val: i64) -> String { - // cast to a u64 so we can correctly print INT64_MIN. All integral types - // are parsed as u64, so we wouldn't want to print an extra negative - // sign. - format!("{}{}", val as u64, int_ty_to_string(t)) -} - -pub fn int_ty_max(t: IntTy) -> u64 { - match t { - TyI8 => 0x80, - TyI16 => 0x8000, - TyIs | TyI32 => 0x80000000, // actually ni about TyIs - TyI64 => 0x8000000000000000 - } -} - -pub fn uint_ty_to_string(t: UintTy) -> &'static str { - match t { - TyUs => "usize", - TyU8 => "u8", - TyU16 => "u16", - TyU32 => "u32", - TyU64 => "u64" - } -} - -pub fn uint_val_to_string(t: UintTy, val: u64) -> String { - format!("{}{}", val, uint_ty_to_string(t)) -} - -pub fn uint_ty_max(t: UintTy) -> u64 { - match t { - TyU8 => 0xff, - TyU16 => 0xffff, - TyUs | TyU32 => 0xffffffff, // actually ni about TyUs - TyU64 => 0xffffffffffffffff - } -} - -pub fn float_ty_to_string(t: FloatTy) -> &'static str { - match t { - TyF32 => "f32", - TyF64 => "f64", - } -} // convert a span and an identifier to the corresponding // 1-segment path @@ -178,8 +42,8 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { identifier: identifier, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: Vec::new(), - types: OwnedSlice::empty(), - bindings: OwnedSlice::empty(), + types: P::empty(), + bindings: P::empty(), }) } ), @@ -204,7 +68,7 @@ pub fn path_to_ident(path: &Path) -> Option { pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> P { P(Pat { id: id, - node: PatIdent(BindByValue(MutImmutable), codemap::Spanned{span:s, node:i}, None), + node: PatIdent(BindingMode::ByValue(MutImmutable), codemap::Spanned{span:s, node:i}, None), span: s }) } @@ -236,17 +100,6 @@ pub fn struct_field_visibility(field: ast::StructField) -> Visibility { } } -pub fn empty_generics() -> Generics { - Generics { - lifetimes: Vec::new(), - ty_params: OwnedSlice::empty(), - where_clause: WhereClause { - id: DUMMY_NODE_ID, - predicates: Vec::new(), - } - } -} - // ______________________________________________________________________ // Enumerating the IDs which appear in an AST @@ -351,7 +204,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { fn visit_stmt(&mut self, statement: &Stmt) { self.operation - .visit_id(ast_util::stmt_id(statement).expect("attempted to visit unexpanded stmt")); + .visit_id(statement.node.id().expect("attempted to visit unexpanded stmt")); visit::walk_stmt(self, statement) } @@ -519,14 +372,6 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo }) } -/// Returns true if this literal is a string and false otherwise. -pub fn lit_is_str(lit: &Lit) -> bool { - match lit.node { - LitStr(..) => true, - _ => false, - } -} - #[cfg(test)] mod tests { use ast::*; diff --git a/syntex_syntax/src/attr.rs b/syntex_syntax/src/attr.rs index e828d8ae..26662605 100644 --- a/syntex_syntax/src/attr.rs +++ b/syntex_syntax/src/attr.rs @@ -21,10 +21,10 @@ use ast::{Expr, Item, Local, Decl}; use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; use config::CfgDiag; -use diagnostic::SpanHandler; +use errors::Handler; use feature_gate::{GatedCfg, GatedCfgAttr}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use parse::token::{InternedString, intern_and_get_ident}; +use parse::token::InternedString; use parse::token; use ptr::P; @@ -299,14 +299,14 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { } /// Find the value of #[export_name=*] attribute and check its validity. -pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option { +pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option { attrs.iter().fold(None, |ia,attr| { if attr.check_name("export_name") { if let s@Some(_) = attr.value_str() { s } else { diag.span_err(attr.span, "export_name attribute has invalid format"); - diag.handler.help("use #[export_name=\"*\"]"); + diag.help("use #[export_name=\"*\"]"); None } } else { @@ -324,7 +324,7 @@ pub enum InlineAttr { } /// Determine what `#[inline]` attribute is present in `attrs`, if any. -pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr { +pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr { attrs.iter().fold(InlineAttr::None, |ia,attr| { match attr.node.value.node { MetaWord(ref n) if *n == "inline" => { @@ -398,7 +398,7 @@ pub fn cfg_matches(cfgs: &[P], pub struct Stability { pub level: StabilityLevel, pub feature: InternedString, - pub depr: Option, + pub rustc_depr: Option, } /// The available stability levels. @@ -410,24 +410,30 @@ pub enum StabilityLevel { } #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] -pub struct Deprecation { +pub struct RustcDeprecation { pub since: InternedString, pub reason: InternedString, } +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + impl StabilityLevel { pub fn is_unstable(&self) -> bool { if let Unstable {..} = *self { true } else { false }} pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }} } -fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, +fn find_stability_generic<'a, I>(diagnostic: &Handler, attrs_iter: I, item_sp: Span) -> Option where I: Iterator { let mut stab: Option = None; - let mut depr: Option = None; + let mut rustc_depr: Option = None; 'outer: for attr in attrs_iter { let tag = attr.name(); @@ -456,7 +462,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, match tag { "rustc_deprecated" => { - if depr.is_some() { + if rustc_depr.is_some() { diagnostic.span_err(item_sp, "multiple rustc_deprecated attributes"); break } @@ -477,7 +483,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, match (since, reason) { (Some(since), Some(reason)) => { - depr = Some(Deprecation { + rustc_depr = Some(RustcDeprecation { since: since, reason: reason, }) @@ -529,7 +535,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, } }, feature: feature, - depr: None, + rustc_depr: None, }) } (None, _, _) => { @@ -569,7 +575,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, since: since, }, feature: feature, - depr: None, + rustc_depr: None, }) } (None, _) => { @@ -591,12 +597,12 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, } // Merge the deprecation info into the stability info - if let Some(depr) = depr { + if let Some(rustc_depr) = rustc_depr { if let Some(ref mut stab) = stab { if let Unstable {reason: ref mut reason @ None, ..} = stab.level { - *reason = Some(depr.reason.clone()) + *reason = Some(rustc_depr.reason.clone()) } - stab.depr = Some(depr); + stab.rustc_depr = Some(rustc_depr); } else { diagnostic.span_err(item_sp, "rustc_deprecated attribute must be paired with \ either stable or unstable attribute"); @@ -606,13 +612,78 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, stab } +fn find_deprecation_generic<'a, I>(diagnostic: &Handler, + attrs_iter: I, + item_sp: Span) + -> Option + where I: Iterator +{ + let mut depr: Option = None; + + 'outer: for attr in attrs_iter { + if attr.name() != "deprecated" { + continue + } + + mark_used(attr); + + if depr.is_some() { + diagnostic.span_err(item_sp, "multiple deprecated attributes"); + break + } + + depr = if let Some(metas) = attr.meta_item_list() { + let get = |meta: &MetaItem, item: &mut Option| { + if item.is_some() { + diagnostic.span_err(meta.span, &format!("multiple '{}' items", + meta.name())); + return false + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + diagnostic.span_err(meta.span, "incorrect meta item"); + false + } + }; + + let mut since = None; + let mut note = None; + for meta in metas { + match &*meta.name() { + "since" => if !get(meta, &mut since) { continue 'outer }, + "note" => if !get(meta, &mut note) { continue 'outer }, + _ => { + diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", + meta.name())); + continue 'outer + } + } + } + + Some(Deprecation {since: since, note: note}) + } else { + Some(Deprecation{since: None, note: None}) + } + } + + depr +} + /// Find the first stability attribute. `None` if none exists. -pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute], +pub fn find_stability(diagnostic: &Handler, attrs: &[Attribute], item_sp: Span) -> Option { find_stability_generic(diagnostic, attrs.iter(), item_sp) } -pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P]) { +/// Find the deprecation attribute. `None` if none exists. +pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], + item_sp: Span) -> Option { + find_deprecation_generic(diagnostic, attrs.iter(), item_sp) +} + +pub fn require_unique_names(diagnostic: &Handler, metas: &[P]) { let mut set = HashSet::new(); for meta in metas { let name = meta.name(); @@ -631,7 +702,7 @@ pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P]) { /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use /// the same discriminant size that the corresponding C enum would or C /// structure layout, and `packed` to remove padding. -pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec { +pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec { let mut acc = Vec::new(); match attr.node.value.node { ast::MetaList(ref s, ref items) if *s == "repr" => { diff --git a/syntex_syntax/src/codemap.rs b/syntex_syntax/src/codemap.rs index db011265..18659cb2 100644 --- a/syntex_syntax/src/codemap.rs +++ b/syntex_syntax/src/codemap.rs @@ -807,6 +807,96 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } + // Returns true if two spans have the same callee + // (Assumes the same ExpnFormat implies same callee) + fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool { + let fmt_a = self + .with_expn_info(sp_a.expn_id, + |ei| ei.map(|ei| ei.callee.format.clone())); + + let fmt_b = self + .with_expn_info(sp_b.expn_id, + |ei| ei.map(|ei| ei.callee.format.clone())); + fmt_a == fmt_b + } + + /// Returns a formatted string showing the expansion chain of a span + /// + /// Spans are printed in the following format: + /// + /// filename:start_line:col: end_line:col + /// snippet + /// Callee: + /// Callee span + /// Callsite: + /// Callsite span + /// + /// Callees and callsites are printed recursively (if available, otherwise header + /// and span is omitted), expanding into their own callee/callsite spans. + /// Each layer of recursion has an increased indent, and snippets are truncated + /// to at most 50 characters. Finally, recursive calls to the same macro are squashed, + /// with '...' used to represent any number of recursive calls. + pub fn span_to_expanded_string(&self, sp: Span) -> String { + self.span_to_expanded_string_internal(sp, "") + } + + fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String { + let mut indent = indent.to_owned(); + let mut output = "".to_owned(); + let span_str = self.span_to_string(sp); + let mut span_snip = self.span_to_snippet(sp) + .unwrap_or("Snippet unavailable".to_owned()); + if span_snip.len() > 50 { + span_snip.truncate(50); + span_snip.push_str("..."); + } + output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip)); + + if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN { + return output; + } + + let mut callee = self.with_expn_info(sp.expn_id, + |ei| ei.and_then(|ei| ei.callee.span.clone())); + let mut callsite = self.with_expn_info(sp.expn_id, + |ei| ei.map(|ei| ei.call_site.clone())); + + indent.push_str(" "); + let mut is_recursive = false; + + while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) { + callee = self.with_expn_info(callee.unwrap().expn_id, + |ei| ei.and_then(|ei| ei.callee.span.clone())); + is_recursive = true; + } + if let Some(span) = callee { + output.push_str(&indent); + output.push_str("Callee:\n"); + if is_recursive { + output.push_str(&indent); + output.push_str("...\n"); + } + output.push_str(&(self.span_to_expanded_string_internal(span, &indent))); + } + + is_recursive = false; + while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) { + callsite = self.with_expn_info(callsite.unwrap().expn_id, + |ei| ei.map(|ei| ei.call_site.clone())); + is_recursive = true; + } + if let Some(span) = callsite { + output.push_str(&indent); + output.push_str("Callsite:\n"); + if is_recursive { + output.push_str(&indent); + output.push_str("...\n"); + } + output.push_str(&(self.span_to_expanded_string_internal(span, &indent))); + } + output + } + pub fn span_to_filename(&self, sp: Span) -> FileName { self.lookup_char_pos(sp.lo).file.name.to_string() } @@ -1274,4 +1364,118 @@ mod tests { assert_eq!(sstr, "blork.rs:2:1: 2:12"); } + + #[test] + fn t10() { + // Test span_to_expanded_string works in base case (no expansion) + let cm = init_code_map(); + let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; + let sstr = cm.span_to_expanded_string(span); + assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n"); + + let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION }; + let sstr = cm.span_to_expanded_string(span); + assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n"); + } + + #[test] + fn t11() { + // Test span_to_expanded_string works with expansion + use ast::Name; + let cm = init_code_map(); + let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; + let format = ExpnFormat::MacroBang(Name(0u32)); + let callee = NameAndSpan { format: format, + allow_internal_unstable: false, + span: None }; + + let info = ExpnInfo { call_site: root, callee: callee }; + let id = cm.record_expansion(info); + let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id }; + + let sstr = cm.span_to_expanded_string(sp); + assert_eq!(sstr, + "blork.rs:2:1: 2:12\n`second line`\n Callsite:\n \ + blork.rs:1:1: 1:12\n `first line.`\n"); + } + + fn init_expansion_chain(cm: &CodeMap) -> Span { + // Creates an expansion chain containing two recursive calls + // root -> expA -> expA -> expB -> expB -> end + use ast::Name; + + let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; + + let format_root = ExpnFormat::MacroBang(Name(0u32)); + let callee_root = NameAndSpan { format: format_root, + allow_internal_unstable: false, + span: Some(root) }; + + let info_a1 = ExpnInfo { call_site: root, callee: callee_root }; + let id_a1 = cm.record_expansion(info_a1); + let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 }; + + let format_a = ExpnFormat::MacroBang(Name(1u32)); + let callee_a = NameAndSpan { format: format_a, + allow_internal_unstable: false, + span: Some(span_a1) }; + + let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() }; + let id_a2 = cm.record_expansion(info_a2); + let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 }; + + let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a }; + let id_b1 = cm.record_expansion(info_b1); + let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 }; + + let format_b = ExpnFormat::MacroBang(Name(2u32)); + let callee_b = NameAndSpan { format: format_b, + allow_internal_unstable: false, + span: None }; + + let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() }; + let id_b2 = cm.record_expansion(info_b2); + let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 }; + + let info_end = ExpnInfo { call_site: span_b2, callee: callee_b }; + let id_end = cm.record_expansion(info_end); + Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } + } + + #[test] + fn t12() { + // Test span_to_expanded_string collapses recursive macros and handles + // recursive callsite and callee expansions + let cm = init_code_map(); + let end = init_expansion_chain(&cm); + let sstr = cm.span_to_expanded_string(end); + let res_str = +r"blork2.rs:2:1: 2:12 +`second line` + Callsite: + ... + blork2.rs:1:1: 1:12 + `first line.` + Callee: + blork.rs:2:1: 2:12 + `second line` + Callee: + blork.rs:1:1: 1:12 + `first line.` + Callsite: + blork.rs:1:1: 1:12 + `first line.` + Callsite: + ... + blork.rs:2:1: 2:12 + `second line` + Callee: + blork.rs:1:1: 1:12 + `first line.` + Callsite: + blork.rs:1:1: 1:12 + `first line.` +"; + assert_eq!(sstr, res_str); + } } diff --git a/syntex_syntax/src/config.rs b/syntex_syntax/src/config.rs index 1209c58f..64b16538 100644 --- a/syntex_syntax/src/config.rs +++ b/syntex_syntax/src/config.rs @@ -9,7 +9,7 @@ // except according to those terms. use attr::AttrMetaMethods; -use diagnostic::SpanHandler; +use errors::Handler; use feature_gate::GatedCfgAttr; use fold::Folder; use {ast, fold, attr}; @@ -23,12 +23,12 @@ use util::small_vector::SmallVector; /// configuration. struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { in_cfg: F, - diagnostic: &'a SpanHandler, + diagnostic: &'a Handler, } // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration -pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate, +pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, feature_gated_cfgs: &mut Vec) -> ast::Crate { @@ -83,7 +83,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } } -pub fn strip_items<'a, F>(diagnostic: &'a SpanHandler, +pub fn strip_items<'a, F>(diagnostic: &'a Handler, krate: ast::Crate, in_cfg: F) -> ast::Crate where F: FnMut(&[ast::Attribute]) -> bool, { @@ -291,7 +291,7 @@ struct CfgAttrFolder<'a, T> { } // Process `#[cfg_attr]`. -fn process_cfg_attr(diagnostic: &SpanHandler, krate: ast::Crate, +fn process_cfg_attr(diagnostic: &Handler, krate: ast::Crate, feature_gated_cfgs: &mut Vec) -> ast::Crate { let mut fld = CfgAttrFolder { diag: CfgDiagReal { @@ -463,17 +463,17 @@ impl<'v, 'a, 'b> visit::Visitor<'v> for StmtExprAttrFeatureVisitor<'a, 'b> { } pub trait CfgDiag { - fn emit_error(&mut self, f: F) where F: FnMut(&SpanHandler); + fn emit_error(&mut self, f: F) where F: FnMut(&Handler); fn flag_gated(&mut self, f: F) where F: FnMut(&mut Vec); } pub struct CfgDiagReal<'a, 'b> { - pub diag: &'a SpanHandler, + pub diag: &'a Handler, pub feature_gated_cfgs: &'b mut Vec, } impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> { - fn emit_error(&mut self, mut f: F) where F: FnMut(&SpanHandler) { + fn emit_error(&mut self, mut f: F) where F: FnMut(&Handler) { f(self.diag) } fn flag_gated(&mut self, mut f: F) where F: FnMut(&mut Vec) { @@ -486,7 +486,7 @@ struct CfgDiagSilent { } impl CfgDiag for CfgDiagSilent { - fn emit_error(&mut self, _: F) where F: FnMut(&SpanHandler) { + fn emit_error(&mut self, _: F) where F: FnMut(&Handler) { self.error = true; } fn flag_gated(&mut self, _: F) where F: FnMut(&mut Vec) {} diff --git a/syntex_syntax/src/diagnostic.rs b/syntex_syntax/src/errors/emitter.rs similarity index 52% rename from syntex_syntax/src/diagnostic.rs rename to syntex_syntax/src/errors/emitter.rs index b854a2f2..7fef85a8 100644 --- a/syntex_syntax/src/diagnostic.rs +++ b/syntex_syntax/src/errors/emitter.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,423 +8,156 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::Level::*; -pub use self::RenderSpan::*; -pub use self::ColorConfig::*; use self::Destination::*; use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}; use diagnostics; -use std::cell::{RefCell, Cell}; -use std::{cmp, error, fmt}; +use errors::{Level, RenderSpan}; +use errors::RenderSpan::*; +use errors::Level::*; + +use std::{cmp, fmt}; use std::io::prelude::*; use std::io; +use std::rc::Rc; use term; -/// maximum number of lines we will print for each error; arbitrary. -const MAX_LINES: usize = 6; -#[derive(Clone)] -pub enum RenderSpan { - /// A FullSpan renders with both with an initial line for the - /// message, prefixed by file:linenum, followed by a summary of - /// the source code covered by the span. - FullSpan(Span), - - /// Similar to a FullSpan, but the cited position is the end of - /// the span, instead of the start. Used, at least, for telling - /// compiletest/runtest to look at the last line of the span - /// (since `end_highlight_lines` displays an arrow to the end - /// of the span). - EndSpan(Span), - - /// A suggestion renders with both with an initial line for the - /// message, prefixed by file:linenum, followed by a summary - /// of hypothetical source code, where the `String` is spliced - /// into the lines in place of the code covered by the span. - Suggestion(Span, String), - - /// A FileLine renders with just a line for the message prefixed - /// by file:linenum. - FileLine(Span), +pub trait Emitter { + fn emit(&mut self, span: Option, msg: &str, code: Option<&str>, lvl: Level); + fn custom_emit(&mut self, sp: RenderSpan, msg: &str, lvl: Level); } -impl RenderSpan { - fn span(&self) -> Span { - match *self { - FullSpan(s) | - Suggestion(s, _) | - EndSpan(s) | - FileLine(s) => - s - } - } -} +/// maximum number of lines we will print for each error; arbitrary. +const MAX_LINES: usize = 6; #[derive(Clone, Copy)] pub enum ColorConfig { Auto, Always, - Never + Never, } -pub trait Emitter { - fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, code: Option<&str>, lvl: Level); - fn custom_emit(&mut self, cm: &codemap::CodeMap, - sp: RenderSpan, msg: &str, lvl: Level); -} - -/// Used as a return value to signify a fatal error occurred. (It is also -/// used as the argument to panic at the moment, but that will eventually -/// not be true.) -#[derive(Copy, Clone, Debug)] -#[must_use] -pub struct FatalError; - -impl fmt::Display for FatalError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "parser fatal error") +impl ColorConfig { + fn use_color(&self) -> bool { + match *self { + ColorConfig::Always => true, + ColorConfig::Never => false, + ColorConfig::Auto => stderr_isatty(), + } } } -impl error::Error for FatalError { - fn description(&self) -> &str { - "The parser has encountered a fatal error" - } +// A basic emitter for when we don't have access to a codemap or registry. Used +// for reporting very early errors, etc. +pub struct BasicEmitter { + dst: Destination, } -/// Signifies that the compiler died with an explicit call to `.bug` -/// or `.span_bug` rather than a failed assertion, etc. -#[derive(Copy, Clone, Debug)] -pub struct ExplicitBug; - -impl fmt::Display for ExplicitBug { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "parser internal bug") - } -} +impl Emitter for BasicEmitter { + fn emit(&mut self, + sp: Option, + msg: &str, + code: Option<&str>, + lvl: Level) { + assert!(sp.is_none(), "BasicEmitter can't handle spans"); + if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { + panic!("failed to print diagnostics: {:?}", e); + } -impl error::Error for ExplicitBug { - fn description(&self) -> &str { - "The parser has encountered an internal bug" } -} -/// A span-handler is like a handler but also -/// accepts span information for source-location -/// reporting. -pub struct SpanHandler { - pub handler: Handler, - pub cm: codemap::CodeMap, -} - -impl SpanHandler { - pub fn new(handler: Handler, cm: codemap::CodeMap) -> SpanHandler { - SpanHandler { - handler: handler, - cm: cm, - } + fn custom_emit(&mut self, _: RenderSpan, _: &str, _: Level) { + panic!("BasicEmitter can't handle custom_emit"); } - pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { - self.handler.emit(Some((&self.cm, sp)), msg, Fatal); - return FatalError; - } - pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { - self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Fatal); - return FatalError; - } - pub fn span_err(&self, sp: Span, msg: &str) { - self.handler.emit(Some((&self.cm, sp)), msg, Error); - self.handler.bump_err_count(); - } - pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { - self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error); - self.handler.bump_err_count(); - } - pub fn span_warn(&self, sp: Span, msg: &str) { - self.handler.emit(Some((&self.cm, sp)), msg, Warning); - } - pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { - self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Warning); - } - pub fn span_note(&self, sp: Span, msg: &str) { - self.handler.emit(Some((&self.cm, sp)), msg, Note); - } - pub fn span_end_note(&self, sp: Span, msg: &str) { - self.handler.custom_emit(&self.cm, EndSpan(sp), msg, Note); - } - pub fn span_help(&self, sp: Span, msg: &str) { - self.handler.emit(Some((&self.cm, sp)), msg, Help); - } - /// Prints out a message with a suggested edit of the code. - /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { - self.handler.custom_emit(&self.cm, Suggestion(sp, suggestion), msg, Help); - } - pub fn fileline_note(&self, sp: Span, msg: &str) { - self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note); - } - pub fn fileline_help(&self, sp: Span, msg: &str) { - self.handler.custom_emit(&self.cm, FileLine(sp), msg, Help); - } - pub fn span_bug(&self, sp: Span, msg: &str) -> ! { - self.handler.emit(Some((&self.cm, sp)), msg, Bug); - panic!(ExplicitBug); - } - pub fn span_bug_no_panic(&self, sp: Span, msg: &str) { - self.handler.emit(Some((&self.cm, sp)), msg, Bug); - self.handler.bump_err_count(); - } - pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { - self.span_bug(sp, &format!("unimplemented {}", msg)); - } - pub fn handler<'a>(&'a self) -> &'a Handler { - &self.handler - } -} - -/// A handler deals with errors; certain errors -/// (fatal, bug, unimpl) may cause immediate exit, -/// others log errors for later reporting. -pub struct Handler { - err_count: Cell, - emit: RefCell>, - pub can_emit_warnings: bool } -impl Handler { - pub fn new(color_config: ColorConfig, - registry: Option, - can_emit_warnings: bool) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, registry)); - Handler::with_emitter(can_emit_warnings, emitter) - } - pub fn with_emitter(can_emit_warnings: bool, e: Box) -> Handler { - Handler { - err_count: Cell::new(0), - emit: RefCell::new(e), - can_emit_warnings: can_emit_warnings - } - } - pub fn fatal(&self, msg: &str) -> FatalError { - self.emit.borrow_mut().emit(None, msg, None, Fatal); - FatalError - } - pub fn err(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Error); - self.bump_err_count(); - } - pub fn bump_err_count(&self) { - self.err_count.set(self.err_count.get() + 1); - } - pub fn err_count(&self) -> usize { - self.err_count.get() - } - pub fn has_errors(&self) -> bool { - self.err_count.get() > 0 - } - pub fn abort_if_errors(&self) { - let s; - match self.err_count.get() { - 0 => return, - 1 => s = "aborting due to previous error".to_string(), - _ => { - s = format!("aborting due to {} previous errors", - self.err_count.get()); - } +impl BasicEmitter { + pub fn stderr(color_config: ColorConfig) -> BasicEmitter { + if color_config.use_color() { + let dst = Destination::from_stderr(); + BasicEmitter { dst: dst } + } else { + BasicEmitter { dst: Raw(Box::new(io::stderr())) } } - - panic!(self.fatal(&s[..])); - } - pub fn warn(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Warning); - } - pub fn note(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Note); - } - pub fn help(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Help); - } - pub fn bug(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, None, Bug); - panic!(ExplicitBug); - } - pub fn unimpl(&self, msg: &str) -> ! { - self.bug(&format!("unimplemented {}", msg)); - } - pub fn emit(&self, - cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, - lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(cmsp, msg, None, lvl); - } - pub fn emit_with_code(&self, - cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, - code: &str, - lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl); - } - pub fn custom_emit(&self, cm: &codemap::CodeMap, - sp: RenderSpan, msg: &str, lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().custom_emit(cm, sp, msg, lvl); } } -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum Level { - Bug, - Fatal, - Error, - Warning, - Note, - Help, +pub struct EmitterWriter { + dst: Destination, + registry: Option, + cm: Rc, } -impl fmt::Display for Level { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use std::fmt::Display; +impl Emitter for EmitterWriter { + fn emit(&mut self, + sp: Option, + msg: &str, + code: Option<&str>, + lvl: Level) { + let error = match sp { + Some(COMMAND_LINE_SP) => self.emit_(FileLine(COMMAND_LINE_SP), msg, code, lvl), + Some(sp) => self.emit_(FullSpan(sp), msg, code, lvl), + None => print_diagnostic(&mut self.dst, "", lvl, msg, code), + }; - match *self { - Bug => "error: internal compiler error".fmt(f), - Fatal | Error => "error".fmt(f), - Warning => "warning".fmt(f), - Note => "note".fmt(f), - Help => "help".fmt(f), + if let Err(e) = error { + panic!("failed to print diagnostics: {:?}", e); } } -} -impl Level { - fn color(self) -> term::color::Color { - match self { - Bug | Fatal | Error => term::color::BRIGHT_RED, - Warning => term::color::BRIGHT_YELLOW, - Note => term::color::BRIGHT_GREEN, - Help => term::color::BRIGHT_CYAN, + fn custom_emit(&mut self, + sp: RenderSpan, + msg: &str, + lvl: Level) { + match self.emit_(sp, msg, None, lvl) { + Ok(()) => {} + Err(e) => panic!("failed to print diagnostics: {:?}", e), } } } -pub struct EmitterWriter { - dst: Destination, - registry: Option -} - -enum Destination { - Terminal(Box), - Raw(Box), -} - /// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See /// `EmitterWriter::print_maybe_styled` for details. macro_rules! print_maybe_styled { - ($writer: expr, $style: expr, $($arg: tt)*) => { - $writer.print_maybe_styled(format_args!($($arg)*), $style, false) + ($dst: expr, $style: expr, $($arg: tt)*) => { + $dst.print_maybe_styled(format_args!($($arg)*), $style, false) } } macro_rules! println_maybe_styled { - ($writer: expr, $style: expr, $($arg: tt)*) => { - $writer.print_maybe_styled(format_args!($($arg)*), $style, true) + ($dst: expr, $style: expr, $($arg: tt)*) => { + $dst.print_maybe_styled(format_args!($($arg)*), $style, true) } } impl EmitterWriter { pub fn stderr(color_config: ColorConfig, - registry: Option) -> EmitterWriter { - let stderr = io::stderr(); - - let use_color = match color_config { - Always => true, - Never => false, - Auto => stderr_isatty(), - }; - - if use_color { - let dst = match term::stderr() { - Some(t) => Terminal(t), - None => Raw(Box::new(stderr)), - }; - EmitterWriter { dst: dst, registry: registry } + registry: Option, + code_map: Rc) + -> EmitterWriter { + if color_config.use_color() { + let dst = Destination::from_stderr(); + EmitterWriter { dst: dst, registry: registry, cm: code_map } } else { - EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry } + EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map } } } pub fn new(dst: Box, - registry: Option) -> EmitterWriter { - EmitterWriter { dst: Raw(dst), registry: registry } - } - - fn print_maybe_styled(&mut self, - args: fmt::Arguments, - color: term::Attr, - print_newline_at_end: bool) -> io::Result<()> { - match self.dst { - Terminal(ref mut t) => { - try!(t.attr(color)); - // If `msg` ends in a newline, we need to reset the color before - // the newline. We're making the assumption that we end up writing - // to a `LineBufferedWriter`, which means that emitting the reset - // after the newline ends up buffering the reset until we print - // another line or exit. Buffering the reset is a problem if we're - // sharing the terminal with any other programs (e.g. other rustc - // instances via `make -jN`). - // - // Note that if `msg` contains any internal newlines, this will - // result in the `LineBufferedWriter` flushing twice instead of - // once, which still leaves the opportunity for interleaved output - // to be miscolored. We assume this is rare enough that we don't - // have to worry about it. - try!(t.write_fmt(args)); - try!(t.reset()); - if print_newline_at_end { - t.write_all(b"\n") - } else { - Ok(()) - } - } - Raw(ref mut w) => { - try!(w.write_fmt(args)); - if print_newline_at_end { - w.write_all(b"\n") - } else { - Ok(()) - } - } - } - } - - fn print_diagnostic(&mut self, topic: &str, lvl: Level, - msg: &str, code: Option<&str>) -> io::Result<()> { - if !topic.is_empty() { - try!(write!(&mut self.dst, "{} ", topic)); - } - - try!(print_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()), - "{}: ", lvl.to_string())); - try!(print_maybe_styled!(self, term::Attr::Bold, "{}", msg)); - - match code { - Some(code) => { - let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); - try!(print_maybe_styled!(self, style, " [{}]", code.clone())); - } - None => () - } - try!(write!(&mut self.dst, "\n")); - Ok(()) + registry: Option, + code_map: Rc) + -> EmitterWriter { + EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map } } - fn emit_(&mut self, cm: &codemap::CodeMap, rsp: RenderSpan, - msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> { + fn emit_(&mut self, + rsp: RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level) + -> io::Result<()> { let sp = rsp.span(); // We cannot check equality directly with COMMAND_LINE_SP @@ -433,25 +166,27 @@ impl EmitterWriter { "".to_string() } else if let EndSpan(_) = rsp { let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; - cm.span_to_string(span_end) + self.cm.span_to_string(span_end) } else { - cm.span_to_string(sp) + self.cm.span_to_string(sp) }; - try!(self.print_diagnostic(&ss[..], lvl, msg, code)); + try!(print_diagnostic(&mut self.dst, &ss[..], lvl, msg, code)); match rsp { FullSpan(_) => { - try!(self.highlight_lines(cm, sp, lvl, cm.span_to_lines(sp))); - try!(self.print_macro_backtrace(cm, sp)); + let lines = self.cm.span_to_lines(sp); + try!(self.highlight_lines(sp, lvl, lines)); + try!(self.print_macro_backtrace(sp)); } EndSpan(_) => { - try!(self.end_highlight_lines(cm, sp, lvl, cm.span_to_lines(sp))); - try!(self.print_macro_backtrace(cm, sp)); + let lines = self.cm.span_to_lines(sp); + try!(self.end_highlight_lines(sp, lvl, lines)); + try!(self.print_macro_backtrace(sp)); } Suggestion(_, ref suggestion) => { - try!(self.highlight_suggestion(cm, sp, suggestion)); - try!(self.print_macro_backtrace(cm, sp)); + try!(self.highlight_suggestion(sp, suggestion)); + try!(self.print_macro_backtrace(sp)); } FileLine(..) => { // no source text in this case! @@ -462,9 +197,9 @@ impl EmitterWriter { Some(code) => match self.registry.as_ref().and_then(|registry| registry.find_description(code)) { Some(_) => { - try!(self.print_diagnostic(&ss[..], Help, - &format!("run `rustc --explain {}` to see a \ - detailed explanation", code), None)); + try!(print_diagnostic(&mut self.dst, &ss[..], Help, + &format!("run `rustc --explain {}` to see a \ + detailed explanation", code), None)); } None => () }, @@ -474,12 +209,11 @@ impl EmitterWriter { } fn highlight_suggestion(&mut self, - cm: &codemap::CodeMap, sp: Span, suggestion: &str) -> io::Result<()> { - let lines = cm.span_to_lines(sp).unwrap(); + let lines = self.cm.span_to_lines(sp).unwrap(); assert!(!lines.lines.is_empty()); // To build up the result, we want to take the snippet from the first @@ -521,7 +255,6 @@ impl EmitterWriter { } fn highlight_lines(&mut self, - cm: &codemap::CodeMap, sp: Span, lvl: Level, lines: codemap::FileLinesResult) @@ -581,7 +314,7 @@ impl EmitterWriter { // FIXME (#3260) // If there's one line at fault we can easily point to the problem if lines.lines.len() == 1 { - let lo = cm.lookup_char_pos(sp.lo); + let lo = self.cm.lookup_char_pos(sp.lo); let mut digits = 0; let mut num = (lines.lines[0].line_index + 1) / 10; @@ -628,7 +361,7 @@ impl EmitterWriter { col += count; s.extend(::std::iter::repeat('~').take(count)); - let hi = cm.lookup_char_pos(sp.hi); + let hi = self.cm.lookup_char_pos(sp.hi); if hi.col != lo.col { for (pos, ch) in iter { if pos >= hi.col.to_usize() { break; } @@ -646,7 +379,7 @@ impl EmitterWriter { s.pop(); } - try!(println_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()), + try!(println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), "{}", s)); } } @@ -661,7 +394,6 @@ impl EmitterWriter { /// six lines. #[allow(deprecated)] fn end_highlight_lines(&mut self, - cm: &codemap::CodeMap, sp: Span, lvl: Level, lines: codemap::FileLinesResult) @@ -697,7 +429,7 @@ impl EmitterWriter { } } let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); - let hi = cm.lookup_char_pos(sp.hi); + let hi = self.cm.lookup_char_pos(sp.hi); let skip = last_line_start.chars().count(); let mut s = String::new(); for _ in 0..skip { @@ -719,55 +451,82 @@ impl EmitterWriter { } } s.push('^'); - println_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()), + println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), "{}", s) } fn print_macro_backtrace(&mut self, - cm: &codemap::CodeMap, sp: Span) -> io::Result<()> { let mut last_span = codemap::DUMMY_SP; - let mut sp_opt = Some(sp); - - while let Some(sp) = sp_opt { - sp_opt = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> { - match expn_info { - Some(ei) => { - let (pre, post) = match ei.callee.format { - codemap::MacroAttribute(..) => ("#[", "]"), - codemap::MacroBang(..) => ("", "!"), - }; - // Don't print recursive invocations - if ei.call_site != last_span { - last_span = ei.call_site; - - let mut diag_string = format!("in this expansion of {}{}{}", - pre, - ei.callee.name(), - post); - - if let Some(def_site_span) = ei.callee.span { - diag_string.push_str(&format!(" (defined in {})", - cm.span_to_filename(def_site_span))); - } - - try!(self.print_diagnostic(&cm.span_to_string(ei.call_site), - Note, - &diag_string, - None)); - } - Ok(Some(ei.call_site)) - } - None => Ok(None) + let mut span = sp; + + loop { + let span_name_span = self.cm.with_expn_info(span.expn_id, |expn_info| { + expn_info.map(|ei| { + let (pre, post) = match ei.callee.format { + codemap::MacroAttribute(..) => ("#[", "]"), + codemap::MacroBang(..) => ("", "!"), + }; + let macro_decl_name = format!("in this expansion of {}{}{}", + pre, + ei.callee.name(), + post); + let def_site_span = ei.callee.span; + (ei.call_site, macro_decl_name, def_site_span) + }) + }); + let (macro_decl_name, def_site_span) = match span_name_span { + None => break, + Some((sp, macro_decl_name, def_site_span)) => { + span = sp; + (macro_decl_name, def_site_span) } - })); + }; + + // Don't print recursive invocations + if span != last_span { + let mut diag_string = macro_decl_name; + if let Some(def_site_span) = def_site_span { + diag_string.push_str(&format!(" (defined in {})", + self.cm.span_to_filename(def_site_span))); + } + + let snippet = self.cm.span_to_string(span); + try!(print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)); + } + last_span = span; } Ok(()) } } +fn print_diagnostic(dst: &mut Destination, + topic: &str, + lvl: Level, + msg: &str, + code: Option<&str>) + -> io::Result<()> { + if !topic.is_empty() { + try!(write!(dst, "{} ", topic)); + } + + try!(print_maybe_styled!(dst, term::Attr::ForegroundColor(lvl.color()), + "{}: ", lvl.to_string())); + try!(print_maybe_styled!(dst, term::Attr::Bold, "{}", msg)); + + match code { + Some(code) => { + let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + try!(print_maybe_styled!(dst, style, " [{}]", code.clone())); + } + None => () + } + try!(write!(dst, "\n")); + Ok(()) +} + #[cfg(unix)] fn stderr_isatty() -> bool { use libc; @@ -791,6 +550,60 @@ fn stderr_isatty() -> bool { } } +enum Destination { + Terminal(Box), + Raw(Box), +} + +impl Destination { + fn from_stderr() -> Destination { + match term::stderr() { + Some(t) => Terminal(t), + None => Raw(Box::new(io::stderr())), + } + } + + fn print_maybe_styled(&mut self, + args: fmt::Arguments, + color: term::Attr, + print_newline_at_end: bool) + -> io::Result<()> { + match *self { + Terminal(ref mut t) => { + try!(t.attr(color)); + // If `msg` ends in a newline, we need to reset the color before + // the newline. We're making the assumption that we end up writing + // to a `LineBufferedWriter`, which means that emitting the reset + // after the newline ends up buffering the reset until we print + // another line or exit. Buffering the reset is a problem if we're + // sharing the terminal with any other programs (e.g. other rustc + // instances via `make -jN`). + // + // Note that if `msg` contains any internal newlines, this will + // result in the `LineBufferedWriter` flushing twice instead of + // once, which still leaves the opportunity for interleaved output + // to be miscolored. We assume this is rare enough that we don't + // have to worry about it. + try!(t.write_fmt(args)); + try!(t.reset()); + if print_newline_at_end { + t.write_all(b"\n") + } else { + Ok(()) + } + } + Raw(ref mut w) => { + try!(w.write_fmt(args)); + if print_newline_at_end { + w.write_all(b"\n") + } else { + Ok(()) + } + } + } + } +} + impl Write for Destination { fn write(&mut self, bytes: &[u8]) -> io::Result { match *self { @@ -806,49 +619,16 @@ impl Write for Destination { } } -impl Emitter for EmitterWriter { - fn emit(&mut self, - cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, code: Option<&str>, lvl: Level) { - let error = match cmsp { - Some((cm, COMMAND_LINE_SP)) => self.emit_(cm, - FileLine(COMMAND_LINE_SP), - msg, code, lvl), - Some((cm, sp)) => self.emit_(cm, FullSpan(sp), msg, code, lvl), - None => self.print_diagnostic("", lvl, msg, code), - }; - - match error { - Ok(()) => {} - Err(e) => panic!("failed to print diagnostics: {:?}", e), - } - } - - fn custom_emit(&mut self, cm: &codemap::CodeMap, - sp: RenderSpan, msg: &str, lvl: Level) { - match self.emit_(cm, sp, msg, None, lvl) { - Ok(()) => {} - Err(e) => panic!("failed to print diagnostics: {:?}", e), - } - } -} - -pub fn expect(diag: &SpanHandler, opt: Option, msg: M) -> T where - M: FnOnce() -> String, -{ - match opt { - Some(t) => t, - None => diag.handler().bug(&msg()), - } -} #[cfg(test)] mod test { - use super::{EmitterWriter, Level}; + use errors::Level; + use super::EmitterWriter; use codemap::{mk_sp, CodeMap}; use std::sync::{Arc, Mutex}; use std::io::{self, Write}; use std::str::from_utf8; + use std::rc::Rc; // Diagnostic doesn't align properly in span where line number increases by one digit #[test] @@ -861,8 +641,8 @@ mod test { fn flush(&mut self) -> io::Result<()> { Ok(()) } } let data = Arc::new(Mutex::new(Vec::new())); - let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None); - let cm = CodeMap::new(); + let cm = Rc::new(CodeMap::new()); + let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); let content = "abcdefg koksi line3 @@ -885,7 +665,7 @@ mod test { println!("span_to_lines"); let lines = cm.span_to_lines(sp); println!("highlight_lines"); - ew.highlight_lines(&cm, sp, lvl, lines).unwrap(); + ew.highlight_lines(sp, lvl, lines).unwrap(); println!("done"); let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; diff --git a/syntex_syntax/src/errors/mod.rs b/syntex_syntax/src/errors/mod.rs new file mode 100644 index 00000000..f2e61090 --- /dev/null +++ b/syntex_syntax/src/errors/mod.rs @@ -0,0 +1,338 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use errors::emitter::ColorConfig; + +use self::Level::*; +use self::RenderSpan::*; + +use codemap::{self, Span}; +use diagnostics; +use errors::emitter::{Emitter, EmitterWriter}; + +use std::cell::{RefCell, Cell}; +use std::{error, fmt}; +use std::io::prelude::*; +use std::rc::Rc; +use term; + +pub mod emitter; + +#[derive(Clone)] +pub enum RenderSpan { + /// A FullSpan renders with both with an initial line for the + /// message, prefixed by file:linenum, followed by a summary of + /// the source code covered by the span. + FullSpan(Span), + + /// Similar to a FullSpan, but the cited position is the end of + /// the span, instead of the start. Used, at least, for telling + /// compiletest/runtest to look at the last line of the span + /// (since `end_highlight_lines` displays an arrow to the end + /// of the span). + EndSpan(Span), + + /// A suggestion renders with both with an initial line for the + /// message, prefixed by file:linenum, followed by a summary + /// of hypothetical source code, where the `String` is spliced + /// into the lines in place of the code covered by the span. + Suggestion(Span, String), + + /// A FileLine renders with just a line for the message prefixed + /// by file:linenum. + FileLine(Span), +} + +impl RenderSpan { + fn span(&self) -> Span { + match *self { + FullSpan(s) | + Suggestion(s, _) | + EndSpan(s) | + FileLine(s) => + s + } + } +} + +/// Used as a return value to signify a fatal error occurred. (It is also +/// used as the argument to panic at the moment, but that will eventually +/// not be true.) +#[derive(Copy, Clone, Debug)] +#[must_use] +pub struct FatalError; + +impl fmt::Display for FatalError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "parser fatal error") + } +} + +impl error::Error for FatalError { + fn description(&self) -> &str { + "The parser has encountered a fatal error" + } +} + +/// Signifies that the compiler died with an explicit call to `.bug` +/// or `.span_bug` rather than a failed assertion, etc. +#[derive(Copy, Clone, Debug)] +pub struct ExplicitBug; + +impl fmt::Display for ExplicitBug { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "parser internal bug") + } +} + +impl error::Error for ExplicitBug { + fn description(&self) -> &str { + "The parser has encountered an internal bug" + } +} + +/// A handler deals with errors; certain errors +/// (fatal, bug, unimpl) may cause immediate exit, +/// others log errors for later reporting. +pub struct Handler { + err_count: Cell, + emit: RefCell>, + pub can_emit_warnings: bool, + treat_err_as_bug: bool, + delayed_span_bug: RefCell>, +} + +impl Handler { + pub fn new(color_config: ColorConfig, + registry: Option, + can_emit_warnings: bool, + treat_err_as_bug: bool, + cm: Rc) + -> Handler { + let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm)); + Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter) + } + + pub fn with_emitter(can_emit_warnings: bool, + treat_err_as_bug: bool, + e: Box) -> Handler { + Handler { + err_count: Cell::new(0), + emit: RefCell::new(e), + can_emit_warnings: can_emit_warnings, + treat_err_as_bug: treat_err_as_bug, + delayed_span_bug: RefCell::new(None), + } + } + + pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit(Some(sp), msg, Fatal); + return FatalError; + } + pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit_with_code(Some(sp), msg, code, Fatal); + return FatalError; + } + pub fn span_err(&self, sp: Span, msg: &str) { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit(Some(sp), msg, Error); + self.bump_err_count(); + } + pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit_with_code(Some(sp), msg, code, Error); + self.bump_err_count(); + } + pub fn span_warn(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Warning); + } + pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { + self.emit_with_code(Some(sp), msg, code, Warning); + } + pub fn span_note(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Note); + } + pub fn span_end_note(&self, sp: Span, msg: &str) { + self.custom_emit(EndSpan(sp), msg, Note); + } + pub fn span_help(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Help); + } + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { + self.custom_emit(Suggestion(sp, suggestion), msg, Help); + } + pub fn fileline_note(&self, sp: Span, msg: &str) { + self.custom_emit(FileLine(sp), msg, Note); + } + pub fn fileline_help(&self, sp: Span, msg: &str) { + self.custom_emit(FileLine(sp), msg, Help); + } + pub fn span_bug(&self, sp: Span, msg: &str) -> ! { + self.emit(Some(sp), msg, Bug); + panic!(ExplicitBug); + } + pub fn delay_span_bug(&self, sp: Span, msg: &str) { + let mut delayed = self.delayed_span_bug.borrow_mut(); + *delayed = Some((sp, msg.to_string())); + } + pub fn span_bug_no_panic(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Bug); + self.bump_err_count(); + } + pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { + self.span_bug(sp, &format!("unimplemented {}", msg)); + } + pub fn fatal(&self, msg: &str) -> FatalError { + if self.treat_err_as_bug { + self.bug(msg); + } + self.emit.borrow_mut().emit(None, msg, None, Fatal); + FatalError + } + pub fn err(&self, msg: &str) { + if self.treat_err_as_bug { + self.bug(msg); + } + self.emit.borrow_mut().emit(None, msg, None, Error); + self.bump_err_count(); + } + pub fn warn(&self, msg: &str) { + self.emit.borrow_mut().emit(None, msg, None, Warning); + } + pub fn note(&self, msg: &str) { + self.emit.borrow_mut().emit(None, msg, None, Note); + } + pub fn help(&self, msg: &str) { + self.emit.borrow_mut().emit(None, msg, None, Help); + } + pub fn bug(&self, msg: &str) -> ! { + self.emit.borrow_mut().emit(None, msg, None, Bug); + panic!(ExplicitBug); + } + pub fn unimpl(&self, msg: &str) -> ! { + self.bug(&format!("unimplemented {}", msg)); + } + + pub fn bump_err_count(&self) { + self.err_count.set(self.err_count.get() + 1); + } + + pub fn err_count(&self) -> usize { + self.err_count.get() + } + + pub fn has_errors(&self) -> bool { + self.err_count.get() > 0 + } + + pub fn abort_if_errors(&self) { + let s; + match self.err_count.get() { + 0 => { + let delayed_bug = self.delayed_span_bug.borrow(); + match *delayed_bug { + Some((span, ref errmsg)) => { + self.span_bug(span, errmsg); + }, + _ => {} + } + + return; + } + 1 => s = "aborting due to previous error".to_string(), + _ => { + s = format!("aborting due to {} previous errors", + self.err_count.get()); + } + } + + panic!(self.fatal(&s[..])); + } + + pub fn emit(&self, + sp: Option, + msg: &str, + lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { return } + self.emit.borrow_mut().emit(sp, msg, None, lvl); + } + + pub fn emit_with_code(&self, + sp: Option, + msg: &str, + code: &str, + lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { return } + self.emit.borrow_mut().emit(sp, msg, Some(code), lvl); + } + + pub fn custom_emit(&self, sp: RenderSpan, msg: &str, lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { return } + self.emit.borrow_mut().custom_emit(sp, msg, lvl); + } +} + + +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum Level { + Bug, + Fatal, + Error, + Warning, + Note, + Help, +} + +impl fmt::Display for Level { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::fmt::Display; + + match *self { + Bug => "error: internal compiler error".fmt(f), + Fatal | Error => "error".fmt(f), + Warning => "warning".fmt(f), + Note => "note".fmt(f), + Help => "help".fmt(f), + } + } +} + +impl Level { + fn color(self) -> term::color::Color { + match self { + Bug | Fatal | Error => term::color::BRIGHT_RED, + Warning => term::color::BRIGHT_YELLOW, + Note => term::color::BRIGHT_GREEN, + Help => term::color::BRIGHT_CYAN, + } + } +} + +pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where + M: FnOnce() -> String, +{ + match opt { + Some(t) => t, + None => diag.bug(&msg()), + } +} diff --git a/syntex_syntax/src/ext/asm.rs b/syntex_syntax/src/ext/asm.rs deleted file mode 100644 index d968858f..00000000 --- a/syntex_syntax/src/ext/asm.rs +++ /dev/null @@ -1,239 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* - * Inline assembly support. - */ -use self::State::*; - -use ast; -use codemap; -use codemap::Span; -use ext::base; -use ext::base::*; -use feature_gate; -use parse::token::{intern, InternedString}; -use parse::token; -use ptr::P; -use syntax::ast::AsmDialect; - -enum State { - Asm, - Outputs, - Inputs, - Clobbers, - Options, - StateNone -} - -impl State { - fn next(&self) -> State { - match *self { - Asm => Outputs, - Outputs => Inputs, - Inputs => Clobbers, - Clobbers => Options, - Options => StateNone, - StateNone => StateNone - } - } -} - -const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; - -pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { - if !cx.ecfg.enable_asm() { - feature_gate::emit_feature_err( - &cx.parse_sess.span_diagnostic, "asm", sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_ASM); - return DummyResult::expr(sp); - } - - let mut p = cx.new_parser_from_tts(tts); - let mut asm = InternedString::new(""); - let mut asm_str_style = None; - let mut outputs = Vec::new(); - let mut inputs = Vec::new(); - let mut clobs = Vec::new(); - let mut volatile = false; - let mut alignstack = false; - let mut dialect = AsmDialect::Att; - - let mut state = Asm; - - 'statement: loop { - match state { - Asm => { - if asm_str_style.is_some() { - // If we already have a string with instructions, - // ending up in Asm state again is an error. - cx.span_err(sp, "malformed inline assembly"); - return DummyResult::expr(sp); - } - let (s, style) = match expr_to_string(cx, panictry!(p.parse_expr()), - "inline assembly must be a string literal") { - Some((s, st)) => (s, st), - // let compilation continue - None => return DummyResult::expr(sp), - }; - asm = s; - asm_str_style = Some(style); - } - Outputs => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { - - if !outputs.is_empty() { - panictry!(p.eat(&token::Comma)); - } - - let (constraint, _str_style) = panictry!(p.parse_str()); - - let span = p.last_span; - - panictry!(p.expect(&token::OpenDelim(token::Paren))); - let out = panictry!(p.parse_expr()); - panictry!(p.expect(&token::CloseDelim(token::Paren))); - - // Expands a read+write operand into two operands. - // - // Use '+' modifier when you want the same expression - // to be both an input and an output at the same time. - // It's the opposite of '=&' which means that the memory - // cannot be shared with any other operand (usually when - // a register is clobbered early.) - let output = match constraint.slice_shift_char() { - Some(('=', _)) => None, - Some(('+', operand)) => { - Some(token::intern_and_get_ident(&format!( - "={}", operand))) - } - _ => { - cx.span_err(span, "output operand constraint lacks '=' or '+'"); - None - } - }; - - let is_rw = output.is_some(); - outputs.push((output.unwrap_or(constraint), out, is_rw)); - } - } - Inputs => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { - - if !inputs.is_empty() { - panictry!(p.eat(&token::Comma)); - } - - let (constraint, _str_style) = panictry!(p.parse_str()); - - if constraint.starts_with("=") && !constraint.contains("*") { - cx.span_err(p.last_span, "input operand constraint contains '='"); - } else if constraint.starts_with("+") && !constraint.contains("*") { - cx.span_err(p.last_span, "input operand constraint contains '+'"); - } - - panictry!(p.expect(&token::OpenDelim(token::Paren))); - let input = panictry!(p.parse_expr()); - panictry!(p.expect(&token::CloseDelim(token::Paren))); - - inputs.push((constraint, input)); - } - } - Clobbers => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { - - if !clobs.is_empty() { - panictry!(p.eat(&token::Comma)); - } - - let (s, _str_style) = panictry!(p.parse_str()); - - if OPTIONS.iter().any(|&opt| s == opt) { - cx.span_warn(p.last_span, "expected a clobber, found an option"); - } - clobs.push(s); - } - } - Options => { - let (option, _str_style) = panictry!(p.parse_str()); - - if option == "volatile" { - // Indicates that the inline assembly has side effects - // and must not be optimized out along with its outputs. - volatile = true; - } else if option == "alignstack" { - alignstack = true; - } else if option == "intel" { - dialect = AsmDialect::Intel; - } else { - cx.span_warn(p.last_span, "unrecognized option"); - } - - if p.token == token::Comma { - panictry!(p.eat(&token::Comma)); - } - } - StateNone => () - } - - loop { - // MOD_SEP is a double colon '::' without space in between. - // When encountered, the state must be advanced twice. - match (&p.token, state.next(), state.next().next()) { - (&token::Colon, StateNone, _) | - (&token::ModSep, _, StateNone) => { - panictry!(p.bump()); - break 'statement; - } - (&token::Colon, st, _) | - (&token::ModSep, _, st) => { - panictry!(p.bump()); - state = st; - } - (&token::Eof, _, _) => break 'statement, - _ => break - } - } - } - - let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: sp, - callee: codemap::NameAndSpan { - format: codemap::MacroBang(intern("asm")), - span: None, - allow_internal_unstable: false, - }, - }); - - MacEager::expr(P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprInlineAsm(ast::InlineAsm { - asm: token::intern_and_get_ident(&asm), - asm_str_style: asm_str_style.unwrap(), - outputs: outputs, - inputs: inputs, - clobbers: clobs, - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }), - span: sp, - attrs: None, - })) -} diff --git a/syntex_syntax/src/ext/base.rs b/syntex_syntax/src/ext/base.rs index 3b613922..f6164202 100644 --- a/syntex_syntax/src/ext/base.rs +++ b/syntex_syntax/src/ext/base.rs @@ -24,7 +24,7 @@ use parse::token; use parse::token::{InternedString, intern, str_to_ident}; use ptr::P; use util::small_vector::SmallVector; -use util::lev_distance::{lev_distance, max_suggestion_distance}; +use util::lev_distance::find_best_match_for_name; use ext::mtwt; use fold::Folder; @@ -464,26 +464,6 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) let mut syntax_expanders = SyntaxEnv::new(); syntax_expanders.insert(intern("macro_rules"), MacroRulesTT); - syntax_expanders.insert(intern("format_args"), - // format_args uses `unstable` things internally. - NormalTT(Box::new(ext::format::expand_format_args), None, true)); - syntax_expanders.insert(intern("env"), - builtin_normal_expander( - ext::env::expand_env)); - syntax_expanders.insert(intern("option_env"), - builtin_normal_expander( - ext::env::expand_option_env)); - syntax_expanders.insert(intern("concat_idents"), - builtin_normal_expander( - ext::concat_idents::expand_syntax_ext)); - syntax_expanders.insert(intern("concat"), - builtin_normal_expander( - ext::concat::expand_syntax_ext)); - syntax_expanders.insert(intern("log_syntax"), - builtin_normal_expander( - ext::log_syntax::expand_syntax_ext)); - - ext::deriving::register_all(&mut syntax_expanders); if ecfg.enable_quotes() { // Quasi-quoting expanders @@ -552,15 +532,6 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders.insert(intern("module_path"), builtin_normal_expander( ext::source_util::expand_mod)); - syntax_expanders.insert(intern("asm"), - builtin_normal_expander( - ext::asm::expand_asm)); - syntax_expanders.insert(intern("cfg"), - builtin_normal_expander( - ext::cfg::expand_cfg)); - syntax_expanders.insert(intern("trace_macros"), - builtin_normal_expander( - ext::trace_macros::expand_trace_macros)); syntax_expanders } @@ -601,13 +572,6 @@ impl<'a> ExtCtxt<'a> { } } - #[unstable(feature = "rustc_private", issue = "0")] - #[rustc_deprecated(since = "1.0.0", - reason = "Replaced with `expander().fold_expr()`")] - pub fn expand_expr(&mut self, e: P) -> P { - self.expander().fold_expr(e) - } - /// Returns a `Folder` for deeply expanding all macros in an AST node. pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { expand::MacroExpander::new(self) @@ -756,7 +720,7 @@ impl<'a> ExtCtxt<'a> { self.parse_sess.span_diagnostic.fileline_help(sp, msg); } pub fn bug(&self, msg: &str) -> ! { - self.parse_sess.span_diagnostic.handler().bug(msg); + self.parse_sess.span_diagnostic.bug(msg); } pub fn trace_macros(&self) -> bool { self.ecfg.trace_mac @@ -780,15 +744,8 @@ impl<'a> ExtCtxt<'a> { } pub fn suggest_macro_name(&mut self, name: &str, span: Span) { - let mut min: Option<(Name, usize)> = None; - let max_dist = max_suggestion_distance(name); - for macro_name in self.syntax_env.names.iter() { - let dist = lev_distance(name, ¯o_name.as_str()); - if dist <= max_dist && (min.is_none() || min.unwrap().1 > dist) { - min = Some((*macro_name, dist)); - } - } - if let Some((suggestion, _)) = min { + let names = &self.syntax_env.names; + if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) { self.fileline_help(span, &format!("did you mean `{}!`?", suggestion)); } } diff --git a/syntex_syntax/src/ext/build.rs b/syntex_syntax/src/ext/build.rs index 806f5a7e..8c19a10b 100644 --- a/syntex_syntax/src/ext/build.rs +++ b/syntex_syntax/src/ext/build.rs @@ -11,11 +11,9 @@ use abi; use ast::{Ident, Generics, Expr}; use ast; -use ast_util; use attr; use codemap::{Span, respan, Spanned, DUMMY_SP, Pos}; use ext::base::ExtCtxt; -use owned_slice::OwnedSlice; use parse::token::special_idents; use parse::token::InternedString; use parse::token; @@ -57,7 +55,7 @@ pub trait AstBuilder { fn ty(&self, span: Span, ty: ast::Ty_) -> P; fn ty_path(&self, ast::Path) -> P; - fn ty_sum(&self, ast::Path, OwnedSlice) -> P; + fn ty_sum(&self, ast::Path, ast::TyParamBounds) -> P; fn ty_ident(&self, span: Span, idents: ast::Ident) -> P; fn ty_rptr(&self, span: Span, @@ -71,13 +69,13 @@ pub trait AstBuilder { fn ty_option(&self, ty: P) -> P; fn ty_infer(&self, sp: Span) -> P; - fn ty_vars(&self, ty_params: &OwnedSlice) -> Vec> ; - fn ty_vars_global(&self, ty_params: &OwnedSlice) -> Vec> ; + fn ty_vars(&self, ty_params: &P<[ast::TyParam]>) -> Vec> ; + fn ty_vars_global(&self, ty_params: &P<[ast::TyParam]>) -> Vec> ; fn typaram(&self, span: Span, id: ast::Ident, - bounds: OwnedSlice, + bounds: ast::TyParamBounds, default: Option>) -> ast::TyParam; fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; @@ -332,8 +330,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { identifier: last_identifier, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), + types: P::from_vec(types), + bindings: P::from_vec(bindings), }) }); ast::Path { @@ -370,8 +368,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { identifier: ident, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), + types: P::from_vec(types), + bindings: P::from_vec(bindings), }) }); @@ -400,7 +398,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.ty(path.span, ast::TyPath(None, path)) } - fn ty_sum(&self, path: ast::Path, bounds: OwnedSlice) -> P { + fn ty_sum(&self, path: ast::Path, bounds: ast::TyParamBounds) -> P { self.ty(path.span, ast::TyObjectSum(self.ty_path(path), bounds)) @@ -449,7 +447,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn typaram(&self, span: Span, id: ast::Ident, - bounds: OwnedSlice, + bounds: ast::TyParamBounds, default: Option>) -> ast::TyParam { ast::TyParam { ident: id, @@ -463,11 +461,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { // these are strange, and probably shouldn't be used outside of // pipes. Specifically, the global version possible generates // incorrect code. - fn ty_vars(&self, ty_params: &OwnedSlice) -> Vec> { + fn ty_vars(&self, ty_params: &P<[ast::TyParam]>) -> Vec> { ty_params.iter().map(|p| self.ty_ident(DUMMY_SP, p.ident)).collect() } - fn ty_vars_global(&self, ty_params: &OwnedSlice) -> Vec> { + fn ty_vars_global(&self, ty_params: &P<[ast::TyParam]>) -> Vec> { ty_params .iter() .map(|p| self.ty_path(self.path_global(DUMMY_SP, vec!(p.ident)))) @@ -515,7 +513,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P) -> P { let pat = if mutbl { - self.pat_ident_binding_mode(sp, ident, ast::BindByValue(ast::MutMutable)) + self.pat_ident_binding_mode(sp, ident, ast::BindingMode::ByValue(ast::MutMutable)) } else { self.pat_ident(sp, ident) }; @@ -539,7 +537,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ex: P) -> P { let pat = if mutbl { - self.pat_ident_binding_mode(sp, ident, ast::BindByValue(ast::MutMutable)) + self.pat_ident_binding_mode(sp, ident, ast::BindingMode::ByValue(ast::MutMutable)) } else { self.pat_ident(sp, ident) }; @@ -810,7 +808,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.pat(span, ast::PatLit(expr)) } fn pat_ident(&self, span: Span, ident: ast::Ident) -> P { - self.pat_ident_binding_mode(span, ident, ast::BindByValue(ast::MutImmutable)) + self.pat_ident_binding_mode(span, ident, ast::BindingMode::ByValue(ast::MutImmutable)) } fn pat_ident_binding_mode(&self, @@ -991,7 +989,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { name, inputs, output, - ast_util::empty_generics(), + Generics::default(), body) } @@ -1029,7 +1027,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn item_enum(&self, span: Span, name: Ident, enum_definition: ast::EnumDef) -> P { self.item_enum_poly(span, name, enum_definition, - ast_util::empty_generics()) + Generics::default()) } fn item_struct(&self, span: Span, name: Ident, @@ -1038,7 +1036,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span, name, struct_def, - ast_util::empty_generics() + Generics::default() ) } @@ -1086,7 +1084,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn item_ty(&self, span: Span, name: Ident, ty: P) -> P { - self.item_ty_poly(span, name, ty, ast_util::empty_generics()) + self.item_ty_poly(span, name, ty, Generics::default()) } fn attribute(&self, sp: Span, mi: P) -> ast::Attribute { diff --git a/syntex_syntax/src/ext/cfg.rs b/syntex_syntax/src/ext/cfg.rs deleted file mode 100644 index e100355e..00000000 --- a/syntex_syntax/src/ext/cfg.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The compiler code necessary to support the cfg! extension, which expands to -/// a literal `true` or `false` based on whether the given cfg matches the -/// current compilation environment. - -use ast; -use codemap::Span; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use attr; -use attr::*; -use parse::token; -use config::CfgDiagReal; - -pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, - sp: Span, - tts: &[ast::TokenTree]) - -> Box { - let mut p = cx.new_parser_from_tts(tts); - let cfg = panictry!(p.parse_meta_item()); - - if !panictry!(p.eat(&token::Eof)){ - cx.span_err(sp, "expected 1 cfg-pattern"); - return DummyResult::expr(sp); - } - - let matches_cfg = { - let mut diag = CfgDiagReal { - diag: &cx.parse_sess.span_diagnostic, - feature_gated_cfgs: cx.feature_gated_cfgs, - }; - attr::cfg_matches(&cx.cfg, &cfg, &mut diag) - }; - MacEager::expr(cx.expr_bool(sp, matches_cfg)) -} diff --git a/syntex_syntax/src/ext/concat.rs b/syntex_syntax/src/ext/concat.rs deleted file mode 100644 index 71430b7a..00000000 --- a/syntex_syntax/src/ext/concat.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use codemap; -use ext::base; -use ext::build::AstBuilder; -use parse::token; - -use std::string::String; - -pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, - sp: codemap::Span, - tts: &[ast::TokenTree]) - -> Box { - let es = match base::get_exprs_from_tts(cx, sp, tts) { - Some(e) => e, - None => return base::DummyResult::expr(sp) - }; - let mut accumulator = String::new(); - for e in es { - match e.node { - ast::ExprLit(ref lit) => { - match lit.node { - ast::LitStr(ref s, _) | - ast::LitFloat(ref s, _) | - ast::LitFloatUnsuffixed(ref s) => { - accumulator.push_str(&s); - } - ast::LitChar(c) => { - accumulator.push(c); - } - ast::LitInt(i, ast::UnsignedIntLit(_)) | - ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) | - ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => { - accumulator.push_str(&format!("{}", i)); - } - ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) | - ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => { - accumulator.push_str(&format!("-{}", i)); - } - ast::LitBool(b) => { - accumulator.push_str(&format!("{}", b)); - } - ast::LitByte(..) | - ast::LitByteStr(..) => { - cx.span_err(e.span, "cannot concatenate a byte string literal"); - } - } - } - _ => { - cx.span_err(e.span, "expected a literal"); - } - } - } - base::MacEager::expr(cx.expr_str( - sp, - token::intern_and_get_ident(&accumulator[..]))) -} diff --git a/syntex_syntax/src/ext/concat_idents.rs b/syntex_syntax/src/ext/concat_idents.rs deleted file mode 100644 index c2233202..00000000 --- a/syntex_syntax/src/ext/concat_idents.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{self, TokenTree}; -use codemap::Span; -use ext::base::*; -use ext::base; -use feature_gate; -use parse::token; -use parse::token::str_to_ident; -use ptr::P; - -pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box { - if !cx.ecfg.enable_concat_idents() { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "concat_idents", - sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CONCAT_IDENTS); - return base::DummyResult::expr(sp); - } - - let mut res_str = String::new(); - for (i, e) in tts.iter().enumerate() { - if i & 1 == 1 { - match *e { - TokenTree::Token(_, token::Comma) => {}, - _ => { - cx.span_err(sp, "concat_idents! expecting comma."); - return DummyResult::expr(sp); - }, - } - } else { - match *e { - TokenTree::Token(_, token::Ident(ident, _)) => { - res_str.push_str(&ident.name.as_str()) - }, - _ => { - cx.span_err(sp, "concat_idents! requires ident args."); - return DummyResult::expr(sp); - }, - } - } - } - let res = str_to_ident(&res_str); - - let e = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(None, - ast::Path { - span: sp, - global: false, - segments: vec!( - ast::PathSegment { - identifier: res, - parameters: ast::PathParameters::none(), - } - ) - } - ), - span: sp, - attrs: None, - }); - MacEager::expr(e) -} diff --git a/syntex_syntax/src/ext/deriving/bounds.rs b/syntex_syntax/src/ext/deriving/bounds.rs deleted file mode 100644 index 87a6d080..00000000 --- a/syntex_syntax/src/ext/deriving/bounds.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::MetaItem; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; - -pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, - span: Span, - _: &MetaItem, - _: &Annotatable, - _: &mut FnMut(Annotatable)) -{ - cx.span_err(span, "this unsafe trait should be implemented explicitly"); -} - -pub fn expand_deriving_copy(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new()); - v.push("marker"); - v.push("Copy"); - let path = Path::new(v); - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path, - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: Vec::new(), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push); -} diff --git a/syntex_syntax/src/ext/deriving/clone.rs b/syntex_syntax/src/ext/deriving/clone.rs deleted file mode 100644 index f1a29834..00000000 --- a/syntex_syntax/src/ext/deriving/clone.rs +++ /dev/null @@ -1,114 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_clone(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::clone::Clone), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "clone", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|c, s, sub| { - cs_clone("Clone", c, s, sub) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn cs_clone( - name: &str, - cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure) -> P { - let ctor_path; - let all_fields; - let fn_path = cx.std_path(&["clone", "Clone", "clone"]); - let subcall = |field: &FieldInfo| { - let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; - - cx.expr_call_global(field.span, fn_path.clone(), args) - }; - - match *substr.fields { - Struct(ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident]); - all_fields = af; - } - EnumMatching(_, variant, ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]); - all_fields = af; - }, - EnumNonMatchingCollapsed (..) => { - cx.span_bug(trait_span, - &format!("non-matching enum variants in \ - `derive({})`", name)) - } - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, - &format!("static method in `derive({})`", name)) - } - } - - if !all_fields.is_empty() && all_fields[0].name.is_none() { - // enum-like - let subcalls = all_fields.iter().map(subcall).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } else { - // struct-like - let fields = all_fields.iter().map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", name)) - } - }; - cx.field_imm(field.span, ident, subcall(field)) - }).collect::>(); - - if fields.is_empty() { - // no fields, so construct like `None` - cx.expr_path(ctor_path) - } else { - cx.expr_struct(trait_span, ctor_path, fields) - } - } -} diff --git a/syntex_syntax/src/ext/deriving/cmp/eq.rs b/syntex_syntax/src/ext/deriving/cmp/eq.rs deleted file mode 100644 index bd6b27fb..00000000 --- a/syntex_syntax/src/ext/deriving/cmp/eq.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_eq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method( - |cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts, None); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") }), - cx, - span, - substr - ) - } - - let inline = cx.meta_word(span, InternedString::new("inline")); - let hidden = cx.meta_word(span, InternedString::new("hidden")); - let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden)); - let attrs = vec!(cx.attribute(span, inline), - cx.attribute(span, doc)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::Eq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "assert_receiver_is_total_eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(), - ret_ty: nil_ty(), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/syntex_syntax/src/ext/deriving/cmp/ord.rs b/syntex_syntax/src/ext/deriving/cmp/ord.rs deleted file mode 100644 index ff36e01d..00000000 --- a/syntex_syntax/src/ext/deriving/cmp/ord.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_ord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::Ord), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_cmp(a, b, c) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - - -pub fn ordering_collapsed(cx: &mut ExtCtxt, - span: Span, - self_arg_tags: &[ast::Ident]) -> P { - let lft = cx.expr_ident(span, self_arg_tags[0]); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) -} - -pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { - let test_id = cx.ident_of("__test"); - let equals_path = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); - - let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]); - - /* - Builds: - - let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1); - if other == ::std::cmp::Ordering::Equal { - let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2); - if __test == ::std::cmp::Ordering::Equal { - ... - } else { - __test - } - } else { - __test - } - - FIXME #6449: These `if`s could/should be `match`es. - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == ::std::cmp::Ordering::Equal { - // old - // } else { - // __test - // } - - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ - cx.expr_addr_of(span, self_f), - cx.expr_addr_of(span, other_f.clone()), - ]; - - cx.expr_call_global(span, cmp_path.clone(), args) - }; - - let assign = cx.stmt_let(span, false, test_id, new); - - let cond = cx.expr_binary(span, ast::BiEq, - cx.expr_ident(span, test_id), - cx.expr_path(equals_path.clone())); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) - }, - cx.expr_path(equals_path.clone()), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`") - } else { - ordering_collapsed(cx, span, tag_tuple) - } - }), - cx, span, substr) -} diff --git a/syntex_syntax/src/ext/deriving/cmp/partial_eq.rs b/syntex_syntax/src/ext/deriving/cmp/partial_eq.rs deleted file mode 100644 index 495761c4..00000000 --- a/syntex_syntax/src/ext/deriving/cmp/partial_eq.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr, self}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - // structures are equal if all fields are equal, and non equal, if - // any fields are not equal or if the enum variants are different - fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; - - let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone()); - - cx.expr_binary(span, ast::BiAnd, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, span, substr) - } - fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; - - let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone()); - - cx.expr_binary(span, ast::BiOr, subexpr, eq) - }, - cx.expr_bool(span, false), - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), - cx, span, substr) - } - - macro_rules! md { - ($name:expr, $f:ident) => { { - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - MethodDef { - name: $name, - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_local!(bool)), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - $f(a, b, c) - })) - } - } } - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::PartialEq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - md!("eq", cs_eq), - md!("ne", cs_ne) - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/syntex_syntax/src/ext/deriving/cmp/partial_ord.rs b/syntex_syntax/src/ext/deriving/cmp/partial_ord.rs deleted file mode 100644 index 084e3ef3..00000000 --- a/syntex_syntax/src/ext/deriving/cmp/partial_ord.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::OrderingOp::*; - -use ast; -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - macro_rules! md { - ($name:expr, $op:expr, $equal:expr) => { { - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - MethodDef { - name: $name, - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_local!(bool)), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_op($op, $equal, cx, span, substr) - })) - } - } } - } - - let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering)); - let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec![Box::new(ordering_ty)], - true)); - - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - - let partial_cmp_def = MethodDef { - name: "partial_cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], - ret_ty: ret_ty, - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) - })) - }; - - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: path_std!(cx, core::cmp::PartialOrd), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec![ - partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true) - ], - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -#[derive(Copy, Clone)] -pub enum OrderingOp { - PartialCmpOp, LtOp, LeOp, GtOp, GeOp, -} - -pub fn some_ordering_collapsed(cx: &mut ExtCtxt, - span: Span, - op: OrderingOp, - self_arg_tags: &[ast::Ident]) -> P { - let lft = cx.expr_ident(span, self_arg_tags[0]); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - let op_str = match op { - PartialCmpOp => "partial_cmp", - LtOp => "lt", LeOp => "le", - GtOp => "gt", GeOp => "ge", - }; - cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) -} - -pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { - let test_id = cx.ident_of("__test"); - let ordering = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); - let ordering = cx.expr_path(ordering); - let equals_expr = cx.expr_some(span, ordering); - - let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]); - - /* - Builds: - - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - ... - } else { - __test - } - } else { - __test - } - - FIXME #6449: These `if`s could/should be `match`es. - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == Some(::std::cmp::Ordering::Equal) { - // old - // } else { - // __test - // } - - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ - cx.expr_addr_of(span, self_f), - cx.expr_addr_of(span, other_f.clone()), - ]; - - cx.expr_call_global(span, partial_cmp_path.clone(), args) - }; - - let assign = cx.stmt_let(span, false, test_id, new); - - let cond = cx.expr_binary(span, ast::BiEq, - cx.expr_ident(span, test_id), - equals_expr.clone()); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) - }, - equals_expr.clone(), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) - } - }), - cx, span, substr) -} - -/// Strict inequality. -fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, - span: Span, substr: &Substructure) -> P { - let op = if less {ast::BiLt} else {ast::BiGt}; - cs_fold( - false, // need foldr, - |cx, span, subexpr, self_f, other_fs| { - /* - build up a series of chain ||'s and &&'s from the inside - out (hence foldr) to get lexical ordering, i.e. for op == - `ast::lt` - - ``` - self.f1 < other.f1 || (!(other.f1 < self.f1) && - (self.f2 < other.f2 || (!(other.f2 < self.f2) && - (false) - )) - ) - ``` - - The optimiser should remove the redundancy. We explicitly - get use the binops to avoid auto-deref dereferencing too many - layers of pointers, if the type includes pointers. - */ - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - }; - - let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - - let not_cmp = cx.expr_unary(span, ast::UnNot, - cx.expr_binary(span, op, other_f.clone(), self_f)); - - let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr); - cx.expr_binary(span, ast::BiOr, cmp, and) - }, - cx.expr_bool(span, equal), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let op = match (less, equal) { - (true, true) => LeOp, (true, false) => LtOp, - (false, true) => GeOp, (false, false) => GtOp, - }; - some_ordering_collapsed(cx, span, op, tag_tuple) - } - }), - cx, span, substr) -} diff --git a/syntex_syntax/src/ext/deriving/debug.rs b/syntex_syntax/src/ext/deriving/debug.rs deleted file mode 100644 index 9488cfb8..00000000 --- a/syntex_syntax/src/ext/deriving/debug.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use ast::{MetaItem, Expr}; -use codemap::{Span, respan}; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token; -use ptr::P; - -pub fn expand_deriving_debug(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - // &mut ::std::fmt::Formatter - let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))), - Borrowed(None, ast::MutMutable)); - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::fmt::Debug), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec![ - MethodDef { - name: "fmt", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(fmtr), - ret_ty: Literal(path_std!(cx, core::fmt::Result)), - attributes: Vec::new(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - show_substructure(a, b, c) - })) - } - ], - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -/// We use the debug builders to do the heavy lifting here -fn show_substructure(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { - // build fmt.debug_struct().field(, &)....build() - // or fmt.debug_tuple().field(&)....build() - // based on the "shape". - let ident = match *substr.fields { - Struct(_) => substr.type_ident, - EnumMatching(_, v, _) => v.node.name, - EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { - cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") - } - }; - - // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), .. span }; - let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(), - ast::StrStyle::CookedStr)); - let builder = token::str_to_ident("builder"); - let builder_expr = cx.expr_ident(span, builder.clone()); - - let fmt = substr.nonself_args[0].clone(); - - let stmts = match *substr.fields { - Struct(ref fields) | EnumMatching(_, _, ref fields) => { - let mut stmts = vec![]; - if fields.is_empty() || fields[0].name.is_none() { - // tuple struct/"normal" variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_tuple"), - vec![name]); - stmts.push(cx.stmt_let(span, true, builder, expr)); - - for field in fields { - // Use double indirection to make sure this works for unsized types - let field = cx.expr_addr_of(field.span, field.self_.clone()); - let field = cx.expr_addr_of(field.span, field); - - let expr = cx.expr_method_call(span, - builder_expr.clone(), - token::str_to_ident("field"), - vec![field]); - - // Use `let _ = expr;` to avoid triggering the - // unused_results lint. - stmts.push(stmt_let_undescore(cx, span, expr)); - } - } else { - // normal struct/struct variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_struct"), - vec![name]); - stmts.push(cx.stmt_let(span, true, builder, expr)); - - for field in fields { - let name = cx.expr_lit(field.span, ast::Lit_::LitStr( - field.name.unwrap().name.as_str(), - ast::StrStyle::CookedStr)); - - // Use double indirection to make sure this works for unsized types - let field = cx.expr_addr_of(field.span, field.self_.clone()); - let field = cx.expr_addr_of(field.span, field); - let expr = cx.expr_method_call(span, - builder_expr.clone(), - token::str_to_ident("field"), - vec![name, field]); - stmts.push(stmt_let_undescore(cx, span, expr)); - } - } - stmts - } - _ => unreachable!() - }; - - let expr = cx.expr_method_call(span, - builder_expr, - token::str_to_ident("finish"), - vec![]); - - let block = cx.block(span, stmts, Some(expr)); - cx.expr_block(block) -} - -fn stmt_let_undescore(cx: &mut ExtCtxt, - sp: Span, - expr: P) -> P { - let local = P(ast::Local { - pat: cx.pat_wild(sp), - ty: None, - init: Some(expr), - id: ast::DUMMY_NODE_ID, - span: sp, - attrs: None, - }); - let decl = respan(sp, ast::DeclLocal(local)); - P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))) -} diff --git a/syntex_syntax/src/ext/deriving/decodable.rs b/syntex_syntax/src/ext/deriving/decodable.rs deleted file mode 100644 index 0fdcbec8..00000000 --- a/syntex_syntax/src/ext/deriving/decodable.rs +++ /dev/null @@ -1,223 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more. - -use ast; -use ast::{MetaItem, Expr, MutMutable}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use parse::token; -use ptr::P; - -pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") -} - -pub fn expand_deriving_decodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") -} - -fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable), - krate: &'static str) -{ - if cx.crate_root != Some("std") { - // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ - or #![no_core]"); - return - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "decode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( - vec!(krate, "Decoder"), None, - vec!(), true)))) - }, - explicit_self: None, - args: vec!(Ptr(Box::new(Literal(Path::new_local("__D"))), - Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), - None, - vec!(Box::new(Self_), Box::new(Literal(Path::new_( - vec!["__D", "Error"], None, vec![], false - )))), - true - )), - attributes: Vec::new(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, - krate: &str) -> P { - let decoder = substr.nonself_args[0].clone(); - let recurse = vec!(cx.ident_of(krate), - cx.ident_of("Decodable"), - cx.ident_of("decode")); - let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); - // throw an underscore in front to suppress unused variable warnings - let blkarg = cx.ident_of("_d"); - let blkdecoder = cx.expr_ident(trait_span, blkarg); - - return match *substr.fields { - StaticStruct(_, ref summary) => { - let nfields = match *summary { - Unnamed(ref fields) => fields.len(), - Named(ref fields) => fields.len() - }; - let read_struct_field = cx.ident_of("read_struct_field"); - - let path = cx.path_ident(trait_span, substr.type_ident); - let result = decode_static_fields(cx, - trait_span, - path, - summary, - |cx, span, name, field| { - cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), read_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone()))) - }); - let result = cx.expr_ok(trait_span, result); - cx.expr_method_call(trait_span, - decoder, - cx.ident_of("read_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg) - )) - } - StaticEnum(_, ref fields) => { - let variant = cx.ident_of("i"); - - let mut arms = Vec::new(); - let mut variants = Vec::new(); - let rvariant_arg = cx.ident_of("read_enum_variant_arg"); - - for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { - variants.push(cx.expr_str(v_span, ident.name.as_str())); - - let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = decode_static_fields(cx, - v_span, - path, - parts, - |cx, span, _, field| { - let idx = cx.expr_usize(span, field); - cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg, - vec!(idx, exprdecode.clone()))) - }); - - arms.push(cx.arm(v_span, - vec!(cx.pat_lit(v_span, cx.expr_usize(v_span, i))), - decoded)); - } - - arms.push(cx.arm_unreachable(trait_span)); - - let result = cx.expr_ok(trait_span, - cx.expr_match(trait_span, - cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec!(blkarg, variant), result); - let variant_vec = cx.expr_vec(trait_span, variants); - let variant_vec = cx.expr_addr_of(trait_span, variant_vec); - let result = cx.expr_method_call(trait_span, blkdecoder, - cx.ident_of("read_enum_variant"), - vec!(variant_vec, lambda)); - cx.expr_method_call(trait_span, - decoder, - cx.ident_of("read_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg) - )) - } - _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)") - }; -} - -/// Create a decoder for a single enum variant/struct: -/// - `outer_pat_path` is the path to this enum variant/struct -/// - `getarg` should retrieve the `usize`-th field with name `@str`. -fn decode_static_fields(cx: &mut ExtCtxt, - trait_span: Span, - outer_pat_path: ast::Path, - fields: &StaticFields, - mut getarg: F) - -> P where - F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P, -{ - match *fields { - Unnamed(ref fields) => { - let path_expr = cx.expr_path(outer_pat_path); - if fields.is_empty() { - path_expr - } else { - let fields = fields.iter().enumerate().map(|(i, &span)| { - getarg(cx, span, - token::intern_and_get_ident(&format!("_field{}", i)), - i) - }).collect(); - - cx.expr_call(trait_span, path_expr, fields) - } - } - Named(ref fields) => { - // use the field's span to get nicer error messages. - let fields = fields.iter().enumerate().map(|(i, &(ident, span))| { - let arg = getarg(cx, span, ident.name.as_str(), i); - cx.field_imm(span, ident, arg) - }).collect(); - cx.expr_struct(trait_span, outer_pat_path, fields) - } - } -} diff --git a/syntex_syntax/src/ext/deriving/default.rs b/syntex_syntax/src/ext/deriving/default.rs deleted file mode 100644 index 6a250887..00000000 --- a/syntex_syntax/src/ext/deriving/default.rs +++ /dev/null @@ -1,84 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_default(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::default::Default), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "default", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - default_substructure(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { - let default_ident = cx.std_path(&["default", "Default", "default"]); - let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); - - return match *substr.fields { - StaticStruct(_, ref summary) => { - match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { - cx.expr_ident(trait_span, substr.type_ident) - } else { - let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); - cx.expr_call_ident(trait_span, substr.type_ident, exprs) - } - } - Named(ref fields) => { - let default_fields = fields.iter().map(|&(ident, span)| { - cx.field_imm(span, ident, default_call(span)) - }).collect(); - cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) - } - } - } - StaticEnum(..) => { - cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs"); - // let compilation continue - cx.expr_usize(trait_span, 0) - } - _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`") - }; -} diff --git a/syntex_syntax/src/ext/deriving/encodable.rs b/syntex_syntax/src/ext/deriving/encodable.rs deleted file mode 100644 index 78673993..00000000 --- a/syntex_syntax/src/ext/deriving/encodable.rs +++ /dev/null @@ -1,288 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The compiler code necessary to implement the `#[derive(Encodable)]` -//! (and `Decodable`, in decodable.rs) extension. The idea here is that -//! type-defining items may be tagged with `#[derive(Encodable, Decodable)]`. -//! -//! For example, a type like: -//! -//! ```ignore -//! #[derive(Encodable, Decodable)] -//! struct Node { id: usize } -//! ``` -//! -//! would generate two implementations like: -//! -//! ```ignore -//! impl, E> Encodable for Node { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Node", 1, |this| { -//! this.emit_struct_field("id", 0, |this| { -//! Encodable::encode(&self.id, this) -//! /* this.emit_usize(self.id) can also be used */ -//! }) -//! }) -//! } -//! } -//! -//! impl, E> Decodable for Node { -//! fn decode(d: &mut D) -> Result { -//! d.read_struct("Node", 1, |this| { -//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { -//! Ok(id) => Ok(Node { id: id }), -//! Err(e) => Err(e), -//! } -//! }) -//! } -//! } -//! ``` -//! -//! Other interesting scenarios are when the item has type parameters or -//! references other non-built-in types. A type definition like: -//! -//! ```ignore -//! #[derive(Encodable, Decodable)] -//! struct Spanned { node: T, span: Span } -//! ``` -//! -//! would yield functions like: -//! -//! ```ignore -//! impl< -//! S: Encoder, -//! E, -//! T: Encodable -//! > Encodable for Spanned { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Spanned", 2, |this| { -//! this.emit_struct_field("node", 0, |this| self.node.encode(this)) -//! .unwrap(); -//! this.emit_struct_field("span", 1, |this| self.span.encode(this)) -//! }) -//! } -//! } -//! -//! impl< -//! D: Decoder, -//! E, -//! T: Decodable -//! > Decodable for Spanned { -//! fn decode(d: &mut D) -> Result, E> { -//! d.read_struct("Spanned", 2, |this| { -//! Ok(Spanned { -//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) -//! .unwrap(), -//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) -//! .unwrap(), -//! }) -//! }) -//! } -//! } -//! ``` - -use ast::{MetaItem, Expr, ExprRet, MutMutable}; -use codemap::Span; -use ext::base::{ExtCtxt,Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token; -use ptr::P; - -pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") -} - -pub fn expand_deriving_encodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") -} - -fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable), - krate: &'static str) -{ - if cx.crate_root != Some("std") { - // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ - or #![no_core]"); - return; - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "encode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( - vec!(krate, "Encoder"), None, - vec!(), true)))) - }, - explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(Path::new_local("__S"))), - Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), - None, - vec!(Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_( - vec!["__S", "Error"], None, vec![], false - )))), - true - )), - attributes: Vec::new(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - encodable_substructure(a, b, c) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure) -> P { - let encoder = substr.nonself_args[0].clone(); - // throw an underscore in front to suppress unused variable warnings - let blkarg = cx.ident_of("_e"); - let blkencoder = cx.expr_ident(trait_span, blkarg); - let encode = cx.ident_of("encode"); - - return match *substr.fields { - Struct(ref fields) => { - let emit_struct_field = cx.ident_of("emit_struct_field"); - let mut stmts = Vec::new(); - for (i, &FieldInfo { - name, - ref self_, - span, - .. - }) in fields.iter().enumerate() { - let name = match name { - Some(id) => id.name.as_str(), - None => { - token::intern_and_get_ident(&format!("_field{}", i)) - } - }; - let enc = cx.expr_method_call(span, self_.clone(), - encode, vec!(blkencoder.clone())); - let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), - emit_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda)); - - // last call doesn't need a try! - let last = fields.len() - 1; - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprRet(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - - // unit structs have no fields and need to return Ok() - if stmts.is_empty() { - let ret_ok = cx.expr(trait_span, - ExprRet(Some(cx.expr_ok(trait_span, - cx.expr_tuple(trait_span, vec![]))))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - cx.expr_method_call(trait_span, - encoder, - cx.ident_of("emit_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, fields.len()), - blk - )) - } - - EnumMatching(idx, variant, ref fields) => { - // We're not generating an AST that the borrow checker is expecting, - // so we need to generate a unique local variable to take the - // mutable loan out on, otherwise we get conflicts which don't - // actually exist. - let me = cx.stmt_let(trait_span, false, blkarg, encoder); - let encoder = cx.expr_ident(trait_span, blkarg); - let emit_variant_arg = cx.ident_of("emit_enum_variant_arg"); - let mut stmts = Vec::new(); - if !fields.is_empty() { - let last = fields.len() - 1; - for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { - let enc = cx.expr_method_call(span, self_.clone(), - encode, vec!(blkencoder.clone())); - let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), - emit_variant_arg, - vec!(cx.expr_usize(span, i), - lambda)); - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprRet(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - } else { - let ret_ok = cx.expr(trait_span, - ExprRet(Some(cx.expr_ok(trait_span, - cx.expr_tuple(trait_span, vec![]))))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - let name = cx.expr_str(trait_span, variant.node.name.name.as_str()); - let call = cx.expr_method_call(trait_span, blkencoder, - cx.ident_of("emit_enum_variant"), - vec!(name, - cx.expr_usize(trait_span, idx), - cx.expr_usize(trait_span, fields.len()), - blk)); - let blk = cx.lambda_expr_1(trait_span, call, blkarg); - let ret = cx.expr_method_call(trait_span, - encoder, - cx.ident_of("emit_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - blk - )); - cx.expr_block(cx.block(trait_span, vec!(me), Some(ret))) - } - - _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)") - }; -} diff --git a/syntex_syntax/src/ext/deriving/generic/mod.rs b/syntex_syntax/src/ext/deriving/generic/mod.rs deleted file mode 100644 index bd89430d..00000000 --- a/syntex_syntax/src/ext/deriving/generic/mod.rs +++ /dev/null @@ -1,1704 +0,0 @@ -// Copyright 2013-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Some code that abstracts away much of the boilerplate of writing -//! `derive` instances for traits. Among other things it manages getting -//! access to the fields of the 4 different sorts of structs and enum -//! variants, as well as creating the method and impl ast instances. -//! -//! Supported features (fairly exhaustive): -//! -//! - Methods taking any number of parameters of any type, and returning -//! any type, other than vectors, bottom and closures. -//! - Generating `impl`s for types with type parameters and lifetimes -//! (e.g. `Option`), the parameters are automatically given the -//! current trait as a bound. (This includes separate type parameters -//! and lifetimes for methods.) -//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`) -//! -//! The most important thing for implementers is the `Substructure` and -//! `SubstructureFields` objects. The latter groups 5 possibilities of the -//! arguments: -//! -//! - `Struct`, when `Self` is a struct (including tuple structs, e.g -//! `struct T(i32, char)`). -//! - `EnumMatching`, when `Self` is an enum and all the arguments are the -//! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments -//! are not the same variant (e.g. `None`, `Some(1)` and `None`). -//! - `StaticEnum` and `StaticStruct` for static methods, where the type -//! being derived upon is either an enum or struct respectively. (Any -//! argument with type Self is just grouped among the non-self -//! arguments.) -//! -//! In the first two cases, the values from the corresponding fields in -//! all the arguments are grouped together. For `EnumNonMatchingCollapsed` -//! this isn't possible (different variants have different fields), so the -//! fields are inaccessible. (Previous versions of the deriving infrastructure -//! had a way to expand into code that could access them, at the cost of -//! generating exponential amounts of code; see issue #15375). There are no -//! fields with values in the static cases, so these are treated entirely -//! differently. -//! -//! The non-static cases have `Option` in several places associated -//! with field `expr`s. This represents the name of the field it is -//! associated with. It is only not `None` when the associated field has -//! an identifier in the source code. For example, the `x`s in the -//! following snippet -//! -//! ```rust -//! # #![allow(dead_code)] -//! struct A { x : i32 } -//! -//! struct B(i32); -//! -//! enum C { -//! C0(i32), -//! C1 { x: i32 } -//! } -//! ``` -//! -//! The `i32`s in `B` and `C0` don't have an identifier, so the -//! `Option`s would be `None` for them. -//! -//! In the static cases, the structure is summarised, either into the just -//! spans of the fields or a list of spans and the field idents (for tuple -//! structs and record structs, respectively), or a list of these, for -//! enums (one for each variant). For empty struct and empty enum -//! variants, it is represented as a count of 0. -//! -//! # "`cs`" functions -//! -//! The `cs_...` functions ("combine substructure) are designed to -//! make life easier by providing some pre-made recipes for common -//! threads; mostly calling the function being derived on all the -//! arguments and then combining them back together in some way (or -//! letting the user chose that). They are not meant to be the only -//! way to handle the structures that this code creates. -//! -//! # Examples -//! -//! The following simplified `PartialEq` is used for in-code examples: -//! -//! ```rust -//! trait PartialEq { -//! fn eq(&self, other: &Self) -> bool; -//! } -//! impl PartialEq for i32 { -//! fn eq(&self, other: &i32) -> bool { -//! *self == *other -//! } -//! } -//! ``` -//! -//! Some examples of the values of `SubstructureFields` follow, using the -//! above `PartialEq`, `A`, `B` and `C`. -//! -//! ## Structs -//! -//! When generating the `expr` for the `A` impl, the `SubstructureFields` is -//! -//! ```{.text} -//! Struct(vec![FieldInfo { -//! span: -//! name: Some(), -//! self_: , -//! other: vec![, -//! name: None, -//! self_: -//! other: vec![] -//! }]) -//! ``` -//! -//! ## Enums -//! -//! When generating the `expr` for a call with `self == C0(a)` and `other -//! == C0(b)`, the SubstructureFields is -//! -//! ```{.text} -//! EnumMatching(0, , -//! vec![FieldInfo { -//! span: -//! name: None, -//! self_: , -//! other: vec![] -//! }]) -//! ``` -//! -//! For `C1 {x}` and `C1 {x}`, -//! -//! ```{.text} -//! EnumMatching(1, , -//! vec![FieldInfo { -//! span: -//! name: Some(), -//! self_: , -//! other: vec![] -//! }]) -//! ``` -//! -//! For `C0(a)` and `C1 {x}` , -//! -//! ```{.text} -//! EnumNonMatchingCollapsed( -//! vec![, ], -//! &[, ], -//! &[, ]) -//! ``` -//! -//! It is the same for when the arguments are flipped to `C1 {x}` and -//! `C0(a)`; the only difference is what the values of the identifiers -//! and will -//! be in the generated code. -//! -//! `EnumNonMatchingCollapsed` deliberately provides far less information -//! than is generally available for a given pair of variants; see #15375 -//! for discussion. -//! -//! ## Static -//! -//! A static method on the types above would result in, -//! -//! ```{.text} -//! StaticStruct(, Named(vec![(, )])) -//! -//! StaticStruct(, Unnamed(vec![])) -//! -//! StaticEnum(, -//! vec![(, , Unnamed(vec![])), -//! (, , Named(vec![(, )]))]) -//! ``` - -pub use self::StaticFields::*; -pub use self::SubstructureFields::*; -use self::StructType::*; - -use std::cell::RefCell; -use std::collections::HashSet; -use std::vec; - -use abi::Abi; -use abi; -use ast; -use ast::{EnumDef, Expr, Ident, Generics, VariantData}; -use ast_util; -use attr; -use attr::AttrMetaMethods; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use codemap::{self, DUMMY_SP}; -use codemap::Span; -use diagnostic::SpanHandler; -use util::move_map::MoveMap; -use owned_slice::OwnedSlice; -use parse::token::{intern, InternedString}; -use parse::token::special_idents; -use ptr::P; - -use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; - -pub mod ty; - -pub struct TraitDef<'a> { - /// The span for the current #[derive(Foo)] header. - pub span: Span, - - pub attributes: Vec, - - /// Path of the trait, including any type parameters - pub path: Path<'a>, - - /// Additional bounds required of any type parameters of the type, - /// other than the current trait - pub additional_bounds: Vec>, - - /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder` - pub generics: LifetimeBounds<'a>, - - /// Is it an `unsafe` trait? - pub is_unsafe: bool, - - pub methods: Vec>, - - pub associated_types: Vec<(ast::Ident, Ty<'a>)>, -} - - -pub struct MethodDef<'a> { - /// name of the method - pub name: &'a str, - /// List of generics, e.g. `R: rand::Rng` - pub generics: LifetimeBounds<'a>, - - /// Whether there is a self argument (outer Option) i.e. whether - /// this is a static function, and whether it is a pointer (inner - /// Option) - pub explicit_self: Option>>, - - /// Arguments other than the self argument - pub args: Vec>, - - /// Return type - pub ret_ty: Ty<'a>, - - pub attributes: Vec, - - // Is it an `unsafe fn`? - pub is_unsafe: bool, - - pub combine_substructure: RefCell>, -} - -/// All the data about the data structure/method being derived upon. -pub struct Substructure<'a> { - /// ident of self - pub type_ident: Ident, - /// ident of the method - pub method_ident: Ident, - /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments - pub self_args: &'a [P], - /// verbatim access to any other arguments - pub nonself_args: &'a [P], - pub fields: &'a SubstructureFields<'a> -} - -/// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo<'a> { - pub span: Span, - /// None for tuple structs/normal enum variants, Some for normal - /// structs/struct enum variants. - pub name: Option, - /// The expression corresponding to this field of `self` - /// (specifically, a reference to it). - pub self_: P, - /// The expressions corresponding to references to this field in - /// the other `Self` arguments. - pub other: Vec>, - /// The attributes on the field - pub attrs: &'a [ast::Attribute], -} - -/// Fields for a static method -pub enum StaticFields { - /// Tuple structs/enum variants like this. - Unnamed(Vec), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span)>), -} - -/// A summary of the possible sets of fields. -pub enum SubstructureFields<'a> { - Struct(Vec>), - /// Matching variants of the enum: variant index, ast::Variant, - /// fields: the field name is only non-`None` in the case of a struct - /// variant. - EnumMatching(usize, &'a ast::Variant, Vec>), - - /// Non-matching variants of the enum, but with all state hidden from - /// the consequent code. The first component holds `Ident`s for all of - /// the `Self` arguments; the second component is a slice of all of the - /// variants for the enum itself, and the third component is a list of - /// `Ident`s bound to the variant index values for each of the actual - /// input `Self` arguments. - EnumNonMatchingCollapsed(Vec, &'a [P], &'a [Ident]), - - /// A static method where `Self` is a struct. - StaticStruct(&'a ast::VariantData, StaticFields), - /// A static method where `Self` is an enum. - StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), -} - - - -/// Combine the values of all the fields together. The last argument is -/// all the fields of all the structures. -pub type CombineSubstructureFunc<'a> = - Box P + 'a>; - -/// Deal with non-matching enum variants. The tuple is a list of -/// identifiers (one for each `Self` argument, which could be any of the -/// variants since they have been collapsed together) and the identifiers -/// holding the variant index value for each of the `Self` arguments. The -/// last argument is all the non-`Self` args of the method being derived. -pub type EnumNonMatchCollapsedFunc<'a> = - Box]) -> P + 'a>; - -pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) - -> RefCell> { - RefCell::new(f) -} - -/// This method helps to extract all the type parameters referenced from a -/// type. For a type parameter ``, it looks for either a `TyPath` that -/// is not global and starts with `T`, or a `TyQPath`. -fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec> { - use visit; - - struct Visitor<'a> { - ty_param_names: &'a [ast::Name], - types: Vec>, - } - - impl<'a> visit::Visitor<'a> for Visitor<'a> { - fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyPath(_, ref path) if !path.global => { - match path.segments.first() { - Some(segment) => { - if self.ty_param_names.contains(&segment.identifier.name) { - self.types.push(P(ty.clone())); - } - } - None => {} - } - } - _ => {} - } - - visit::walk_ty(self, ty) - } - } - - let mut visitor = Visitor { - ty_param_names: ty_param_names, - types: Vec::new(), - }; - - visit::Visitor::visit_ty(&mut visitor, ty); - - visitor.types -} - -impl<'a> TraitDef<'a> { - pub fn expand(&self, - cx: &mut ExtCtxt, - mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut FnMut(Annotatable)) - { - match *item { - Annotatable::Item(ref item) => { - let newitem = match item.node { - ast::ItemStruct(ref struct_def, ref generics) => { - self.expand_struct_def(cx, - &struct_def, - item.ident, - generics) - } - ast::ItemEnum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, - enum_def, - &item.attrs, - item.ident, - generics) - } - _ => { - cx.span_err(mitem.span, - "`derive` may only be applied to structs and enums"); - return; - } - }; - // Keep the lint attributes of the previous item to control how the - // generated implementations are linted - let mut attrs = newitem.attrs.clone(); - attrs.extend(item.attrs.iter().filter(|a| { - match &a.name()[..] { - "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, - _ => false, - } - }).cloned()); - push(Annotatable::Item(P(ast::Item { - attrs: attrs, - ..(*newitem).clone() - }))) - } - _ => { - cx.span_err(mitem.span, "`derive` may only be applied to structs and enums"); - } - } - } - - /// Given that we are deriving a trait `DerivedTrait` for a type like: - /// - /// ```ignore - /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait { - /// a: A, - /// b: B::Item, - /// b1: ::Item, - /// c1: ::Item, - /// c2: Option<::Item>, - /// ... - /// } - /// ``` - /// - /// create an impl like: - /// - /// ```ignore - /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where - /// C: WhereTrait, - /// A: DerivedTrait + B1 + ... + BN, - /// B: DerivedTrait + B1 + ... + BN, - /// C: DerivedTrait + B1 + ... + BN, - /// B::Item: DerivedTrait + B1 + ... + BN, - /// ::Item: DerivedTrait + B1 + ... + BN, - /// ... - /// { - /// ... - /// } - /// ``` - /// - /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and - /// therefore does not get bound by the derived trait. - fn create_derived_impl(&self, - cx: &mut ExtCtxt, - type_ident: Ident, - generics: &Generics, - field_tys: Vec>, - methods: Vec>) -> P { - let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - - // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem` - let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| { - P(ast::ImplItem { - id: ast::DUMMY_NODE_ID, - span: self.span, - ident: ident, - vis: ast::Inherited, - attrs: Vec::new(), - node: ast::ImplItemKind::Type(type_def.to_ty(cx, - self.span, - type_ident, - generics - )), - }) - }); - - let Generics { mut lifetimes, ty_params, mut where_clause } = - self.generics.to_generics(cx, self.span, type_ident, generics); - let mut ty_params = ty_params.into_vec(); - - // Copy the lifetimes - lifetimes.extend(generics.lifetimes.iter().cloned()); - - // Create the type parameters. - ty_params.extend(generics.ty_params.iter().map(|ty_param| { - // I don't think this can be moved out of the loop, since - // a TyParamBound requires an ast id - let mut bounds: Vec<_> = - // extra restrictions on the generics parameters to the type being derived upon - self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, - type_ident, generics)) - }).collect(); - - // require the current trait - bounds.push(cx.typarambound(trait_path.clone())); - - // also add in any bounds from the declaration - for declared_bound in ty_param.bounds.iter() { - bounds.push((*declared_bound).clone()); - } - - cx.typaram(self.span, - ty_param.ident, - OwnedSlice::from_vec(bounds), - None) - })); - - // and similarly for where clauses - where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { - match *clause { - ast::WherePredicate::BoundPredicate(ref wb) => { - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - span: self.span, - bound_lifetimes: wb.bound_lifetimes.clone(), - bounded_ty: wb.bounded_ty.clone(), - bounds: OwnedSlice::from_vec(wb.bounds.iter().cloned().collect()) - }) - } - ast::WherePredicate::RegionPredicate(ref rb) => { - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - span: self.span, - lifetime: rb.lifetime, - bounds: rb.bounds.iter().cloned().collect() - }) - } - ast::WherePredicate::EqPredicate(ref we) => { - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - id: ast::DUMMY_NODE_ID, - span: self.span, - path: we.path.clone(), - ty: we.ty.clone() - }) - } - } - })); - - if !ty_params.is_empty() { - let ty_param_names: Vec = ty_params.iter() - .map(|ty_param| ty_param.ident.name) - .collect(); - - let mut processed_field_types = HashSet::new(); - for field_ty in field_tys { - let tys = find_type_parameters(&*field_ty, &ty_param_names); - - for ty in tys { - // if we have already handled this type, skip it - if let ast::TyPath(_, ref p) = ty.node { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].identifier.name) - || processed_field_types.contains(&p.segments) { - continue; - }; - processed_field_types.insert(p.segments.clone()); - } - let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) - }).collect(); - - // require the current trait - bounds.push(cx.typarambound(trait_path.clone())); - - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: OwnedSlice::from_vec(bounds), - }; - - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } - } - } - - let trait_generics = Generics { - lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params), - where_clause: where_clause - }; - - // Create the reference to the trait. - let trait_ref = cx.trait_ref(trait_path); - - // Create the type parameters on the `self` path. - let self_ty_params = generics.ty_params.map(|ty_param| { - cx.ty_ident(self.span, ty_param.ident) - }); - - let self_lifetimes: Vec = - generics.lifetimes - .iter() - .map(|ld| ld.lifetime) - .collect(); - - // Create the type of `self`. - let self_type = cx.ty_path( - cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes, - self_ty_params.into_vec(), Vec::new())); - - let attr = cx.attribute( - self.span, - cx.meta_word(self.span, - InternedString::new("automatically_derived"))); - // Just mark it now since we know that it'll end up used downstream - attr::mark_used(&attr); - let opt_trait_ref = Some(trait_ref); - let ident = ast_util::impl_pretty_name(&opt_trait_ref, Some(&*self_type)); - let unused_qual = cx.attribute( - self.span, - cx.meta_list(self.span, - InternedString::new("allow"), - vec![cx.meta_word(self.span, - InternedString::new("unused_qualifications"))])); - let mut a = vec![attr, unused_qual]; - a.extend(self.attributes.iter().cloned()); - - let unsafety = if self.is_unsafe { - ast::Unsafety::Unsafe - } else { - ast::Unsafety::Normal - }; - - cx.item( - self.span, - ident, - a, - ast::ItemImpl(unsafety, - ast::ImplPolarity::Positive, - trait_generics, - opt_trait_ref, - self_type, - methods.into_iter().chain(associated_types).collect())) - } - - fn expand_struct_def(&self, - cx: &mut ExtCtxt, - struct_def: &'a VariantData, - type_ident: Ident, - generics: &Generics) -> P { - let field_tys: Vec> = struct_def.fields().iter() - .map(|field| field.node.ty.clone()) - .collect(); - - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args( - cx, self, type_ident, generics); - - let body = if method_def.is_static() { - method_def.expand_static_struct_method_body( - cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_struct_method_body(cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - }; - - method_def.create_method(cx, - self, - type_ident, - generics, - abi::Rust, - explicit_self, - tys, - body) - }).collect(); - - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) - } - - fn expand_enum_def(&self, - cx: &mut ExtCtxt, - enum_def: &'a EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - generics: &Generics) -> P { - let mut field_tys = Vec::new(); - - for variant in &enum_def.variants { - field_tys.extend(variant.node.data.fields().iter() - .map(|field| field.node.ty.clone())); - } - - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, - type_ident, generics); - - let body = if method_def.is_static() { - method_def.expand_static_enum_method_body( - cx, - self, - enum_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_enum_method_body(cx, - self, - enum_def, - type_attrs, - type_ident, - self_args, - &nonself_args[..]) - }; - - method_def.create_method(cx, - self, - type_ident, - generics, - abi::Rust, - explicit_self, - tys, - body) - }).collect(); - - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) - } -} - -fn find_repr_type_name(diagnostic: &SpanHandler, - type_attrs: &[ast::Attribute]) -> &'static str { - let mut repr_type_name = "i32"; - for a in type_attrs { - for r in &attr::find_repr_attrs(diagnostic, a) { - repr_type_name = match *r { - attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, - attr::ReprExtern => "i32", - - attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize", - attr::ReprInt(_, attr::SignedInt(ast::TyI8)) => "i8", - attr::ReprInt(_, attr::SignedInt(ast::TyI16)) => "i16", - attr::ReprInt(_, attr::SignedInt(ast::TyI32)) => "i32", - attr::ReprInt(_, attr::SignedInt(ast::TyI64)) => "i64", - - attr::ReprInt(_, attr::UnsignedInt(ast::TyUs)) => "usize", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU8)) => "u8", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU16)) => "u16", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU32)) => "u32", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU64)) => "u64", - } - } - } - repr_type_name -} - -impl<'a> MethodDef<'a> { - fn call_substructure_method(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - self_args: &[P], - nonself_args: &[P], - fields: &SubstructureFields) - -> P { - let substructure = Substructure { - type_ident: type_ident, - method_ident: cx.ident_of(self.name), - self_args: self_args, - nonself_args: nonself_args, - fields: fields - }; - let mut f = self.combine_substructure.borrow_mut(); - let f: &mut CombineSubstructureFunc = &mut *f; - f(cx, trait_.span, &substructure) - } - - fn get_ret_ty(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - generics: &Generics, - type_ident: Ident) - -> P { - self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) - } - - fn is_static(&self) -> bool { - self.explicit_self.is_none() - } - - fn split_self_nonself_args(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics) - -> (ast::ExplicitSelf, Vec>, Vec>, Vec<(Ident, P)>) { - - let mut self_args = Vec::new(); - let mut nonself_args = Vec::new(); - let mut arg_tys = Vec::new(); - let mut nonstatic = false; - - let ast_explicit_self = match self.explicit_self { - Some(ref self_ptr) => { - let (self_expr, explicit_self) = - ty::get_explicit_self(cx, trait_.span, self_ptr); - - self_args.push(self_expr); - nonstatic = true; - - explicit_self - } - None => codemap::respan(trait_.span, ast::SelfStatic), - }; - - for (i, ty) in self.args.iter().enumerate() { - let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(&format!("__arg_{}", i)); - arg_tys.push((ident, ast_ty)); - - let arg_expr = cx.expr_ident(trait_.span, ident); - - match *ty { - // for static methods, just treat any Self - // arguments as a normal arg - Self_ if nonstatic => { - self_args.push(arg_expr); - } - Ptr(ref ty, _) if **ty == Self_ && nonstatic => { - self_args.push(cx.expr_deref(trait_.span, arg_expr)) - } - _ => { - nonself_args.push(arg_expr); - } - } - } - - (ast_explicit_self, self_args, nonself_args, arg_tys) - } - - fn create_method(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics, - abi: Abi, - explicit_self: ast::ExplicitSelf, - arg_types: Vec<(Ident, P)> , - body: P) -> P { - // create the generics that aren't for Self - let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - - let self_arg = match explicit_self.node { - ast::SelfStatic => None, - // creating fresh self id - _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_)) - }; - let args = { - let args = arg_types.into_iter().map(|(name, ty)| { - cx.arg(trait_.span, name, ty) - }); - self_arg.into_iter().chain(args).collect() - }; - - let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - - let method_ident = cx.ident_of(self.name); - let fn_decl = cx.fn_decl(args, ret_type); - let body_block = cx.block_expr(body); - - let unsafety = if self.is_unsafe { - ast::Unsafety::Unsafe - } else { - ast::Unsafety::Normal - }; - - // Create the method. - P(ast::ImplItem { - id: ast::DUMMY_NODE_ID, - attrs: self.attributes.clone(), - span: trait_.span, - vis: ast::Inherited, - ident: method_ident, - node: ast::ImplItemKind::Method(ast::MethodSig { - generics: fn_generics, - abi: abi, - explicit_self: explicit_self, - unsafety: unsafety, - constness: ast::Constness::NotConst, - decl: fn_decl - }, body_block) - }) - } - - /// ```ignore - /// #[derive(PartialEq)] - /// struct A { x: i32, y: i32 } - /// - /// // equivalent to: - /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> bool { - /// match *self { - /// A {x: ref __self_0_0, y: ref __self_0_1} => { - /// match *__arg_1 { - /// A {x: ref __self_1_0, y: ref __self_1_1} => { - /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) - /// } - /// } - /// } - /// } - /// } - /// } - /// ``` - fn expand_struct_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - struct_def: &'b VariantData, - type_ident: Ident, - self_args: &[P], - nonself_args: &[P]) - -> P { - - let mut raw_fields = Vec::new(); // Vec<[fields of self], - // [fields of next Self arg], [etc]> - let mut patterns = Vec::new(); - for i in 0..self_args.len() { - let struct_path= cx.path(DUMMY_SP, vec!( type_ident )); - let (pat, ident_expr) = - trait_.create_struct_pattern(cx, - struct_path, - struct_def, - &format!("__self_{}", - i), - ast::MutImmutable); - patterns.push(pat); - raw_fields.push(ident_expr); - } - - // transpose raw_fields - let fields = if !raw_fields.is_empty() { - let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); - let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec> - = raw_fields.collect(); - first_field.map(|(span, opt_id, field, attrs)| { - FieldInfo { - span: span, - name: opt_id, - self_: field, - other: other_fields.iter_mut().map(|l| { - match l.next().unwrap() { - (_, _, ex, _) => ex - } - }).collect(), - attrs: attrs, - } - }).collect() - } else { - cx.span_bug(trait_.span, - "no self arguments to non-static method in generic \ - `derive`") - }; - - // body of the inner most destructuring match - let mut body = self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &Struct(fields)); - - // make a series of nested matches, to destructure the - // structs. This is actually right-to-left, but it shouldn't - // matter. - for (arg_expr, pat) in self_args.iter().zip(patterns) { - body = cx.expr_match(trait_.span, arg_expr.clone(), - vec!( cx.arm(trait_.span, vec!(pat.clone()), body) )) - } - body - } - - fn expand_static_struct_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &VariantData, - type_ident: Ident, - self_args: &[P], - nonself_args: &[P]) - -> P { - let summary = trait_.summarise_struct(cx, struct_def); - - self.call_substructure_method(cx, - trait_, - type_ident, - self_args, nonself_args, - &StaticStruct(struct_def, summary)) - } - - /// ```ignore - /// #[derive(PartialEq)] - /// enum A { - /// A1, - /// A2(i32) - /// } - /// - /// // is equivalent to - /// - /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> ::bool { - /// match (&*self, &*__arg_1) { - /// (&A1, &A1) => true, - /// (&A2(ref __self_0), - /// &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)), - /// _ => { - /// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 }; - /// let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 }; - /// false - /// } - /// } - /// } - /// } - /// ``` - /// - /// (Of course `__self_vi` and `__arg_1_vi` are unused for - /// `PartialEq`, and those subcomputations will hopefully be removed - /// as their results are unused. The point of `__self_vi` and - /// `__arg_1_vi` is for `PartialOrd`; see #15503.) - fn expand_enum_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec>, - nonself_args: &[P]) - -> P { - self.build_enum_match_tuple( - cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args) - } - - - /// Creates a match for a tuple of all `self_args`, where either all - /// variants match, or it falls into a catch-all for when one variant - /// does not match. - - /// There are N + 1 cases because is a case for each of the N - /// variants where all of the variants match, and one catch-all for - /// when one does not match. - - /// As an optimization we generate code which checks whether all variants - /// match first which makes llvm see that C-like enums can be compiled into - /// a simple equality check (for PartialEq). - - /// The catch-all handler is provided access the variant index values - /// for each of the self-args, carried in precomputed variables. - - /// ```{.text} - /// let __self0_vi = unsafe { - /// std::intrinsics::discriminant_value(&self) } as i32; - /// let __self1_vi = unsafe { - /// std::intrinsics::discriminant_value(&__arg1) } as i32; - /// let __self2_vi = unsafe { - /// std::intrinsics::discriminant_value(&__arg2) } as i32; - /// - /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { - /// match (...) { - /// (Variant1, Variant1, ...) => Body1 - /// (Variant2, Variant2, ...) => Body2, - /// ... - /// _ => ::core::intrinsics::unreachable() - /// } - /// } - /// else { - /// ... // catch-all remainder can inspect above variant index values. - /// } - /// ``` - fn build_enum_match_tuple<'b>( - &self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec>, - nonself_args: &[P]) -> P { - - let sp = trait_.span; - let variants = &enum_def.variants; - - let self_arg_names = self_args.iter().enumerate() - .map(|(arg_count, _self_arg)| { - if arg_count == 0 { - "__self".to_string() - } else { - format!("__arg_{}", arg_count) - } - }) - .collect::>(); - - let self_arg_idents = self_arg_names.iter() - .map(|name|cx.ident_of(&name[..])) - .collect::>(); - - // The `vi_idents` will be bound, solely in the catch-all, to - // a series of let statements mapping each self_arg to an int - // value corresponding to its discriminant. - let vi_idents: Vec = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..]) }) - .collect::>(); - - // Builds, via callback to call_substructure_method, the - // delegated expression that handles the catch-all case, - // using `__variants_tuple` to drive logic if necessary. - let catch_all_substructure = EnumNonMatchingCollapsed( - self_arg_idents, &variants[..], &vi_idents[..]); - - // These arms are of the form: - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2 - // ... - // where each tuple has length = self_args.len() - let mut match_arms: Vec = variants.iter().enumerate() - .map(|(index, variant)| { - let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| { - let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident, - &**variant, - self_arg_name, - ast::MutImmutable); - (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents) - }; - - // A single arm has form (&VariantK, &VariantK, ...) => BodyK - // (see "Final wrinkle" note below for why.) - let mut subpats = Vec::with_capacity(self_arg_names.len()); - let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1); - let first_self_pat_idents = { - let (p, idents) = mk_self_pat(cx, &self_arg_names[0]); - subpats.push(p); - idents - }; - for self_arg_name in &self_arg_names[1..] { - let (p, idents) = mk_self_pat(cx, &self_arg_name[..]); - subpats.push(p); - self_pats_idents.push(idents); - } - - // Here is the pat = `(&VariantK, &VariantK, ...)` - let single_pat = cx.pat_tuple(sp, subpats); - - // For the BodyK, we need to delegate to our caller, - // passing it an EnumMatching to indicate which case - // we are in. - - // All of the Self args have the same variant in these - // cases. So we transpose the info in self_pats_idents - // to gather the getter expressions together, in the - // form that EnumMatching expects. - - // The transposition is driven by walking across the - // arg fields of the variant for the first self pat. - let field_tuples = first_self_pat_idents.into_iter().enumerate() - // For each arg field of self, pull out its getter expr ... - .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| { - // ... but FieldInfo also wants getter expr - // for matching other arguments of Self type; - // so walk across the *other* self_pats_idents - // and pull out getter for same field in each - // of them (using `field_index` tracked above). - // That is the heart of the transposition. - let others = self_pats_idents.iter().map(|fields| { - let (_, _opt_ident, ref other_getter_expr, _) = - fields[field_index]; - - // All Self args have same variant, so - // opt_idents are the same. (Assert - // here to make it self-evident that - // it is okay to ignore `_opt_ident`.) - assert!(opt_ident == _opt_ident); - - other_getter_expr.clone() - }).collect::>>(); - - FieldInfo { span: sp, - name: opt_ident, - self_: self_getter_expr, - other: others, - attrs: attrs, - } - }).collect::>(); - - // Now, for some given VariantK, we have built up - // expressions for referencing every field of every - // Self arg, assuming all are instances of VariantK. - // Build up code associated with such a case. - let substructure = EnumMatching(index, - &**variant, - field_tuples); - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &substructure); - - cx.arm(sp, vec![single_pat], arm_expr) - }).collect(); - // We will usually need the catch-all after matching the - // tuples `(VariantK, VariantK, ...)` for each VariantK of the - // enum. But: - // - // * when there is only one Self arg, the arms above suffice - // (and the deriving we call back into may not be prepared to - // handle EnumNonMatchCollapsed), and, - // - // * when the enum has only one variant, the single arm that - // is already present always suffices. - // - // * In either of the two cases above, if we *did* add a - // catch-all `_` match, it would trigger the - // unreachable-pattern error. - // - if variants.len() > 1 && self_args.len() > 1 { - // Build a series of let statements mapping each self_arg - // to its discriminant value. If this is a C-style enum - // with a specific repr type, then casts the values to - // that type. Otherwise casts to `i32` (the default repr - // type). - // - // i.e. for `enum E { A, B(1), C(T, T) }`, and a deriving - // with three Self args, builds three statements: - // - // ``` - // let __self0_vi = unsafe { - // std::intrinsics::discriminant_value(&self) } as i32; - // let __self1_vi = unsafe { - // std::intrinsics::discriminant_value(&__arg1) } as i32; - // let __self2_vi = unsafe { - // std::intrinsics::discriminant_value(&__arg2) } as i32; - // ``` - let mut index_let_stmts: Vec> = Vec::new(); - - //We also build an expression which checks whether all discriminants are equal - // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... - let mut discriminant_test = cx.expr_bool(sp, true); - - let target_type_name = - find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); - - let mut first_ident = None; - for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { - let path = cx.std_path(&["intrinsics", "discriminant_value"]); - let call = cx.expr_call_global( - sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]); - let variant_value = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::UnsafeBlock(ast::CompilerGenerated), - span: sp })); - - let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); - let variant_disr = cx.expr_cast(sp, variant_value, target_ty); - let let_stmt = cx.stmt_let(sp, false, ident, variant_disr); - index_let_stmts.push(let_stmt); - - match first_ident { - Some(first) => { - let first_expr = cx.expr_ident(sp, first); - let id = cx.expr_ident(sp, ident); - let test = cx.expr_binary(sp, ast::BiEq, first_expr, id); - discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test) - } - None => { - first_ident = Some(ident); - } - } - } - - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &catch_all_substructure); - - //Since we know that all the arguments will match if we reach the match expression we - //add the unreachable intrinsics as the result of the catch all which should help llvm - //in optimizing it - let path = cx.std_path(&["intrinsics", "unreachable"]); - let call = cx.expr_call_global( - sp, path, vec![]); - let unreachable = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::UnsafeBlock(ast::CompilerGenerated), - span: sp })); - match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable)); - - // Final wrinkle: the self_args are expressions that deref - // down to desired l-values, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); - - //Lastly we create an expression which branches on all discriminants being equal - // if discriminant_test { - // match (...) { - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2, - // ... - // _ => ::core::intrinsics::unreachable() - // } - // } - // else { - // - // } - let all_match = cx.expr_match(sp, match_arg, match_arms); - let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr)); - cx.expr_block( - cx.block_all(sp, index_let_stmts, Some(arm_expr))) - } else if variants.is_empty() { - // As an additional wrinkle, For a zero-variant enum A, - // currently the compiler - // will accept `fn (a: &Self) { match *a { } }` - // but rejects `fn (a: &Self) { match (&*a,) { } }` - // as well as `fn (a: &Self) { match ( *a,) { } }` - // - // This means that the strategy of building up a tuple of - // all Self arguments fails when Self is a zero variant - // enum: rustc rejects the expanded program, even though - // the actual code tends to be impossible to execute (at - // least safely), according to the type system. - // - // The most expedient fix for this is to just let the - // code fall through to the catch-all. But even this is - // error-prone, since the catch-all as defined above would - // generate code like this: - // - // _ => { let __self0 = match *self { }; - // let __self1 = match *__arg_0 { }; - // } - // - // Which is yields bindings for variables which type - // inference cannot resolve to unique types. - // - // One option to the above might be to add explicit type - // annotations. But the *only* reason to go down that path - // would be to try to make the expanded output consistent - // with the case when the number of enum variants >= 1. - // - // That just isn't worth it. In fact, trying to generate - // sensible code for *any* deriving on a zero-variant enum - // does not make sense. But at the same time, for now, we - // do not want to cause a compile failure just because the - // user happened to attach a deriving to their - // zero-variant enum. - // - // Instead, just generate a failing expression for the - // zero variant case, skipping matches and also skipping - // delegating back to the end user code entirely. - // - // (See also #4499 and #12609; note that some of the - // discussions there influence what choice we make here; - // e.g. if we feature-gate `match x { ... }` when x refers - // to an uninhabited type (e.g. a zero-variant enum or a - // type holding such an enum), but do not feature-gate - // zero-variant enums themselves, then attempting to - // derive Debug on such a type could here generate code - // that needs the feature gate enabled.) - - cx.expr_unreachable(sp) - } - else { - - // Final wrinkle: the self_args are expressions that deref - // down to desired l-values, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); - cx.expr_match(sp, match_arg, match_arms) - } - } - - fn expand_static_enum_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[P], - nonself_args: &[P]) - -> P { - let summary = enum_def.variants.iter().map(|v| { - let ident = v.node.name; - let summary = trait_.summarise_struct(cx, &v.node.data); - (ident, v.span, summary) - }).collect(); - self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, - &StaticEnum(enum_def, summary)) - } -} - -#[derive(PartialEq)] // dogfooding! -enum StructType { - Unknown, Record, Tuple -} - -// general helper methods. -impl<'a> TraitDef<'a> { - fn set_expn_info(&self, - cx: &mut ExtCtxt, - mut to_set: Span) -> Span { - let trait_name = match self.path.path.last() { - None => cx.span_bug(self.span, "trait with empty path in generic `derive`"), - Some(name) => *name - }; - to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: to_set, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(intern(&format!("derive({})", trait_name))), - span: Some(self.span), - allow_internal_unstable: false, - } - }); - to_set - } - - fn summarise_struct(&self, - cx: &mut ExtCtxt, - struct_def: &VariantData) -> StaticFields { - let mut named_idents = Vec::new(); - let mut just_spans = Vec::new(); - for field in struct_def.fields(){ - let sp = self.set_expn_info(cx, field.span); - match field.node.kind { - ast::NamedField(ident, _) => named_idents.push((ident, sp)), - ast::UnnamedField(..) => just_spans.push(sp), - } - } - - match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx.span_bug(self.span, - "a struct with named and unnamed \ - fields in generic `derive`"), - // named fields - (_, false) => Named(named_idents), - // tuple structs (includes empty structs) - (_, _) => Unnamed(just_spans) - } - } - - fn create_subpatterns(&self, - cx: &mut ExtCtxt, - field_paths: Vec , - mutbl: ast::Mutability) - -> Vec> { - field_paths.iter().map(|path| { - cx.pat(path.span, - ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None)) - }).collect() - } - - fn create_struct_pattern(&self, - cx: &mut ExtCtxt, - struct_path: ast::Path, - struct_def: &'a VariantData, - prefix: &str, - mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, - P, - &'a [ast::Attribute])>) { - if struct_def.fields().is_empty() { - return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); - } - - let mut paths = Vec::new(); - let mut ident_expr = Vec::new(); - let mut struct_type = Unknown; - - for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = self.set_expn_info(cx, struct_field.span); - let opt_id = match struct_field.node.kind { - ast::NamedField(ident, _) if (struct_type == Unknown || - struct_type == Record) => { - struct_type = Record; - Some(ident) - } - ast::UnnamedField(..) if (struct_type == Unknown || - struct_type == Tuple) => { - struct_type = Tuple; - None - } - _ => { - cx.span_bug(sp, "a struct with named and unnamed fields in `derive`"); - } - }; - let ident = cx.ident_of(&format!("{}_{}", prefix, i)); - paths.push(codemap::Spanned{span: sp, node: ident}); - let val = cx.expr( - sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))))); - ident_expr.push((sp, opt_id, val, &struct_field.node.attrs[..])); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl); - - // struct_type is definitely not Unknown, since struct_def.fields - // must be nonempty to reach here - let pattern = if struct_type == Record { - let field_pats = subpats.into_iter().zip(&ident_expr) - .map(|(pat, &(_, id, _, _))| { - // id is guaranteed to be Some - codemap::Spanned { - span: pat.span, - node: ast::FieldPat { ident: id.unwrap(), pat: pat, is_shorthand: false }, - } - }).collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } else { - cx.pat_enum(self.span, struct_path, subpats) - }; - - (pattern, ident_expr) - } - - fn create_enum_variant_pattern(&self, - cx: &mut ExtCtxt, - enum_ident: ast::Ident, - variant: &'a ast::Variant, - prefix: &str, - mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { - let variant_ident = variant.node.name; - let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); - self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) - } -} - -/* helpful premade recipes */ - -/// Fold the fields. `use_foldl` controls whether this is done -/// left-to-right (`true`) or right-to-left (`false`). -pub fn cs_fold(use_foldl: bool, - mut f: F, - base: P, - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> P where - F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P, -{ - match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { - if use_foldl { - all_fields.iter().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) - }) - } else { - all_fields.iter().rev().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) - }) - } - }, - EnumNonMatchingCollapsed(ref all_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") - } - } -} - - -/// Call the method that is being derived on all the fields, and then -/// process the collected results. i.e. -/// -/// ```ignore -/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1), -/// self_2.method(__arg_1_2, __arg_2_2)]) -/// ``` -#[inline] -pub fn cs_same_method(f: F, - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> P where - F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P, -{ - match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { - // call self_n.method(other_1_n, other_2_n, ...) - let called = all_fields.iter().map(|field| { - cx.expr_method_call(field.span, - field.self_.clone(), - substructure.method_ident, - field.other.iter() - .map(|e| cx.expr_addr_of(field.span, e.clone())) - .collect()) - }).collect(); - - f(cx, trait_span, called) - }, - EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") - } - } -} - -/// Fold together the results of calling the derived method on all the -/// fields. `use_foldl` controls whether this is done left-to-right -/// (`true`) or right-to-left (`false`). -#[inline] -pub fn cs_same_method_fold(use_foldl: bool, - mut f: F, - base: P, - enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> P where - F: FnMut(&mut ExtCtxt, Span, P, P) -> P, -{ - cs_same_method( - |cx, span, vals| { - if use_foldl { - vals.into_iter().fold(base.clone(), |old, new| { - f(cx, span, old, new) - }) - } else { - vals.into_iter().rev().fold(base.clone(), |old, new| { - f(cx, span, old, new) - }) - } - }, - enum_nonmatch_f, - cx, trait_span, substructure) -} - -/// Use a given binop to combine the result of calling the derived method -/// on all the fields. -#[inline] -pub fn cs_binop(binop: ast::BinOp_, base: P, - enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, trait_span: Span, - substructure: &Substructure) -> P { - cs_same_method_fold( - true, // foldl is good enough - |cx, span, old, new| { - cx.expr_binary(span, - binop, - old, new) - - }, - base, - enum_nonmatch_f, - cx, trait_span, substructure) -} - -/// cs_binop with binop == or -#[inline] -pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, span: Span, - substructure: &Substructure) -> P { - cs_binop(ast::BiOr, cx.expr_bool(span, false), - enum_nonmatch_f, - cx, span, substructure) -} - -/// cs_binop with binop == and -#[inline] -pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, span: Span, - substructure: &Substructure) -> P { - cs_binop(ast::BiAnd, cx.expr_bool(span, true), - enum_nonmatch_f, - cx, span, substructure) -} diff --git a/syntex_syntax/src/ext/deriving/generic/ty.rs b/syntex_syntax/src/ext/deriving/generic/ty.rs deleted file mode 100644 index 67826c9c..00000000 --- a/syntex_syntax/src/ext/deriving/generic/ty.rs +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use -//! when specifying impls to be derived. - -pub use self::PtrTy::*; -pub use self::Ty::*; - -use ast; -use ast::{Expr,Generics,Ident}; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use codemap::{Span,respan}; -use owned_slice::OwnedSlice; -use parse::token::special_idents; -use ptr::P; - -/// The types of pointers -#[derive(Clone, Eq, PartialEq)] -pub enum PtrTy<'a> { - /// &'lifetime mut - Borrowed(Option<&'a str>, ast::Mutability), - /// *mut - Raw(ast::Mutability), -} - -/// A path, e.g. `::std::option::Option::` (global). Has support -/// for type parameters and a lifetime. -#[derive(Clone, Eq, PartialEq)] -pub struct Path<'a> { - pub path: Vec<&'a str> , - pub lifetime: Option<&'a str>, - pub params: Vec>>, - pub global: bool, -} - -impl<'a> Path<'a> { - pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> { - Path::new_(path, None, Vec::new(), true) - } - pub fn new_local<'r>(path: &'r str) -> Path<'r> { - Path::new_(vec!( path ), None, Vec::new(), false) - } - pub fn new_<'r>(path: Vec<&'r str> , - lifetime: Option<&'r str>, - params: Vec>>, - global: bool) - -> Path<'r> { - Path { - path: path, - lifetime: lifetime, - params: params, - global: global - } - } - - pub fn to_ty(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> P { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } - pub fn to_path(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> ast::Path { - let idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); - let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - - cx.path_all(span, self.global, idents, lt, tys, Vec::new()) - } -} - -/// A type. Supports pointers, Self, and literals -#[derive(Clone, Eq, PartialEq)] -pub enum Ty<'a> { - Self_, - /// &/Box/ Ty - Ptr(Box>, PtrTy<'a>), - /// mod::mod::Type<[lifetime], [Params...]>, including a plain type - /// parameter, and things like `i32` - Literal(Path<'a>), - /// includes unit - Tuple(Vec> ) -} - -pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { - Borrowed(None, ast::MutImmutable) -} -pub fn borrowed<'r>(ty: Box>) -> Ty<'r> { - Ptr(ty, borrowed_ptrty()) -} - -pub fn borrowed_explicit_self<'r>() -> Option>> { - Some(Some(borrowed_ptrty())) -} - -pub fn borrowed_self<'r>() -> Ty<'r> { - borrowed(Box::new(Self_)) -} - -pub fn nil_ty<'r>() -> Ty<'r> { - Tuple(Vec::new()) -} - -fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option { - match *lt { - Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)), - None => None - } -} - -fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec { - match *lt { - Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)), - None => vec!() - } -} - -impl<'a> Ty<'a> { - pub fn to_ty(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> P { - match *self { - Ptr(ref ty, ref ptr) => { - let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = mk_lifetime(cx, span, lt); - cx.ty_rptr(span, raw_ty, lt, mutbl) - } - Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl) - } - } - Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } - Self_ => { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } - Tuple(ref fields) => { - let ty = ast::TyTup(fields.iter() - .map(|f| f.to_ty(cx, span, self_ty, self_generics)) - .collect()); - cx.ty(span, ty) - } - } - } - - pub fn to_path(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> ast::Path { - match *self { - Self_ => { - let self_params = self_generics.ty_params.map(|ty_param| { - cx.ty_ident(span, ty_param.ident) - }); - let lifetimes = self_generics.lifetimes.iter() - .map(|d| d.lifetime) - .collect(); - - cx.path_all(span, false, vec!(self_ty), lifetimes, - self_params.into_vec(), Vec::new()) - } - Literal(ref p) => { - p.to_path(cx, span, self_ty, self_generics) - } - Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `derive`") } - Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `derive`") } - } - } -} - - -fn mk_ty_param(cx: &ExtCtxt, - span: Span, - name: &str, - bounds: &[Path], - self_ident: Ident, - self_generics: &Generics) - -> ast::TyParam { - let bounds = - bounds.iter().map(|b| { - let path = b.to_path(cx, span, self_ident, self_generics); - cx.typarambound(path) - }).collect(); - cx.typaram(span, cx.ident_of(name), bounds, None) -} - -fn mk_generics(lifetimes: Vec, ty_params: Vec) - -> Generics { - Generics { - lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, - } -} - -/// Lifetimes and bounds on type parameters -#[derive(Clone)] -pub struct LifetimeBounds<'a> { - pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, - pub bounds: Vec<(&'a str, Vec>)>, -} - -impl<'a> LifetimeBounds<'a> { - pub fn empty() -> LifetimeBounds<'a> { - LifetimeBounds { - lifetimes: Vec::new(), bounds: Vec::new() - } - } - pub fn to_generics(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> Generics { - let lifetimes = self.lifetimes.iter().map(|&(ref lt, ref bounds)| { - let bounds = - bounds.iter().map( - |b| cx.lifetime(span, cx.ident_of(*b).name)).collect(); - cx.lifetime_def(span, cx.ident_of(*lt).name, bounds) - }).collect(); - let ty_params = self.bounds.iter().map(|t| { - match *t { - (ref name, ref bounds) => { - mk_ty_param(cx, - span, - *name, - bounds, - self_ty, - self_generics) - } - } - }).collect(); - mk_generics(lifetimes, ty_params) - } -} - -pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) - -> (P, ast::ExplicitSelf) { - // this constructs a fresh `self` path, which will match the fresh `self` binding - // created below. - let self_path = cx.expr_self(span); - match *self_ptr { - None => { - (self_path, respan(span, ast::SelfValue(special_idents::self_))) - } - Some(ref ptr) => { - let self_ty = respan( - span, - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); - ast::SelfRegion(lt, mutbl, special_idents::self_) - } - Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition") - }); - let self_expr = cx.expr_deref(span, self_path); - (self_expr, self_ty) - } - } -} diff --git a/syntex_syntax/src/ext/deriving/hash.rs b/syntex_syntax/src/ext/deriving/hash.rs deleted file mode 100644 index 96be774e..00000000 --- a/syntex_syntax/src/ext/deriving/hash.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr, MutMutable}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use ptr::P; - -pub fn expand_deriving_hash(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - - let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, - vec!(), true); - let arg = Path::new_local("__H"); - let hash_trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path, - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "hash", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![("__H", - vec![path_std!(cx, core::hash::Hasher)])], - }, - explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, MutMutable))), - ret_ty: nil_ty(), - attributes: vec![], - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - - hash_trait_def.expand(cx, mitem, item, push); -} - -fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { - let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`") - }; - let call_hash = |span, thing_expr| { - let hash_path = { - let strs = cx.std_path(&["hash", "Hash", "hash"]); - - cx.expr_path(cx.path_global(span, strs)) - }; - let ref_thing = cx.expr_addr_of(span, thing_expr); - let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone())); - cx.stmt_expr(expr) - }; - let mut stmts = Vec::new(); - - let fields = match *substr.fields { - Struct(ref fs) => fs, - EnumMatching(index, variant, ref fs) => { - // Determine the discriminant. We will feed this value to the byte - // iteration function. - let discriminant = match variant.node.disr_expr { - Some(ref d) => d.clone(), - None => cx.expr_usize(trait_span, index) - }; - - stmts.push(call_hash(trait_span, discriminant)); - - fs - } - _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`") - }; - - for &FieldInfo { ref self_, span, .. } in fields { - stmts.push(call_hash(span, self_.clone())); - } - - cx.expr_block(cx.block(trait_span, stmts, None)) -} diff --git a/syntex_syntax/src/ext/deriving/mod.rs b/syntex_syntax/src/ext/deriving/mod.rs deleted file mode 100644 index d26bb794..00000000 --- a/syntex_syntax/src/ext/deriving/mod.rs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2012-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The compiler code necessary to implement the `#[derive]` extensions. -//! -//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is -//! the standard library, and "std" is the core library. - -use ast::{MetaItem, MetaWord}; -use attr::AttrMetaMethods; -use ext::base::{ExtCtxt, SyntaxEnv, MultiDecorator, MultiItemDecorator, MultiModifier, Annotatable}; -use ext::build::AstBuilder; -use feature_gate; -use codemap::Span; -use parse::token::{intern, intern_and_get_ident}; - -macro_rules! pathvec { - ($($x:ident)::+) => ( - vec![ $( stringify!($x) ),+ ] - ) -} - -macro_rules! path { - ($($x:tt)*) => ( - ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) ) - ) -} - -macro_rules! path_local { - ($x:ident) => ( - ::ext::deriving::generic::ty::Path::new_local(stringify!($x)) - ) -} - -macro_rules! pathvec_std { - ($cx:expr, $first:ident :: $($rest:ident)::+) => ({ - let mut v = pathvec!($($rest)::+); - if let Some(s) = $cx.crate_root { - v.insert(0, s); - } - v - }) -} - -macro_rules! path_std { - ($($x:tt)*) => ( - ::ext::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) ) - ) -} - -pub mod bounds; -pub mod clone; -pub mod encodable; -pub mod decodable; -pub mod hash; -pub mod debug; -pub mod default; -pub mod primitive; - -#[path="cmp/partial_eq.rs"] -pub mod partial_eq; -#[path="cmp/eq.rs"] -pub mod eq; -#[path="cmp/partial_ord.rs"] -pub mod partial_ord; -#[path="cmp/ord.rs"] -pub mod ord; - - -pub mod generic; - -fn expand_derive(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - annotatable: Annotatable) - -> Annotatable { - annotatable.map_item_or(|item| { - item.map(|mut item| { - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); - } - - let traits = mitem.meta_item_list().unwrap_or(&[]); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); - } - - for titem in traits.iter().rev() { - let tname = match titem.node { - MetaWord(ref tname) => tname, - _ => { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - } - }; - - if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "custom_derive", - titem.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CUSTOM_DERIVE); - continue; - } - - // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, - intern_and_get_ident(&format!("derive_{}", tname))))); - } - - item - }) - }, |a| { - cx.span_err(span, "`derive` can only be applied to items"); - a - }) -} - -macro_rules! derive_traits { - ($( $name:expr => $func:path, )+) => { - pub fn register_all(env: &mut SyntaxEnv) { - // Define the #[derive_*] extensions. - $({ - struct DeriveExtension; - - impl MultiItemDecorator for DeriveExtension { - fn expand(&self, - ecx: &mut ExtCtxt, - sp: Span, - mitem: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable)) { - warn_if_deprecated(ecx, sp, $name); - $func(ecx, sp, mitem, annotatable, push); - } - } - - env.insert(intern(concat!("derive_", $name)), - MultiDecorator(Box::new(DeriveExtension))); - })+ - - env.insert(intern("derive"), - MultiModifier(Box::new(expand_derive))); - } - - fn is_builtin_trait(name: &str) -> bool { - match name { - $( $name )|+ => true, - _ => false, - } - } - } -} - -derive_traits! { - "Clone" => clone::expand_deriving_clone, - - "Hash" => hash::expand_deriving_hash, - - "RustcEncodable" => encodable::expand_deriving_rustc_encodable, - - "RustcDecodable" => decodable::expand_deriving_rustc_decodable, - - "PartialEq" => partial_eq::expand_deriving_partial_eq, - "Eq" => eq::expand_deriving_eq, - "PartialOrd" => partial_ord::expand_deriving_partial_ord, - "Ord" => ord::expand_deriving_ord, - - "Debug" => debug::expand_deriving_debug, - - "Default" => default::expand_deriving_default, - - "FromPrimitive" => primitive::expand_deriving_from_primitive, - - "Send" => bounds::expand_deriving_unsafe_bound, - "Sync" => bounds::expand_deriving_unsafe_bound, - "Copy" => bounds::expand_deriving_copy, - - // deprecated - "Encodable" => encodable::expand_deriving_encodable, - "Decodable" => decodable::expand_deriving_decodable, -} - -#[inline] // because `name` is a compile-time constant -fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { - if let Some(replacement) = match name { - "Encodable" => Some("RustcEncodable"), - "Decodable" => Some("RustcDecodable"), - _ => None, - } { - ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})", - name, replacement)); - } -} diff --git a/syntex_syntax/src/ext/deriving/primitive.rs b/syntex_syntax/src/ext/deriving/primitive.rs deleted file mode 100644 index 07b58778..00000000 --- a/syntex_syntax/src/ext/deriving/primitive.rs +++ /dev/null @@ -1,141 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use ast; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::num::FromPrimitive), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "from_i64", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: vec!(Literal(path_local!(i64))), - ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec!(Box::new(Self_)), - true)), - // #[inline] liable to cause code-bloat - attributes: attrs.clone(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|c, s, sub| { - cs_from("i64", c, s, sub) - })), - }, - MethodDef { - name: "from_u64", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: vec!(Literal(path_local!(u64))), - ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec!(Box::new(Self_)), - true)), - // #[inline] liable to cause code-bloat - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|c, s, sub| { - cs_from("u64", c, s, sub) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { - let n = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`") - }; - - match *substr.fields { - StaticStruct(..) => { - cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs"); - return cx.expr_fail(trait_span, InternedString::new("")); - } - StaticEnum(enum_def, _) => { - if enum_def.variants.is_empty() { - cx.span_err(trait_span, - "`FromPrimitive` cannot be derived for enums with no variants"); - return cx.expr_fail(trait_span, InternedString::new("")); - } - - let mut arms = Vec::new(); - - for variant in &enum_def.variants { - let def = &variant.node.data; - if !def.is_unit() { - cx.span_err(trait_span, "`FromPrimitive` cannot be derived \ - for enums with non-unit variants"); - return cx.expr_fail(trait_span, - InternedString::new("")); - } - - let span = variant.span; - - // expr for `$n == $variant as $name` - let path = cx.path(span, vec![substr.type_ident, variant.node.name]); - let variant = cx.expr_path(path); - let ty = cx.ty_ident(span, cx.ident_of(name)); - let cast = cx.expr_cast(span, variant.clone(), ty); - let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast); - - // expr for `Some($variant)` - let body = cx.expr_some(span, variant); - - // arm for `_ if $guard => $body` - let arm = ast::Arm { - attrs: vec!(), - pats: vec!(cx.pat_wild(span)), - guard: Some(guard), - body: body, - }; - - arms.push(arm); - } - - // arm for `_ => None` - let arm = ast::Arm { - attrs: vec!(), - pats: vec!(cx.pat_wild(trait_span)), - guard: None, - body: cx.expr_none(trait_span), - }; - arms.push(arm); - - cx.expr_match(trait_span, n.clone(), arms) - } - _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)") - } -} diff --git a/syntex_syntax/src/ext/env.rs b/syntex_syntax/src/ext/env.rs deleted file mode 100644 index d85071e7..00000000 --- a/syntex_syntax/src/ext/env.rs +++ /dev/null @@ -1,106 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* - * The compiler code necessary to support the env! extension. Eventually this - * should all get sucked into either the compiler syntax extension plugin - * interface. - */ - -use ast; -use codemap::Span; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use parse::token; - -use std::env; - -pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { - let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { - None => return DummyResult::expr(sp), - Some(v) => v - }; - - let e = match env::var(&var[..]) { - Err(..) => { - cx.expr_path(cx.path_all(sp, - true, - cx.std_path(&["option", "Option", "None"]), - Vec::new(), - vec!(cx.ty_rptr(sp, - cx.ty_ident(sp, - cx.ident_of("str")), - Some(cx.lifetime(sp, - cx.ident_of( - "'static").name)), - ast::MutImmutable)), - Vec::new())) - } - Ok(s) => { - cx.expr_call_global(sp, - cx.std_path(&["option", "Option", "Some"]), - vec!(cx.expr_str(sp, - token::intern_and_get_ident( - &s[..])))) - } - }; - MacEager::expr(e) -} - -pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { - let mut exprs = match get_exprs_from_tts(cx, sp, tts) { - Some(ref exprs) if exprs.is_empty() => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); - } - None => return DummyResult::expr(sp), - Some(exprs) => exprs.into_iter() - }; - - let var = match expr_to_string(cx, - exprs.next().unwrap(), - "expected string literal") { - None => return DummyResult::expr(sp), - Some((v, _style)) => v - }; - let msg = match exprs.next() { - None => { - token::intern_and_get_ident(&format!("environment variable `{}` \ - not defined", - var)) - } - Some(second) => { - match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::expr(sp), - Some((s, _style)) => s - } - } - }; - - match exprs.next() { - None => {} - Some(_) => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); - } - } - - let e = match env::var(&var[..]) { - Err(_) => { - cx.span_err(sp, &msg); - cx.expr_usize(sp, 0) - } - Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s)) - }; - MacEager::expr(e) -} diff --git a/syntex_syntax/src/ext/expand.rs b/syntex_syntax/src/ext/expand.rs index 573f4cfe..743bcda1 100644 --- a/syntex_syntax/src/ext/expand.rs +++ b/syntex_syntax/src/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Block, Crate, DeclLocal, ExprMac, PatMac}; +use ast::{Block, Crate, DeclLocal, PatMac}; use ast::{Local, Ident, Mac_, Name}; use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac}; use ast::{StmtExpr, StmtSemi}; @@ -21,7 +21,7 @@ use attr::{AttrMetaMethods, WithAttrs}; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; -use feature_gate::{self, Features, GatedCfgAttr}; +use feature_gate::{self, Features}; use fold; use fold::*; use util::move_map::MoveMap; @@ -1276,15 +1276,11 @@ impl<'feat> ExpansionConfig<'feat> { } } -pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, - cfg: ExpansionConfig<'feat>, - // these are the macros being imported to this crate: - imported_macros: Vec, - user_exts: Vec, - feature_gated_cfgs: &mut Vec, - c: Crate) -> (Crate, HashSet) { - let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg, - feature_gated_cfgs); +pub fn expand_crate(mut cx: ExtCtxt, + // these are the macros being imported to this crate: + imported_macros: Vec, + user_exts: Vec, + c: Crate) -> (Crate, HashSet) { if std_inject::no_core(&c) { cx.crate_root = None; } else if std_inject::no_std(&c) { @@ -1305,7 +1301,7 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, let mut ret = expander.fold_crate(c); ret.exported_macros = expander.cx.exported_macros.clone(); - parse_sess.span_diagnostic.handler().abort_if_errors(); + cx.parse_sess.span_diagnostic.abort_if_errors(); ret }; return (ret, cx.syntax_env.names); @@ -1401,6 +1397,7 @@ mod tests { use ast; use ast::Name; use codemap; + use ext::base::ExtCtxt; use ext::mtwt; use fold::Folder; use parse; @@ -1471,7 +1468,9 @@ mod tests { src, Vec::new(), &sess); // should fail: - expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast); } // make sure that macros can't escape modules @@ -1484,7 +1483,9 @@ mod tests { "".to_string(), src, Vec::new(), &sess); - expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast); } // macro_use modules should allow macros to escape @@ -1496,14 +1497,18 @@ mod tests { "".to_string(), src, Vec::new(), &sess); - expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast); + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast); } fn expand_crate_str(crate_str: String) -> ast::Crate { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0 + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast).0 } // find the pat_ident paths in a crate diff --git a/syntex_syntax/src/ext/format.rs b/syntex_syntax/src/ext/format.rs deleted file mode 100644 index 904cf0c4..00000000 --- a/syntex_syntax/src/ext/format.rs +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use self::ArgumentType::*; -use self::Position::*; - -use ast; -use codemap::{Span, respan}; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use fmt_macros as parse; -use fold::Folder; -use parse::token::special_idents; -use parse::token; -use ptr::P; - -use std::collections::HashMap; - -#[derive(PartialEq)] -enum ArgumentType { - Known(String), - Unsigned -} - -enum Position { - Exact(usize), - Named(String), -} - -struct Context<'a, 'b:'a> { - ecx: &'a mut ExtCtxt<'b>, - /// The macro's call site. References to unstable formatting internals must - /// use this span to pass the stability checker. - macsp: Span, - /// The span of the format string literal. - fmtsp: Span, - - /// Parsed argument expressions and the types that we've found so far for - /// them. - args: Vec>, - arg_types: Vec>, - /// Parsed named expressions and the types that we've found for them so far. - /// Note that we keep a side-array of the ordering of the named arguments - /// found to be sure that we can translate them in the same order that they - /// were declared in. - names: HashMap>, - name_types: HashMap, - name_ordering: Vec, - - /// The latest consecutive literal strings, or empty if there weren't any. - literal: String, - - /// Collection of the compiled `rt::Argument` structures - pieces: Vec>, - /// Collection of string literals - str_pieces: Vec>, - /// Stays `true` if all formatting parameters are default (as in "{}{}"). - all_pieces_simple: bool, - - name_positions: HashMap, - - /// Updated as arguments are consumed or methods are entered - nest_level: usize, - next_arg: usize, -} - -/// Parses the arguments from the given list of tokens, returning None -/// if there's a parse error so we can continue parsing other format! -/// expressions. -/// -/// If parsing succeeds, the return value is: -/// ```ignore -/// Some((fmtstr, unnamed arguments, ordering of named arguments, -/// named arguments)) -/// ``` -fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Option<(P, Vec>, Vec, - HashMap>)> { - let mut args = Vec::new(); - let mut names = HashMap::>::new(); - let mut order = Vec::new(); - - let mut p = ecx.new_parser_from_tts(tts); - - if p.token == token::Eof { - ecx.span_err(sp, "requires at least a format string argument"); - return None; - } - let fmtstr = panictry!(p.parse_expr()); - let mut named = false; - while p.token != token::Eof { - if !panictry!(p.eat(&token::Comma)) { - ecx.span_err(sp, "expected token: `,`"); - return None; - } - if p.token == token::Eof { break } // accept trailing commas - if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) { - named = true; - let ident = match p.token { - token::Ident(i, _) => { - panictry!(p.bump()); - i - } - _ if named => { - ecx.span_err(p.span, - "expected ident, positional arguments \ - cannot follow named arguments"); - return None; - } - _ => { - ecx.span_err(p.span, - &format!("expected ident for named argument, found `{}`", - p.this_token_to_string())); - return None; - } - }; - let name: &str = &ident.name.as_str(); - - panictry!(p.expect(&token::Eq)); - let e = panictry!(p.parse_expr()); - match names.get(name) { - None => {} - Some(prev) => { - ecx.span_err(e.span, - &format!("duplicate argument named `{}`", - name)); - ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here"); - continue - } - } - order.push(name.to_string()); - names.insert(name.to_string(), e); - } else { - args.push(panictry!(p.parse_expr())); - } - } - Some((fmtstr, args, order, names)) -} - -impl<'a, 'b> Context<'a, 'b> { - /// Verifies one piece of a parse string. All errors are not emitted as - /// fatal so we can continue giving errors about this and possibly other - /// format strings. - fn verify_piece(&mut self, p: &parse::Piece) { - match *p { - parse::String(..) => {} - parse::NextArgument(ref arg) => { - // width/precision first, if they have implicit positional - // parameters it makes more sense to consume them first. - self.verify_count(arg.format.width); - self.verify_count(arg.format.precision); - - // argument second, if it's an implicit positional parameter - // it's written second, so it should come after width/precision. - let pos = match arg.position { - parse::ArgumentNext => { - let i = self.next_arg; - if self.check_positional_ok() { - self.next_arg += 1; - } - Exact(i) - } - parse::ArgumentIs(i) => Exact(i), - parse::ArgumentNamed(s) => Named(s.to_string()), - }; - - let ty = Known(arg.format.ty.to_string()); - self.verify_arg_type(pos, ty); - } - } - } - - fn verify_count(&mut self, c: parse::Count) { - match c { - parse::CountImplied | parse::CountIs(..) => {} - parse::CountIsParam(i) => { - self.verify_arg_type(Exact(i), Unsigned); - } - parse::CountIsName(s) => { - self.verify_arg_type(Named(s.to_string()), Unsigned); - } - parse::CountIsNextParam => { - if self.check_positional_ok() { - let next_arg = self.next_arg; - self.verify_arg_type(Exact(next_arg), Unsigned); - self.next_arg += 1; - } - } - } - } - - fn check_positional_ok(&mut self) -> bool { - if self.nest_level != 0 { - self.ecx.span_err(self.fmtsp, "cannot use implicit positional \ - arguments nested inside methods"); - false - } else { - true - } - } - - fn describe_num_args(&self) -> String { - match self.args.len() { - 0 => "no arguments given".to_string(), - 1 => "there is 1 argument".to_string(), - x => format!("there are {} arguments", x), - } - } - - fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) { - match arg { - Exact(arg) => { - if self.args.len() <= arg { - let msg = format!("invalid reference to argument `{}` ({})", - arg, self.describe_num_args()); - - self.ecx.span_err(self.fmtsp, &msg[..]); - return; - } - { - let arg_type = match self.arg_types[arg] { - None => None, - Some(ref x) => Some(x) - }; - self.verify_same(self.args[arg].span, &ty, arg_type); - } - if self.arg_types[arg].is_none() { - self.arg_types[arg] = Some(ty); - } - } - - Named(name) => { - let span = match self.names.get(&name) { - Some(e) => e.span, - None => { - let msg = format!("there is no argument named `{}`", name); - self.ecx.span_err(self.fmtsp, &msg[..]); - return; - } - }; - self.verify_same(span, &ty, self.name_types.get(&name)); - if !self.name_types.contains_key(&name) { - self.name_types.insert(name.clone(), ty); - } - // Assign this named argument a slot in the arguments array if - // it hasn't already been assigned a slot. - if !self.name_positions.contains_key(&name) { - let slot = self.name_positions.len(); - self.name_positions.insert(name, slot); - } - } - } - } - - /// When we're keeping track of the types that are declared for certain - /// arguments, we assume that `None` means we haven't seen this argument - /// yet, `Some(None)` means that we've seen the argument, but no format was - /// specified, and `Some(Some(x))` means that the argument was declared to - /// have type `x`. - /// - /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true - /// that: `Some(None) == Some(Some(x))` - fn verify_same(&self, - sp: Span, - ty: &ArgumentType, - before: Option<&ArgumentType>) { - let cur = match before { - None => return, - Some(t) => t, - }; - if *ty == *cur { - return - } - match (cur, ty) { - (&Known(ref cur), &Known(ref ty)) => { - self.ecx.span_err(sp, - &format!("argument redeclared with type `{}` when \ - it was previously `{}`", - *ty, - *cur)); - } - (&Known(ref cur), _) => { - self.ecx.span_err(sp, - &format!("argument used to format with `{}` was \ - attempted to not be used for formatting", - *cur)); - } - (_, &Known(ref ty)) => { - self.ecx.span_err(sp, - &format!("argument previously used as a format \ - argument attempted to be used as `{}`", - *ty)); - } - (_, _) => { - self.ecx.span_err(sp, "argument declared with multiple formats"); - } - } - } - - fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec { - ecx.std_path(&["fmt", "rt", "v1", s]) - } - - fn trans_count(&self, c: parse::Count) -> P { - let sp = self.macsp; - let count = |c, arg| { - let mut path = Context::rtpath(self.ecx, "Count"); - path.push(self.ecx.ident_of(c)); - match arg { - Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]), - None => self.ecx.expr_path(self.ecx.path_global(sp, path)), - } - }; - match c { - parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))), - parse::CountIsParam(i) => { - count("Param", Some(self.ecx.expr_usize(sp, i))) - } - parse::CountImplied => count("Implied", None), - parse::CountIsNextParam => count("NextParam", None), - parse::CountIsName(n) => { - let i = match self.name_positions.get(n) { - Some(&i) => i, - None => 0, // error already emitted elsewhere - }; - let i = i + self.args.len(); - count("Param", Some(self.ecx.expr_usize(sp, i))) - } - } - } - - /// Translate the accumulated string literals to a literal expression - fn trans_literal_string(&mut self) -> P { - let sp = self.fmtsp; - let s = token::intern_and_get_ident(&self.literal); - self.literal.clear(); - self.ecx.expr_str(sp, s) - } - - /// Translate a `parse::Piece` to a static `rt::Argument` or append - /// to the `literal` string. - fn trans_piece(&mut self, piece: &parse::Piece) -> Option> { - let sp = self.macsp; - match *piece { - parse::String(s) => { - self.literal.push_str(s); - None - } - parse::NextArgument(ref arg) => { - // Translate the position - let pos = { - let pos = |c, arg| { - let mut path = Context::rtpath(self.ecx, "Position"); - path.push(self.ecx.ident_of(c)); - match arg { - Some(i) => { - let arg = self.ecx.expr_usize(sp, i); - self.ecx.expr_call_global(sp, path, vec![arg]) - } - None => { - self.ecx.expr_path(self.ecx.path_global(sp, path)) - } - } - }; - match arg.position { - // These two have a direct mapping - parse::ArgumentNext => pos("Next", None), - parse::ArgumentIs(i) => pos("At", Some(i)), - - // Named arguments are converted to positional arguments - // at the end of the list of arguments - parse::ArgumentNamed(n) => { - let i = match self.name_positions.get(n) { - Some(&i) => i, - None => 0, // error already emitted elsewhere - }; - let i = i + self.args.len(); - pos("At", Some(i)) - } - } - }; - - let simple_arg = parse::Argument { - position: parse::ArgumentNext, - format: parse::FormatSpec { - fill: arg.format.fill, - align: parse::AlignUnknown, - flags: 0, - precision: parse::CountImplied, - width: parse::CountImplied, - ty: arg.format.ty - } - }; - - let fill = match arg.format.fill { Some(c) => c, None => ' ' }; - - if *arg != simple_arg || fill != ' ' { - self.all_pieces_simple = false; - } - - // Translate the format - let fill = self.ecx.expr_lit(sp, ast::LitChar(fill)); - let align = |name| { - let mut p = Context::rtpath(self.ecx, "Alignment"); - p.push(self.ecx.ident_of(name)); - self.ecx.path_global(sp, p) - }; - let align = match arg.format.align { - parse::AlignLeft => align("Left"), - parse::AlignRight => align("Right"), - parse::AlignCenter => align("Center"), - parse::AlignUnknown => align("Unknown"), - }; - let align = self.ecx.expr_path(align); - let flags = self.ecx.expr_u32(sp, arg.format.flags); - let prec = self.trans_count(arg.format.precision); - let width = self.trans_count(arg.format.width); - let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec")); - let fmt = self.ecx.expr_struct(sp, path, vec!( - self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), - self.ecx.field_imm(sp, self.ecx.ident_of("align"), align), - self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags), - self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec), - self.ecx.field_imm(sp, self.ecx.ident_of("width"), width))); - - let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument")); - Some(self.ecx.expr_struct(sp, path, vec!( - self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), - self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt)))) - } - } - } - - fn static_array(ecx: &mut ExtCtxt, - name: &str, - piece_ty: P, - pieces: Vec>) - -> P { - let sp = piece_ty.span; - let ty = ecx.ty_rptr(sp, - ecx.ty(sp, ast::TyVec(piece_ty)), - Some(ecx.lifetime(sp, special_idents::static_lifetime.name)), - ast::MutImmutable); - let slice = ecx.expr_vec_slice(sp, pieces); - // static instead of const to speed up codegen by not requiring this to be inlined - let st = ast::ItemStatic(ty, ast::MutImmutable, slice); - - let name = ecx.ident_of(name); - let item = ecx.item(sp, name, vec![], st); - let decl = respan(sp, ast::DeclItem(item)); - - // Wrap the declaration in a block so that it forms a single expression. - ecx.expr_block(ecx.block(sp, - vec![P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], - Some(ecx.expr_ident(sp, name)))) - } - - /// Actually builds the expression which the iformat! block will be expanded - /// to - fn into_expr(mut self) -> P { - let mut locals = Vec::new(); - let mut names = vec![None; self.name_positions.len()]; - let mut pats = Vec::new(); - let mut heads = Vec::new(); - - // First, build up the static array which will become our precompiled - // format "string" - let static_lifetime = self.ecx.lifetime(self.fmtsp, special_idents::static_lifetime.name); - let piece_ty = self.ecx.ty_rptr( - self.fmtsp, - self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")), - Some(static_lifetime), - ast::MutImmutable); - let pieces = Context::static_array(self.ecx, - "__STATIC_FMTSTR", - piece_ty, - self.str_pieces); - - - // Right now there is a bug such that for the expression: - // foo(bar(&1)) - // the lifetime of `1` doesn't outlast the call to `bar`, so it's not - // valid for the call to `foo`. To work around this all arguments to the - // format! string are shoved into locals. Furthermore, we shove the address - // of each variable because we don't want to move out of the arguments - // passed to this function. - for (i, e) in self.args.into_iter().enumerate() { - let arg_ty = match self.arg_types[i].as_ref() { - Some(ty) => ty, - None => continue // error already generated - }; - - let name = self.ecx.ident_of(&format!("__arg{}", i)); - pats.push(self.ecx.pat_ident(e.span, name)); - locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, - self.ecx.expr_ident(e.span, name))); - heads.push(self.ecx.expr_addr_of(e.span, e)); - } - for name in &self.name_ordering { - let e = match self.names.remove(name) { - Some(e) => e, - None => continue - }; - let arg_ty = match self.name_types.get(name) { - Some(ty) => ty, - None => continue - }; - - let lname = self.ecx.ident_of(&format!("__arg{}", - *name)); - pats.push(self.ecx.pat_ident(e.span, lname)); - names[*self.name_positions.get(name).unwrap()] = - Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, - self.ecx.expr_ident(e.span, lname))); - heads.push(self.ecx.expr_addr_of(e.span, e)); - } - - // Now create a vector containing all the arguments - let args = locals.into_iter().chain(names.into_iter().map(|a| a.unwrap())); - - let args_array = self.ecx.expr_vec(self.fmtsp, args.collect()); - - // Constructs an AST equivalent to: - // - // match (&arg0, &arg1) { - // (tmp0, tmp1) => args_array - // } - // - // It was: - // - // let tmp0 = &arg0; - // let tmp1 = &arg1; - // args_array - // - // Because of #11585 the new temporary lifetime rule, the enclosing - // statements for these temporaries become the let's themselves. - // If one or more of them are RefCell's, RefCell borrow() will also - // end there; they don't last long enough for args_array to use them. - // The match expression solves the scope problem. - // - // Note, it may also very well be transformed to: - // - // match arg0 { - // ref tmp0 => { - // match arg1 => { - // ref tmp1 => args_array } } } - // - // But the nested match expression is proved to perform not as well - // as series of let's; the first approach does. - let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, vec!(pat), args_array); - let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads)); - let result = self.ecx.expr_match(self.fmtsp, head, vec!(arm)); - - let args_slice = self.ecx.expr_addr_of(self.fmtsp, result); - - // Now create the fmt::Arguments struct with all our locals we created. - let (fn_name, fn_args) = if self.all_pieces_simple { - ("new_v1", vec![pieces, args_slice]) - } else { - // Build up the static array which will store our precompiled - // nonstandard placeholders, if there are any. - let piece_ty = self.ecx.ty_path(self.ecx.path_global( - self.macsp, - Context::rtpath(self.ecx, "Argument"))); - let fmt = Context::static_array(self.ecx, - "__STATIC_FMTARGS", - piece_ty, - self.pieces); - - ("new_v1_formatted", vec![pieces, args_slice, fmt]) - }; - - let path = self.ecx.std_path(&["fmt", "Arguments", fn_name]); - self.ecx.expr_call_global(self.macsp, path, fn_args) - } - - fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span, - ty: &ArgumentType, arg: P) - -> P { - let trait_ = match *ty { - Known(ref tyname) => { - match &tyname[..] { - "" => "Display", - "?" => "Debug", - "e" => "LowerExp", - "E" => "UpperExp", - "o" => "Octal", - "p" => "Pointer", - "b" => "Binary", - "x" => "LowerHex", - "X" => "UpperHex", - _ => { - ecx.span_err(sp, - &format!("unknown format trait `{}`", - *tyname)); - "Dummy" - } - } - } - Unsigned => { - let path = ecx.std_path(&["fmt", "ArgumentV1", "from_usize"]); - return ecx.expr_call_global(macsp, path, vec![arg]) - } - }; - - let path = ecx.std_path(&["fmt", trait_, "fmt"]); - let format_fn = ecx.path_global(sp, path); - let path = ecx.std_path(&["fmt", "ArgumentV1", "new"]); - ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)]) - } -} - -pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) - -> Box { - - match parse_args(ecx, sp, tts) { - Some((efmt, args, order, names)) => { - MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, - args, order, names)) - } - None => DummyResult::expr(sp) - } -} - -/// Take the various parts of `format_args!(efmt, args..., name=names...)` -/// and construct the appropriate formatting expression. -pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, - efmt: P, - args: Vec>, - name_ordering: Vec, - names: HashMap>) - -> P { - let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect(); - let macsp = ecx.call_site(); - // Expand the format literal so that efmt.span will have a backtrace. This - // is essential for locating a bug when the format literal is generated in - // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")). - let efmt = ecx.expander().fold_expr(efmt); - let mut cx = Context { - ecx: ecx, - args: args, - arg_types: arg_types, - names: names, - name_positions: HashMap::new(), - name_types: HashMap::new(), - name_ordering: name_ordering, - nest_level: 0, - next_arg: 0, - literal: String::new(), - pieces: Vec::new(), - str_pieces: Vec::new(), - all_pieces_simple: true, - macsp: macsp, - fmtsp: efmt.span, - }; - let fmt = match expr_to_string(cx.ecx, - efmt, - "format argument must be a string literal.") { - Some((fmt, _)) => fmt, - None => return DummyResult::raw_expr(sp) - }; - - let mut parser = parse::Parser::new(&fmt); - - loop { - match parser.next() { - Some(piece) => { - if !parser.errors.is_empty() { break } - cx.verify_piece(&piece); - match cx.trans_piece(&piece) { - Some(piece) => { - let s = cx.trans_literal_string(); - cx.str_pieces.push(s); - cx.pieces.push(piece); - } - None => {} - } - } - None => break - } - } - if !parser.errors.is_empty() { - cx.ecx.span_err(cx.fmtsp, &format!("invalid format string: {}", - parser.errors.remove(0))); - return DummyResult::raw_expr(sp); - } - if !cx.literal.is_empty() { - let s = cx.trans_literal_string(); - cx.str_pieces.push(s); - } - - // Make sure that all arguments were used and all arguments have types. - for (i, ty) in cx.arg_types.iter().enumerate() { - if ty.is_none() { - cx.ecx.span_err(cx.args[i].span, "argument never used"); - } - } - for (name, e) in &cx.names { - if !cx.name_types.contains_key(name) { - cx.ecx.span_err(e.span, "named argument never used"); - } - } - - cx.into_expr() -} diff --git a/syntex_syntax/src/ext/log_syntax.rs b/syntex_syntax/src/ext/log_syntax.rs deleted file mode 100644 index 5f7ce8d9..00000000 --- a/syntex_syntax/src/ext/log_syntax.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use codemap; -use ext::base; -use feature_gate; -use print; - -pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, - sp: codemap::Span, - tts: &[ast::TokenTree]) - -> Box { - if !cx.ecfg.enable_log_syntax() { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "log_syntax", - sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_LOG_SYNTAX); - return base::DummyResult::any(sp); - } - - println!("{}", print::pprust::tts_to_string(tts)); - - // any so that `log_syntax` can be invoked as an expression and item. - base::DummyResult::any(sp) -} diff --git a/syntex_syntax/src/ext/quote.rs b/syntex_syntax/src/ext/quote.rs index 496f6a42..0c3a8b05 100644 --- a/syntex_syntax/src/ext/quote.rs +++ b/syntex_syntax/src/ext/quote.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Path, Stmt, TokenTree, Ty}; +use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, TokenTree, Ty}; use codemap::Span; use ext::base::ExtCtxt; use ext::base; @@ -33,7 +33,7 @@ pub mod rt { use ptr::P; use std::rc::Rc; - use ast::{TokenTree, Expr}; + use ast::TokenTree; pub use parse::new_parser_from_tts; pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP}; diff --git a/syntex_syntax/src/ext/trace_macros.rs b/syntex_syntax/src/ext/trace_macros.rs deleted file mode 100644 index 628b88d1..00000000 --- a/syntex_syntax/src/ext/trace_macros.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::TokenTree; -use codemap::Span; -use ext::base::ExtCtxt; -use ext::base; -use feature_gate; -use parse::token::keywords; - - -pub fn expand_trace_macros(cx: &mut ExtCtxt, - sp: Span, - tt: &[TokenTree]) - -> Box { - if !cx.ecfg.enable_trace_macros() { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "trace_macros", - sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_TRACE_MACROS); - return base::DummyResult::any(sp); - } - - match (tt.len(), tt.first()) { - (1, Some(&TokenTree::Token(_, ref tok))) if tok.is_keyword(keywords::True) => { - cx.set_trace_macros(true); - } - (1, Some(&TokenTree::Token(_, ref tok))) if tok.is_keyword(keywords::False) => { - cx.set_trace_macros(false); - } - _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"), - } - - base::DummyResult::any(sp) -} diff --git a/syntex_syntax/src/ext/tt/macro_parser.rs b/syntex_syntax/src/ext/tt/macro_parser.rs index 5b8307eb..fb091180 100644 --- a/syntex_syntax/src/ext/tt/macro_parser.rs +++ b/syntex_syntax/src/ext/tt/macro_parser.rs @@ -79,13 +79,13 @@ pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; use ast; -use ast::{TokenTree, Name}; -use codemap::{BytePos, mk_sp, Span}; +use ast::{TokenTree, Name, Ident}; +use codemap::{BytePos, mk_sp, Span, Spanned}; use codemap; use parse::lexer::*; //resolve bug? use parse::ParseSess; use parse::parser::{LifetimeAndTypesWithoutColons, Parser}; -use parse::token::{Eof, DocComment, MatchNt, SubstNt}; +use parse::token::{DocComment, MatchNt, SubstNt}; use parse::token::{Token, Nonterminal}; use parse::token; use print::pprust; @@ -526,7 +526,10 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => match p.token { - token::Ident(sn,b) => { panictry!(p.bump()); token::NtIdent(Box::new(sn),b) } + token::Ident(sn,b) => { + panictry!(p.bump()); + token::NtIdent(Box::new(Spanned::{node: sn, span: p.span}),b) + } _ => { let token_str = pprust::token_to_string(&p.token); panic!(p.fatal(&format!("expected ident, found {}", diff --git a/syntex_syntax/src/ext/tt/transcribe.rs b/syntex_syntax/src/ext/tt/transcribe.rs index 0fc31f3f..8878c606 100644 --- a/syntex_syntax/src/ext/tt/transcribe.rs +++ b/syntex_syntax/src/ext/tt/transcribe.rs @@ -12,9 +12,9 @@ use self::LockstepIterSize::*; use ast; use ast::{TokenTree, Ident, Name}; use codemap::{Span, DUMMY_SP}; -use diagnostic::SpanHandler; +use errors::Handler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; -use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt}; +use parse::token::{DocComment, MatchNt, SubstNt}; use parse::token::{Token, NtIdent, SpecialMacroVar}; use parse::token; use parse::lexer::TokenAndSpan; @@ -34,7 +34,7 @@ struct TtFrame { #[derive(Clone)] pub struct TtReader<'a> { - pub sp_diag: &'a SpanHandler, + pub sp_diag: &'a Handler, /// the unzipped tree: stack: Vec, /* for MBE-style macro transcription */ @@ -55,7 +55,7 @@ pub struct TtReader<'a> { /// This can do Macro-By-Example transcription. On the other hand, if /// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can /// (and should) be None. -pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler, +pub fn new_tt_reader<'a>(sp_diag: &'a Handler, interp: Option>>, imported_from: Option, src: Vec) @@ -69,7 +69,7 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler, /// This can do Macro-By-Example transcription. On the other hand, if /// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can /// (and should) be None. -pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a SpanHandler, +pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a Handler, interp: Option>>, imported_from: Option, src: Vec, @@ -293,8 +293,8 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { // (a) idents can be in lots of places, so it'd be a pain // (b) we actually can, since it's a token. MatchedNonterminal(NtIdent(ref sn, b)) => { - r.cur_span = sp; - r.cur_tok = token::Ident(**sn, b); + r.cur_span = sn.span; + r.cur_tok = token::Ident(sn.node, b); return ret_val; } MatchedNonterminal(ref other_whole_nt) => { diff --git a/syntex_syntax/src/feature_gate.rs b/syntex_syntax/src/feature_gate.rs index c456b7dc..4ea0fd76 100644 --- a/syntex_syntax/src/feature_gate.rs +++ b/syntex_syntax/src/feature_gate.rs @@ -32,7 +32,7 @@ use ast; use attr; use attr::AttrMetaMethods; use codemap::{CodeMap, Span}; -use diagnostic::SpanHandler; +use errors::Handler; use visit; use visit::{FnKind, Visitor}; use parse::token::InternedString; @@ -82,7 +82,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status ("advanced_slice_patterns", "1.0.0", Some(23121), Active), ("tuple_indexing", "1.0.0", None, Accepted), ("associated_types", "1.0.0", None, Accepted), - ("visible_private_types", "1.0.0", Some(29627), Active), + ("visible_private_types", "1.0.0", None, Removed), ("slicing_syntax", "1.0.0", None, Accepted), ("box_syntax", "1.0.0", Some(27779), Active), ("placement_in_syntax", "1.0.0", Some(27779), Active), @@ -230,6 +230,15 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // Allow attributes on expressions and non-item statements ("stmt_expr_attributes", "1.6.0", Some(15701), Active), + + // Allows `#[deprecated]` attribute + ("deprecated", "1.6.0", Some(29935), Active), + + // allow using type ascription in expressions + ("type_ascription", "1.6.0", Some(23416), Active), + + // Allows cfg(target_thread_local) + ("cfg_target_thread_local", "1.7.0", Some(29594), Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -377,6 +386,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("must_use", Whitelisted, Ungated), ("stable", Whitelisted, Ungated), ("unstable", Whitelisted, Ungated), + ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")), ("rustc_paren_sugar", Normal, Gated("unboxed_closures", "unboxed_closures are still evolving")), @@ -407,6 +417,8 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] // (name in cfg, feature, function to check if the feature is enabled) ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)), ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)), + ("target_thread_local", "cfg_target_thread_local", + cfg_fn!(|x| x.cfg_target_thread_local)), ]; #[derive(Debug, Eq, PartialEq)] @@ -442,10 +454,13 @@ impl PartialOrd for GatedCfgAttr { } impl GatedCfgAttr { - pub fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) { + pub fn check_and_emit(&self, + diagnostic: &Handler, + features: &Features, + codemap: &CodeMap) { match *self { GatedCfgAttr::GatedCfg(ref cfg) => { - cfg.check_and_emit(diagnostic, features); + cfg.check_and_emit(diagnostic, features, codemap); } GatedCfgAttr::GatedAttr(span) => { if !features.stmt_expr_attributes { @@ -472,9 +487,12 @@ impl GatedCfg { } }) } - fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) { + fn check_and_emit(&self, + diagnostic: &Handler, + features: &Features, + codemap: &CodeMap) { let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) { + if !has_feature(features) && !codemap.span_allows_unstable(self.span) { let explain = format!("`cfg({})` is experimental and subject to change", cfg); emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain); } @@ -510,7 +528,6 @@ pub enum AttributeGate { pub struct Features { pub unboxed_closures: bool, pub rustc_diagnostic_macros: bool, - pub visible_private_types: bool, pub allow_quote: bool, pub allow_asm: bool, pub allow_log_syntax: bool, @@ -535,10 +552,12 @@ pub struct Features { pub type_macros: bool, pub cfg_target_feature: bool, pub cfg_target_vendor: bool, + pub cfg_target_thread_local: bool, pub augmented_assignments: bool, pub braced_empty_structs: bool, pub staged_api: bool, pub stmt_expr_attributes: bool, + pub deprecated: bool, } impl Features { @@ -546,7 +565,6 @@ impl Features { Features { unboxed_closures: false, rustc_diagnostic_macros: false, - visible_private_types: false, allow_quote: false, allow_asm: false, allow_log_syntax: false, @@ -569,10 +587,12 @@ impl Features { type_macros: false, cfg_target_feature: false, cfg_target_vendor: false, + cfg_target_thread_local: false, augmented_assignments: false, braced_empty_structs: false, staged_api: false, stmt_expr_attributes: false, + deprecated: false, } } } @@ -589,21 +609,21 @@ const EXPLAIN_PUSHPOP_UNSAFE: &'static str = const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = "attributes on non-item statements and expressions are experimental."; -pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { +pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) { if let Some(&Features { allow_box: true, .. }) = f { return; } emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX); } -pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) { +pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) { if let Some(&Features { allow_placement_in: true, .. }) = f { return; } emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN); } -pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { +pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) { if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f { return; } @@ -612,7 +632,7 @@ pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: struct Context<'a> { features: Vec<&'static str>, - span_handler: &'a SpanHandler, + span_handler: &'a Handler, cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } @@ -698,7 +718,7 @@ pub enum GateIssue { Library(Option) } -pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, issue: GateIssue, +pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue, explain: &str) { let issue = match issue { GateIssue::Language => find_lang_feature_issue(feature), @@ -954,6 +974,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { "box expression syntax is experimental; \ you can call `Box::new` instead."); } + ast::ExprType(..) => { + self.gate_feature("type_ascription", e.span, + "type ascription is experimental"); + } _ => {} } visit::walk_expr(self, e); @@ -1058,7 +1082,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } } -fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, +fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate, plugin_attributes: &[(String, AttributeType)], check: F) @@ -1124,7 +1148,6 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, Features { unboxed_closures: cx.has_feature("unboxed_closures"), rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"), - visible_private_types: cx.has_feature("visible_private_types"), allow_quote: cx.has_feature("quote"), allow_asm: cx.has_feature("asm"), allow_log_syntax: cx.has_feature("log_syntax"), @@ -1147,20 +1170,22 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, type_macros: cx.has_feature("type_macros"), cfg_target_feature: cx.has_feature("cfg_target_feature"), cfg_target_vendor: cx.has_feature("cfg_target_vendor"), + cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"), augmented_assignments: cx.has_feature("augmented_assignments"), braced_empty_structs: cx.has_feature("braced_empty_structs"), staged_api: cx.has_feature("staged_api"), stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"), + deprecated: cx.has_feature("deprecated"), } } -pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) +pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate) -> Features { check_crate_inner(cm, span_handler, krate, &[] as &'static [_], |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate)) } -pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, +pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate, plugin_attributes: &[(String, AttributeType)], unstable: UnstableFeatures) -> Features { @@ -1185,7 +1210,7 @@ pub enum UnstableFeatures { Cheat } -fn maybe_stage_features(span_handler: &SpanHandler, krate: &ast::Crate, +fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) { let allow_features = match unstable { UnstableFeatures::Allow => true, diff --git a/syntex_syntax/src/fold.rs b/syntex_syntax/src/fold.rs index 73f2c51b..cb467f90 100644 --- a/syntex_syntax/src/fold.rs +++ b/syntex_syntax/src/fold.rs @@ -23,7 +23,6 @@ use ast; use attr::{ThinAttributes, ThinAttributesExt}; use ast_util; use codemap::{respan, Span, Spanned}; -use owned_slice::OwnedSlice; use parse::token; use ptr::P; use util::small_vector::SmallVector; @@ -233,7 +232,7 @@ pub trait Folder : Sized { noop_fold_ty_param(tp, self) } - fn fold_ty_params(&mut self, tps: OwnedSlice) -> OwnedSlice { + fn fold_ty_params(&mut self, tps: P<[TyParam]>) -> P<[TyParam]> { noop_fold_ty_params(tps, self) } @@ -257,13 +256,13 @@ pub trait Folder : Sized { noop_fold_opt_lifetime(o_lt, self) } - fn fold_opt_bounds(&mut self, b: Option>) - -> Option> { + fn fold_opt_bounds(&mut self, b: Option) + -> Option { noop_fold_opt_bounds(b, self) } - fn fold_bounds(&mut self, b: OwnedSlice) - -> OwnedSlice { + fn fold_bounds(&mut self, b: TyParamBounds) + -> TyParamBounds { noop_fold_bounds(b, self) } @@ -663,7 +662,8 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(id, is_mod_name) => - token::NtIdent(Box::new(fld.fold_ident(*id)), is_mod_name), + token::NtIdent(Box::new(Spanned::{node: fld.fold_ident(id.node), .. *id}), + is_mod_name), token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))), token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&tt))), @@ -713,8 +713,8 @@ pub fn noop_fold_ty_param(tp: TyParam, fld: &mut T) -> TyParam { } } -pub fn noop_fold_ty_params(tps: OwnedSlice, fld: &mut T) - -> OwnedSlice { +pub fn noop_fold_ty_params(tps: P<[TyParam]>, fld: &mut T) + -> P<[TyParam]> { tps.move_map(|tp| fld.fold_ty_param(tp)) } @@ -870,8 +870,8 @@ pub fn noop_fold_mt(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutT } } -pub fn noop_fold_opt_bounds(b: Option>, folder: &mut T) - -> Option> { +pub fn noop_fold_opt_bounds(b: Option, folder: &mut T) + -> Option { b.map(|bounds| folder.fold_bounds(bounds)) } @@ -1203,6 +1203,9 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprCast(expr, ty) => { ExprCast(folder.fold_expr(expr), folder.fold_ty(ty)) } + ExprType(expr, ty) => { + ExprType(folder.fold_expr(expr), folder.fold_ty(ty)) + } ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)), ExprIf(cond, tr, fl) => { ExprIf(folder.fold_expr(cond), @@ -1303,8 +1306,13 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu inputs: inputs.move_map(|(c, input)| { (c, folder.fold_expr(input)) }), - outputs: outputs.move_map(|(c, out, is_rw)| { - (c, folder.fold_expr(out), is_rw) + outputs: outputs.move_map(|out| { + InlineAsmOutput { + constraint: out.constraint, + expr: folder.fold_expr(out.expr), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } }), asm: asm, asm_str_style: asm_str_style, diff --git a/syntex_syntax/src/lib.rs b/syntex_syntax/src/lib.rs index 4498120a..c09e35f1 100644 --- a/syntex_syntax/src/lib.rs +++ b/syntex_syntax/src/lib.rs @@ -14,11 +14,8 @@ //! //! This API is completely unstable and subject to change. -// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) -#![cfg_attr(stage0, feature(custom_attribute))] #![crate_name = "syntax"] #![unstable(feature = "rustc_private", issue = "27812")] -#![cfg_attr(stage0, staged_api)] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -26,8 +23,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![cfg_attr(stage0, feature(rustc_attrs))] -#![cfg_attr(stage0, allow(unused_attributes))] #![feature(associated_consts)] #![feature(filling_drop)] #![feature(libc)] @@ -37,7 +32,6 @@ #![feature(str_escape)] #![feature(unicode)] -extern crate fmt_macros; extern crate serialize; extern crate term; extern crate libc; @@ -53,7 +47,7 @@ extern crate serialize as rustc_serialize; // used by deriving macro_rules! panictry { ($e:expr) => ({ use std::result::Result::{Ok, Err}; - use diagnostic::FatalError; + use errors::FatalError; match $e { Ok(e) => e, Err(FatalError) => panic!(FatalError) @@ -79,6 +73,8 @@ pub mod diagnostics { pub mod metadata; } +pub mod errors; + pub mod syntax { pub use ext; pub use parse; @@ -91,7 +87,6 @@ pub mod ast_util; pub mod attr; pub mod codemap; pub mod config; -pub mod diagnostic; pub mod entry; pub mod feature_gate; pub mod fold; @@ -110,21 +105,12 @@ pub mod print { } pub mod ext { - pub mod asm; pub mod base; pub mod build; - pub mod cfg; - pub mod concat; - pub mod concat_idents; - pub mod deriving; - pub mod env; pub mod expand; - pub mod format; - pub mod log_syntax; pub mod mtwt; pub mod quote; pub mod source_util; - pub mod trace_macros; pub mod tt { pub mod transcribe; diff --git a/syntex_syntax/src/owned_slice.rs b/syntex_syntax/src/owned_slice.rs index 83369689..33a3d578 100644 --- a/syntex_syntax/src/owned_slice.rs +++ b/syntex_syntax/src/owned_slice.rs @@ -8,100 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::default::Default; -use std::fmt; -use std::iter::{IntoIterator, FromIterator}; -use std::ops::Deref; -use std::slice; -use std::vec; -use serialize::{Encodable, Decodable, Encoder, Decoder}; - -/// A non-growable owned slice. This is a separate type to allow the -/// representation to change. -#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct OwnedSlice { - data: Box<[T]> -} - -impl fmt::Debug for OwnedSlice { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.data.fmt(fmt) - } -} - -impl OwnedSlice { - pub fn empty() -> OwnedSlice { - OwnedSlice { data: Box::new([]) } - } - - #[inline(never)] - pub fn from_vec(v: Vec) -> OwnedSlice { - OwnedSlice { data: v.into_boxed_slice() } - } - - #[inline(never)] - pub fn into_vec(self) -> Vec { - self.data.into_vec() - } - - pub fn as_slice<'a>(&'a self) -> &'a [T] { - &*self.data - } - - pub fn move_iter(self) -> vec::IntoIter { - self.into_vec().into_iter() - } - - pub fn map U>(&self, f: F) -> OwnedSlice { - self.iter().map(f).collect() - } -} - -impl Deref for OwnedSlice { - type Target = [T]; - - fn deref(&self) -> &[T] { - self.as_slice() - } -} - -impl Default for OwnedSlice { - fn default() -> OwnedSlice { - OwnedSlice::empty() - } -} - -impl Clone for OwnedSlice { - fn clone(&self) -> OwnedSlice { - OwnedSlice::from_vec(self.to_vec()) - } -} - -impl FromIterator for OwnedSlice { - fn from_iter>(iter: I) -> OwnedSlice { - OwnedSlice::from_vec(iter.into_iter().collect()) - } -} - -impl<'a, T> IntoIterator for &'a OwnedSlice { - type Item = &'a T; - type IntoIter = slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.data.into_iter() - } -} - -impl Encodable for OwnedSlice { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - Encodable::encode(&**self, s) - } -} - -impl Decodable for OwnedSlice { - fn decode(d: &mut D) -> Result, D::Error> { - Ok(OwnedSlice::from_vec(match Decodable::decode(d) { - Ok(t) => t, - Err(e) => return Err(e) - })) - } -} +/// A non-growable owned slice. +#[unstable(feature = "rustc_private", issue = "0")] +#[rustc_deprecated(since = "1.7.0", reason = "use `ptr::P<[T]>` instead")] +pub type OwnedSlice = ::ptr::P<[T]>; diff --git a/syntex_syntax/src/parse/lexer/comments.rs b/syntex_syntax/src/parse/lexer/comments.rs index e5e2c3a9..d2156d7c 100644 --- a/syntex_syntax/src/parse/lexer/comments.rs +++ b/syntex_syntax/src/parse/lexer/comments.rs @@ -12,7 +12,7 @@ pub use self::CommentStyle::*; use ast; use codemap::{BytePos, CharPos, CodeMap, Pos}; -use diagnostic; +use errors; use parse::lexer::is_block_doc_comment; use parse::lexer::{StringReader, TokenAndSpan}; use parse::lexer::{is_whitespace, Reader}; @@ -334,7 +334,7 @@ pub struct Literal { // it appears this function is called only from pprust... that's // probably not a good thing. -pub fn gather_comments_and_literals(span_diagnostic: &diagnostic::SpanHandler, +pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler, path: String, srdr: &mut Read) -> (Vec, Vec) { diff --git a/syntex_syntax/src/parse/lexer/mod.rs b/syntex_syntax/src/parse/lexer/mod.rs index cb2181a0..4619410a 100644 --- a/syntex_syntax/src/parse/lexer/mod.rs +++ b/syntex_syntax/src/parse/lexer/mod.rs @@ -11,8 +11,7 @@ use ast; use codemap::{BytePos, CharPos, CodeMap, Pos, Span}; use codemap; -use diagnostic::FatalError; -use diagnostic::SpanHandler; +use errors::{FatalError, Handler}; use ext::tt::transcribe::tt_next_token; use parse::token::str_to_ident; use parse::token; @@ -58,7 +57,7 @@ pub struct TokenAndSpan { } pub struct StringReader<'a> { - pub span_diagnostic: &'a SpanHandler, + pub span_diagnostic: &'a Handler, /// The absolute offset within the codemap of the next character to read pub pos: BytePos, /// The absolute offset within the codemap of the last character read(curr) @@ -128,10 +127,10 @@ impl<'a> Reader for TtReader<'a> { impl<'a> StringReader<'a> { /// For comments.rs, which hackily pokes into pos and curr - pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler, + pub fn new_raw<'b>(span_diagnostic: &'b Handler, filemap: Rc) -> StringReader<'b> { if filemap.src.is_none() { - span_diagnostic.handler.bug(&format!("Cannot lex filemap without source: {}", + span_diagnostic.bug(&format!("Cannot lex filemap without source: {}", filemap.name)[..]); } @@ -153,7 +152,7 @@ impl<'a> StringReader<'a> { sr } - pub fn new<'b>(span_diagnostic: &'b SpanHandler, + pub fn new<'b>(span_diagnostic: &'b Handler, filemap: Rc) -> StringReader<'b> { let mut sr = StringReader::new_raw(span_diagnostic, filemap); sr.advance_token(); @@ -1423,28 +1422,30 @@ mod tests { use super::*; use codemap::{BytePos, CodeMap, Span, NO_EXPANSION}; - use diagnostic; + use errors; use parse::token; use parse::token::{str_to_ident}; use std::io; + use std::rc::Rc; - fn mk_sh() -> diagnostic::SpanHandler { + fn mk_sh(cm: Rc) -> errors::Handler { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - let emitter = diagnostic::EmitterWriter::new(Box::new(io::sink()), None); - let handler = diagnostic::Handler::with_emitter(true, Box::new(emitter)); - diagnostic::SpanHandler::new(handler, CodeMap::new()) + let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), None, cm); + errors::Handler::with_emitter(true, false, Box::new(emitter)) } // open a string reader for the given string - fn setup<'a>(span_handler: &'a diagnostic::SpanHandler, + fn setup<'a>(cm: &CodeMap, + span_handler: &'a errors::Handler, teststr: String) -> StringReader<'a> { - let fm = span_handler.cm.new_filemap("zebra.rs".to_string(), teststr); + let fm = cm.new_filemap("zebra.rs".to_string(), teststr); StringReader::new(span_handler, fm) } #[test] fn t1 () { - let span_handler = mk_sh(); - let mut string_reader = setup(&span_handler, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + let mut string_reader = setup(&cm, &sh, "/* my source file */ \ fn main() { println!(\"zebra\"); }\n".to_string()); let id = str_to_ident("fn"); @@ -1482,21 +1483,27 @@ mod tests { } #[test] fn doublecolonparsing () { - check_tokenization(setup(&mk_sh(), "a b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a b".to_string()), vec![mk_ident("a", token::Plain), token::Whitespace, mk_ident("b", token::Plain)]); } #[test] fn dcparsing_2 () { - check_tokenization(setup(&mk_sh(), "a::b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a::b".to_string()), vec![mk_ident("a",token::ModName), token::ModSep, mk_ident("b", token::Plain)]); } #[test] fn dcparsing_3 () { - check_tokenization(setup(&mk_sh(), "a ::b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a ::b".to_string()), vec![mk_ident("a", token::Plain), token::Whitespace, token::ModSep, @@ -1504,7 +1511,9 @@ mod tests { } #[test] fn dcparsing_4 () { - check_tokenization(setup(&mk_sh(), "a:: b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a:: b".to_string()), vec![mk_ident("a",token::ModName), token::ModSep, token::Whitespace, @@ -1512,40 +1521,52 @@ mod tests { } #[test] fn character_a() { - assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok, token::Literal(token::Char(token::intern("a")), None)); } #[test] fn character_space() { - assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok, token::Literal(token::Char(token::intern(" ")), None)); } #[test] fn character_escaped() { - assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok, token::Literal(token::Char(token::intern("\\n")), None)); } #[test] fn lifetime_name() { - assert_eq!(setup(&mk_sh(), "'abc".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok, token::Lifetime(token::str_to_ident("'abc"))); } #[test] fn raw_string() { - assert_eq!(setup(&mk_sh(), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token() .tok, token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3), None)); } #[test] fn literal_suffixes() { + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&mk_sh(), format!("{}suffix", $input)).next_token().tok, + assert_eq!(setup(&cm, &sh, format!("{}suffix", $input)).next_token().tok, token::Literal(token::$tok_type(token::intern($tok_contents)), Some(token::intern("suffix")))); // with a whitespace separator: - assert_eq!(setup(&mk_sh(), format!("{} suffix", $input)).next_token().tok, + assert_eq!(setup(&cm, &sh, format!("{} suffix", $input)).next_token().tok, token::Literal(token::$tok_type(token::intern($tok_contents)), None)); }} @@ -1561,13 +1582,13 @@ mod tests { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&mk_sh(), "2us".to_string()).next_token().tok, + assert_eq!(setup(&cm, &sh, "2us".to_string()).next_token().tok, token::Literal(token::Integer(token::intern("2")), Some(token::intern("us")))); - assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok, + assert_eq!(setup(&cm, &sh, "r###\"raw\"###suffix".to_string()).next_token().tok, token::Literal(token::StrRaw(token::intern("raw"), 3), Some(token::intern("suffix")))); - assert_eq!(setup(&mk_sh(), "br###\"raw\"###suffix".to_string()).next_token().tok, + assert_eq!(setup(&cm, &sh, "br###\"raw\"###suffix".to_string()).next_token().tok, token::Literal(token::ByteStrRaw(token::intern("raw"), 3), Some(token::intern("suffix")))); } @@ -1579,8 +1600,9 @@ mod tests { } #[test] fn nested_block_comments() { - let sh = mk_sh(); - let mut lexer = setup(&sh, "/* /* */ */'a'".to_string()); + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string()); match lexer.next_token().tok { token::Comment => { }, _ => panic!("expected a comment!") @@ -1589,8 +1611,9 @@ mod tests { } #[test] fn crlf_comments() { - let sh = mk_sh(); - let mut lexer = setup(&sh, "// test\r\n/// test\r\n".to_string()); + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); assert_eq!(comment.tok, token::Comment); assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7))); diff --git a/syntex_syntax/src/parse/mod.rs b/syntex_syntax/src/parse/mod.rs index e9c8173a..6951d631 100644 --- a/syntex_syntax/src/parse/mod.rs +++ b/syntex_syntax/src/parse/mod.rs @@ -12,7 +12,7 @@ use ast; use codemap::{self, Span, CodeMap, FileMap}; -use diagnostic::{SpanHandler, Handler, Auto, FatalError}; +use errors::{Handler, ColorConfig, FatalError}; use parse::parser::Parser; use parse::token::InternedString; use ptr::P; @@ -40,26 +40,29 @@ pub mod obsolete; /// Info about a parsing session. pub struct ParseSess { - pub span_diagnostic: SpanHandler, // better be the same as the one in the reader! + pub span_diagnostic: Handler, // better be the same as the one in the reader! /// Used to determine and report recursive mod inclusions included_mod_stack: RefCell>, + code_map: Rc, } impl ParseSess { pub fn new() -> ParseSess { - let handler = SpanHandler::new(Handler::new(Auto, None, true), CodeMap::new()); - ParseSess::with_span_handler(handler) + let cm = Rc::new(CodeMap::new()); + let handler = Handler::new(ColorConfig::Auto, None, true, false, cm.clone()); + ParseSess::with_span_handler(handler, cm) } - pub fn with_span_handler(sh: SpanHandler) -> ParseSess { + pub fn with_span_handler(handler: Handler, code_map: Rc) -> ParseSess { ParseSess { - span_diagnostic: sh, - included_mod_stack: RefCell::new(vec![]) + span_diagnostic: handler, + included_mod_stack: RefCell::new(vec![]), + code_map: code_map } } pub fn codemap(&self) -> &CodeMap { - &self.span_diagnostic.cm + &self.code_map } } @@ -235,7 +238,7 @@ fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option) let msg = format!("couldn't read {:?}: {}", path.display(), e); match spanopt { Some(sp) => panic!(sess.span_diagnostic.span_fatal(sp, &msg)), - None => panic!(sess.span_diagnostic.handler().fatal(&msg)) + None => panic!(sess.span_diagnostic.fatal(&msg)) } } } @@ -438,7 +441,7 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { } fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, - sd: &SpanHandler, sp: Span) -> ast::Lit_ { + sd: &Handler, sp: Span) -> ast::Lit_ { debug!("filtered_float_lit: {}, {:?}", data, suffix); match suffix.as_ref().map(|s| &**s) { Some("f32") => ast::LitFloat(data, ast::TyF32), @@ -459,7 +462,7 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, } } pub fn float_lit(s: &str, suffix: Option, - sd: &SpanHandler, sp: Span) -> ast::Lit_ { + sd: &Handler, sp: Span) -> ast::Lit_ { debug!("float_lit: {:?}, {:?}", s, suffix); // FIXME #2252: bounds checking float literals is deferred until trans let s = s.chars().filter(|&c| c != '_').collect::(); @@ -561,7 +564,7 @@ pub fn byte_str_lit(lit: &str) -> Rc> { pub fn integer_lit(s: &str, suffix: Option, - sd: &SpanHandler, + sd: &Handler, sp: Span) -> ast::Lit_ { // s can only be ascii, byte indexing is fine @@ -668,7 +671,6 @@ mod tests { use super::*; use std::rc::Rc; use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION}; - use owned_slice::OwnedSlice; use ast::{self, TokenTree}; use abi; use attr::{first_attr_value_str_by_name, AttrMetaMethods}; @@ -890,7 +892,7 @@ mod tests { assert!(panictry!(parser.parse_pat()) == P(ast::Pat{ id: ast::DUMMY_NODE_ID, - node: ast::PatIdent(ast::BindByValue(ast::MutImmutable), + node: ast::PatIdent(ast::BindingMode::ByValue(ast::MutImmutable), Spanned{ span:sp(0, 1), node: str_to_ident("b") }, @@ -926,7 +928,7 @@ mod tests { pat: P(ast::Pat { id: ast::DUMMY_NODE_ID, node: ast::PatIdent( - ast::BindByValue(ast::MutImmutable), + ast::BindingMode::ByValue(ast::MutImmutable), Spanned{ span: sp(6,7), node: str_to_ident("b")}, @@ -944,7 +946,7 @@ mod tests { abi::Rust, ast::Generics{ // no idea on either of these: lifetimes: Vec::new(), - ty_params: OwnedSlice::empty(), + ty_params: P::empty(), where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), diff --git a/syntex_syntax/src/parse/obsolete.rs b/syntex_syntax/src/parse/obsolete.rs index bc355f70..5dba1e18 100644 --- a/syntex_syntax/src/parse/obsolete.rs +++ b/syntex_syntax/src/parse/obsolete.rs @@ -66,10 +66,9 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { } if !self.obsolete_set.contains(&kind) && - (error || self.sess.span_diagnostic.handler().can_emit_warnings) { + (error || self.sess.span_diagnostic.can_emit_warnings) { self.sess .span_diagnostic - .handler() .note(&format!("{}", desc)); self.obsolete_set.insert(kind); } diff --git a/syntex_syntax/src/parse/parser.rs b/syntex_syntax/src/parse/parser.rs index 7502a8cb..dbd34b49 100644 --- a/syntex_syntax/src/parse/parser.rs +++ b/syntex_syntax/src/parse/parser.rs @@ -14,7 +14,7 @@ use abi; use ast::BareFnTy; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{Public, Unsafety}; -use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; +use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindingMode}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; use ast::{Constness, ConstTraitItem, Crate, CrateConfig}; @@ -26,14 +26,14 @@ use ast::{ExprBreak, ExprCall, ExprCast, ExprInPlace}; use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac, ExprRange}; use ast::{ExprMethodCall, ExprParen, ExprPath}; -use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; +use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprType, ExprUnary}; use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl}; -use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; +use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, FunctionRetTy}; use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst}; use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl}; use ast::{ItemExternCrate, ItemUse}; -use ast::{LifetimeDef, Lit, Lit_}; +use ast::{Lit, Lit_}; use ast::{LitBool, LitChar, LitByte, LitByteStr}; use ast::{LitStr, LitInt, Local}; use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; @@ -50,7 +50,7 @@ use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue}; use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef}; use ast::{Ty, Ty_, TypeBinding, TyMac}; use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer}; -use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr}; +use ast::{TyParam, TyParamBounds, TyParen, TyPath, TyPtr}; use ast::{TyRptr, TyTup, TyU32, TyVec}; use ast::TypeTraitItem; use ast::{UnnamedField, UnsafeBlock}; @@ -60,7 +60,7 @@ use attr::{ThinAttributes, ThinAttributesExt, AttributesExt}; use ast; use ast_util::{self, ident_to_path}; use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; -use diagnostic; +use errors::{self, FatalError}; use ext::tt::macro_parser; use parse; use parse::classify; @@ -73,9 +73,7 @@ use parse::{new_sub_parser_from_file, ParseSess}; use util::parser::{AssocOp, Fixity}; use print::pprust; use ptr::P; -use owned_slice::OwnedSlice; use parse::PResult; -use diagnostic::FatalError; use std::collections::HashSet; use std::io::prelude::*; @@ -752,7 +750,7 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_before_gt_or_return(&mut self, sep: Option, mut f: F) - -> PResult<(OwnedSlice, bool)> where + -> PResult<(P<[T]>, bool)> where F: FnMut(&mut Parser) -> PResult>, { let mut v = Vec::new(); @@ -773,7 +771,7 @@ impl<'a> Parser<'a> { if i % 2 == 0 { match try!(f(self)) { Some(result) => v.push(result), - None => return Ok((OwnedSlice::from_vec(v), true)) + None => return Ok((P::from_vec(v), true)) } } else { if let Some(t) = sep.as_ref() { @@ -782,7 +780,7 @@ impl<'a> Parser<'a> { } } - return Ok((OwnedSlice::from_vec(v), false)); + return Ok((P::from_vec(v), false)); } /// Parse a sequence bracketed by '<' and '>', stopping @@ -790,7 +788,7 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_before_gt(&mut self, sep: Option, mut f: F) - -> PResult> where + -> PResult> where F: FnMut(&mut Parser) -> PResult, { let (result, returned) = try!(self.parse_seq_to_before_gt_or_return(sep, @@ -802,7 +800,7 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_gt(&mut self, sep: Option, f: F) - -> PResult> where + -> PResult> where F: FnMut(&mut Parser) -> PResult, { let v = try!(self.parse_seq_to_before_gt(sep, f)); @@ -813,7 +811,7 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_gt_or_return(&mut self, sep: Option, f: F) - -> PResult<(OwnedSlice, bool)> where + -> PResult<(P<[T]>, bool)> where F: FnMut(&mut Parser) -> PResult>, { let (v, returned) = try!(self.parse_seq_to_before_gt_or_return(sep, f)); @@ -983,16 +981,16 @@ impl<'a> Parser<'a> { } f(&self.buffer[((self.buffer_start + dist - 1) & 3) as usize].tok) } - pub fn fatal(&self, m: &str) -> diagnostic::FatalError { + pub fn fatal(&self, m: &str) -> errors::FatalError { self.sess.span_diagnostic.span_fatal(self.span, m) } - pub fn span_fatal(&self, sp: Span, m: &str) -> diagnostic::FatalError { + pub fn span_fatal(&self, sp: Span, m: &str) -> errors::FatalError { self.sess.span_diagnostic.span_fatal(sp, m) } - pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> diagnostic::FatalError { + pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> errors::FatalError { self.span_err(sp, m); self.fileline_help(sp, help); - diagnostic::FatalError + errors::FatalError } pub fn span_note(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_note(sp, m) @@ -1022,7 +1020,7 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.span_bug(sp, m) } pub fn abort_if_errors(&self) { - self.sess.span_diagnostic.handler().abort_if_errors(); + self.sess.span_diagnostic.abort_if_errors(); } pub fn id_to_interned_str(&mut self, id: Ident) -> InternedString { @@ -1077,7 +1075,7 @@ impl<'a> Parser<'a> { let other_bounds = if try!(self.eat(&token::BinOp(token::Plus)) ){ try!(self.parse_ty_param_bounds(BoundParsingMode::Bare)) } else { - OwnedSlice::empty() + P::empty() }; let all_bounds = Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() @@ -1710,8 +1708,8 @@ impl<'a> Parser<'a> { ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), + types: P::from_vec(types), + bindings: P::from_vec(bindings), }) } else if try!(self.eat(&token::OpenDelim(token::Paren)) ){ let lo = self.last_span.lo; @@ -1774,8 +1772,8 @@ impl<'a> Parser<'a> { identifier: identifier, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), + types: P::from_vec(types), + bindings: P::from_vec(bindings), }), }); @@ -2789,6 +2787,11 @@ impl<'a> Parser<'a> { lhs = self.mk_expr(lhs.span.lo, rhs.span.hi, ExprCast(lhs, rhs), None); continue + } else if op == AssocOp::Colon { + let rhs = try!(self.parse_ty()); + lhs = self.mk_expr(lhs.span.lo, rhs.span.hi, + ExprType(lhs, rhs), None); + continue } else if op == AssocOp::DotDot { // If we didn’t have to handle `x..`, it would be pretty easy to generalise // it to the Fixity::None code. @@ -2811,7 +2814,6 @@ impl<'a> Parser<'a> { break } - let rhs = try!(match op.fixity() { Fixity::Right => self.with_res(restrictions, |this|{ this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed) @@ -2858,7 +2860,9 @@ impl<'a> Parser<'a> { let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None) } - AssocOp::As | AssocOp::DotDot => self.bug("As or DotDot branch reached") + AssocOp::As | AssocOp::Colon | AssocOp::DotDot => { + self.bug("As, Colon or DotDot branch reached") + } }; if op.fixity() == Fixity::None { break } @@ -2872,7 +2876,7 @@ impl<'a> Parser<'a> { fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) { debug_assert!(outer_op.is_comparison()); match lhs.node { - ExprBinary(op, _, _) if ast_util::is_comparison_binop(op.node) => { + ExprBinary(op, _, _) if op.node.is_comparison() => { // respan to include both operators let op_span = mk_sp(op.span.lo, self.span.hi); self.span_err(op_span, @@ -3274,10 +3278,10 @@ impl<'a> Parser<'a> { hi = self.last_span.hi; let bind_type = match (is_ref, is_mut) { - (true, true) => BindByRef(MutMutable), - (true, false) => BindByRef(MutImmutable), - (false, true) => BindByValue(MutMutable), - (false, false) => BindByValue(MutImmutable), + (true, true) => BindingMode::ByRef(MutMutable), + (true, false) => BindingMode::ByRef(MutImmutable), + (false, true) => BindingMode::ByValue(MutMutable), + (false, false) => BindingMode::ByValue(MutImmutable), }; let fieldpath = codemap::Spanned{span:self.last_span, node:fieldname}; let fieldpat = P(ast::Pat{ @@ -3372,11 +3376,11 @@ impl<'a> Parser<'a> { // At this point, token != _, &, &&, (, [ if try!(self.eat_keyword(keywords::Mut)) { // Parse mut ident @ pat - pat = try!(self.parse_pat_ident(BindByValue(MutMutable))); + pat = try!(self.parse_pat_ident(BindingMode::ByValue(MutMutable))); } else if try!(self.eat_keyword(keywords::Ref)) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = try!(self.parse_mutability()); - pat = try!(self.parse_pat_ident(BindByRef(mutbl))); + pat = try!(self.parse_pat_ident(BindingMode::ByRef(mutbl))); } else if try!(self.eat_keyword(keywords::Box)) { // Parse box pat let subpat = try!(self.parse_pat()); @@ -3405,7 +3409,7 @@ impl<'a> Parser<'a> { // Parse ident @ pat // This can give false positives and parse nullary enums, // they are dealt with later in resolve - pat = try!(self.parse_pat_ident(BindByValue(MutImmutable))); + pat = try!(self.parse_pat_ident(BindingMode::ByValue(MutImmutable))); } } else { let (qself, path) = if try!(self.eat_lt()) { @@ -3883,10 +3887,10 @@ impl<'a> Parser<'a> { // otherwise returns empty list. fn parse_colon_then_ty_param_bounds(&mut self, mode: BoundParsingMode) - -> PResult> + -> PResult { if !try!(self.eat(&token::Colon) ){ - Ok(OwnedSlice::empty()) + Ok(P::empty()) } else { self.parse_ty_param_bounds(mode) } @@ -3898,7 +3902,7 @@ impl<'a> Parser<'a> { // and bound = 'region | trait_ref fn parse_ty_param_bounds(&mut self, mode: BoundParsingMode) - -> PResult> + -> PResult { let mut result = vec!(); loop { @@ -3940,7 +3944,7 @@ impl<'a> Parser<'a> { } } - return Ok(OwnedSlice::from_vec(result)); + return Ok(P::from_vec(result)); } /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? @@ -4000,7 +4004,7 @@ impl<'a> Parser<'a> { } }) } else { - Ok(ast_util::empty_generics()) + Ok(ast::Generics::default()) } } diff --git a/syntex_syntax/src/parse/token.rs b/syntex_syntax/src/parse/token.rs index 17b7d8db..b942954c 100644 --- a/syntex_syntax/src/parse/token.rs +++ b/syntex_syntax/src/parse/token.rs @@ -377,7 +377,7 @@ pub enum Nonterminal { NtPat(P), NtExpr(P), NtTy(P), - NtIdent(Box, IdentStyle), + NtIdent(Box, IdentStyle), /// Stuff inside brackets for attributes NtMeta(P), NtPath(Box), diff --git a/syntex_syntax/src/print/pprust.rs b/syntex_syntax/src/print/pprust.rs index f7105951..347b9f45 100644 --- a/syntex_syntax/src/print/pprust.rs +++ b/syntex_syntax/src/print/pprust.rs @@ -15,13 +15,11 @@ use ast::{self, TokenTree}; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use attr::ThinAttributesExt; -use ast_util; use util::parser::AssocOp; use attr; -use owned_slice::OwnedSlice; use attr::{AttrMetaMethods, AttributeMethods}; use codemap::{self, CodeMap, BytePos}; -use diagnostic; +use errors; use parse::token::{self, BinOpToken, Token, InternedString}; use parse::lexer::comments; use parse; @@ -100,7 +98,7 @@ pub const DEFAULT_COLUMNS: usize = 78; /// it can scan the input text for comments and literals to /// copy forward. pub fn print_crate<'a>(cm: &'a CodeMap, - span_diagnostic: &diagnostic::SpanHandler, + span_diagnostic: &errors::Handler, krate: &ast::Crate, filename: String, input: &mut Read, @@ -140,7 +138,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, impl<'a> State<'a> { pub fn new_from_input(cm: &'a CodeMap, - span_diagnostic: &diagnostic::SpanHandler, + span_diagnostic: &errors::Handler, filename: String, input: &mut Read, out: Box, @@ -296,7 +294,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtBlock(ref e) => block_to_string(&**e), token::NtStmt(ref e) => stmt_to_string(&**e), token::NtPat(ref e) => pat_to_string(&**e), - token::NtIdent(ref e, _) => ident_to_string(**e), + token::NtIdent(ref e, _) => ident_to_string(e.node), token::NtTT(ref e) => tt_to_string(&**e), token::NtArm(ref e) => arm_to_string(&*e), token::NtImplItem(ref e) => impl_item_to_string(&**e), @@ -446,7 +444,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool { ast::ExprAssign(..) | ast::ExprBinary(..) | ast::ExprClosure(..) | ast::ExprAssignOp(..) | ast::ExprCast(..) | - ast::ExprInPlace(..) => true, + ast::ExprInPlace(..) | ast::ExprType(..) => true, _ => false, } } @@ -649,15 +647,15 @@ pub trait PrintState<'a> { match t { ast::SignedIntLit(st, ast::Plus) => { word(self.writer(), - &ast_util::int_val_to_string(st, i as i64)) + &st.val_to_string(i as i64)) } ast::SignedIntLit(st, ast::Minus) => { - let istr = ast_util::int_val_to_string(st, -(i as i64)); + let istr = st.val_to_string(-(i as i64)); word(self.writer(), &format!("-{}", istr)) } ast::UnsignedIntLit(ut) => { - word(self.writer(), &ast_util::uint_val_to_string(ut, i)) + word(self.writer(), &ut.val_to_string(i)) } ast::UnsuffixedIntLit(ast::Plus) => { word(self.writer(), &format!("{}", i)) @@ -672,7 +670,7 @@ pub trait PrintState<'a> { &format!( "{}{}", &f, - &ast_util::float_ty_to_string(t))) + t.ty_to_string())) } ast::LitFloatUnsuffixed(ref f) => word(self.writer(), &f[..]), ast::LitBool(val) => { @@ -1002,7 +1000,7 @@ impl<'a> State<'a> { ast::TyBareFn(ref f) => { let generics = ast::Generics { lifetimes: f.lifetimes.clone(), - ty_params: OwnedSlice::empty(), + ty_params: P::empty(), where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), @@ -1528,7 +1526,7 @@ impl<'a> State<'a> { pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> { try!(self.head("")); - let generics = ast_util::empty_generics(); + let generics = ast::Generics::default(); try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)); match v.node.disr_expr { Some(ref d) => { @@ -1948,7 +1946,7 @@ impl<'a> State<'a> { try!(self.print_expr(lhs)); } try!(space(&mut self.s)); - try!(self.word_space(ast_util::binop_to_string(op.node))); + try!(self.word_space(op.node.to_string())); if self.check_expr_bin_needs_paren(rhs, op) { self.print_expr_maybe_paren(rhs) } else { @@ -1959,7 +1957,7 @@ impl<'a> State<'a> { fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) -> io::Result<()> { - try!(word(&mut self.s, ast_util::unop_to_string(op))); + try!(word(&mut self.s, ast::UnOp::to_string(op))); self.print_expr_maybe_paren(expr) } @@ -2037,6 +2035,11 @@ impl<'a> State<'a> { try!(self.word_space("as")); try!(self.print_type(&**ty)); } + ast::ExprType(ref expr, ref ty) => { + try!(self.print_expr(&**expr)); + try!(self.word_space(":")); + try!(self.print_type(&**ty)); + } ast::ExprIf(ref test, ref blk, ref elseopt) => { try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e))); } @@ -2151,7 +2154,7 @@ impl<'a> State<'a> { ast::ExprAssignOp(op, ref lhs, ref rhs) => { try!(self.print_expr(&**lhs)); try!(space(&mut self.s)); - try!(word(&mut self.s, ast_util::binop_to_string(op.node))); + try!(word(&mut self.s, op.node.to_string())); try!(self.word_space("=")); try!(self.print_expr(&**rhs)); } @@ -2219,16 +2222,16 @@ impl<'a> State<'a> { try!(self.word_space(":")); try!(self.commasep(Inconsistent, &a.outputs, - |s, &(ref co, ref o, is_rw)| { - match co.slice_shift_char() { - Some(('=', operand)) if is_rw => { + |s, out| { + match out.constraint.slice_shift_char() { + Some(('=', operand)) if out.is_rw => { try!(s.print_string(&format!("+{}", operand), ast::CookedStr)) } - _ => try!(s.print_string(&co, ast::CookedStr)) + _ => try!(s.print_string(&out.constraint, ast::CookedStr)) } try!(s.popen()); - try!(s.print_expr(&**o)); + try!(s.print_expr(&*out.expr)); try!(s.pclose()); Ok(()) })); @@ -2468,12 +2471,12 @@ impl<'a> State<'a> { ast::PatWild => try!(word(&mut self.s, "_")), ast::PatIdent(binding_mode, ref path1, ref sub) => { match binding_mode { - ast::BindByRef(mutbl) => { + ast::BindingMode::ByRef(mutbl) => { try!(self.word_nbsp("ref")); try!(self.print_mutability(mutbl)); } - ast::BindByValue(ast::MutImmutable) => {} - ast::BindByValue(ast::MutMutable) => { + ast::BindingMode::ByValue(ast::MutImmutable) => {} + ast::BindingMode::ByValue(ast::MutMutable) => { try!(self.word_nbsp("mut")); } } @@ -2679,7 +2682,7 @@ impl<'a> State<'a> { let m = match *explicit_self { ast::SelfStatic => ast::MutImmutable, _ => match decl.inputs[0].pat.node { - ast::PatIdent(ast::BindByValue(m), _, _) => m, + ast::PatIdent(ast::BindingMode::ByValue(m), _, _) => m, _ => ast::MutImmutable } }; @@ -3025,7 +3028,7 @@ impl<'a> State<'a> { } let generics = ast::Generics { lifetimes: Vec::new(), - ty_params: OwnedSlice::empty(), + ty_params: P::empty(), where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), @@ -3159,7 +3162,7 @@ mod tests { output: ast::DefaultReturn(codemap::DUMMY_SP), variadic: false }; - let generics = ast_util::empty_generics(); + let generics = ast::Generics::default(); assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, ast::Constness::NotConst, abba_ident, diff --git a/syntex_syntax/src/ptr.rs b/syntex_syntax/src/ptr.rs index 83e321f1..0504c313 100644 --- a/syntex_syntax/src/ptr.rs +++ b/syntex_syntax/src/ptr.rs @@ -37,14 +37,15 @@ //! Moreover, a switch to, e.g. `P<'a, T>` would be easy and mostly automated. use std::fmt::{self, Display, Debug}; -use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; use std::ops::Deref; -use std::ptr; +use std::{ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; /// An owned smart pointer. -pub struct P { +#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct P { ptr: Box } @@ -92,14 +93,6 @@ impl Clone for P { } } -impl PartialEq for P { - fn eq(&self, other: &P) -> bool { - **self == **other - } -} - -impl Eq for P {} - impl Debug for P { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(&**self, f) @@ -111,19 +104,12 @@ impl Display for P { } } -#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for P { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.ptr, f) } } -impl Hash for P { - fn hash(&self, state: &mut H) { - (**self).hash(state); - } -} - impl Decodable for P { fn decode(d: &mut D) -> Result, D::Error> { Decodable::decode(d).map(P) @@ -135,3 +121,112 @@ impl Encodable for P { (**self).encode(s) } } + + +impl fmt::Debug for P<[T]> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.ptr.fmt(fmt) + } +} + +impl P<[T]> { + pub fn new() -> P<[T]> { + P::empty() + } + + pub fn empty() -> P<[T]> { + P { ptr: Default::default() } + } + + #[inline(never)] + pub fn from_vec(v: Vec) -> P<[T]> { + P { ptr: v.into_boxed_slice() } + } + + #[inline(never)] + pub fn into_vec(self) -> Vec { + self.ptr.into_vec() + } + + pub fn as_slice<'a>(&'a self) -> &'a [T] { + &*self.ptr + } + + pub fn move_iter(self) -> vec::IntoIter { + self.into_vec().into_iter() + } + + pub fn map U>(&self, f: F) -> P<[U]> { + self.iter().map(f).collect() + } +} + +impl Deref for P<[T]> { + type Target = [T]; + + fn deref(&self) -> &[T] { + self.as_slice() + } +} + +impl Default for P<[T]> { + fn default() -> P<[T]> { + P::empty() + } +} + +impl Clone for P<[T]> { + fn clone(&self) -> P<[T]> { + P::from_vec(self.to_vec()) + } +} + +impl From> for P<[T]> { + fn from(v: Vec) -> Self { + P::from_vec(v) + } +} + +impl Into> for P<[T]> { + fn into(self) -> Vec { + self.into_vec() + } +} + +impl FromIterator for P<[T]> { + fn from_iter>(iter: I) -> P<[T]> { + P::from_vec(iter.into_iter().collect()) + } +} + +impl IntoIterator for P<[T]> { + type Item = T; + type IntoIter = vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.into_vec().into_iter() + } +} + +impl<'a, T> IntoIterator for &'a P<[T]> { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.ptr.into_iter() + } +} + +impl Encodable for P<[T]> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + Encodable::encode(&**self, s) + } +} + +impl Decodable for P<[T]> { + fn decode(d: &mut D) -> Result, D::Error> { + Ok(P::from_vec(match Decodable::decode(d) { + Ok(t) => t, + Err(e) => return Err(e) + })) + } +} diff --git a/syntex_syntax/src/show_span.rs b/syntex_syntax/src/show_span.rs index 6492cd4b..014c7b2a 100644 --- a/syntex_syntax/src/show_span.rs +++ b/syntex_syntax/src/show_span.rs @@ -16,7 +16,7 @@ use std::str::FromStr; use ast; -use diagnostic; +use errors; use visit; use visit::Visitor; @@ -40,7 +40,7 @@ impl FromStr for Mode { } struct ShowSpanVisitor<'a> { - span_diagnostic: &'a diagnostic::SpanHandler, + span_diagnostic: &'a errors::Handler, mode: Mode, } @@ -71,7 +71,7 @@ impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { } } -pub fn run(span_diagnostic: &diagnostic::SpanHandler, +pub fn run(span_diagnostic: &errors::Handler, mode: &str, krate: &ast::Crate) { let mode = match mode.parse().ok() { diff --git a/syntex_syntax/src/test.rs b/syntex_syntax/src/test.rs index 6fd3833a..9a6d1f8f 100644 --- a/syntex_syntax/src/test.rs +++ b/syntex_syntax/src/test.rs @@ -23,7 +23,7 @@ use attr::AttrMetaMethods; use attr; use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; use codemap; -use diagnostic; +use errors; use config; use entry::{self, EntryPointType}; use ext::base::ExtCtxt; @@ -32,7 +32,6 @@ use ext::expand::ExpansionConfig; use fold::Folder; use util::move_map::MoveMap; use fold; -use owned_slice::OwnedSlice; use parse::token::{intern, InternedString}; use parse::{token, ParseSess}; use print::pprust; @@ -55,7 +54,7 @@ struct Test { struct TestCtxt<'a> { sess: &'a ParseSess, - span_diagnostic: &'a diagnostic::SpanHandler, + span_diagnostic: &'a errors::Handler, path: Vec, ext_cx: ExtCtxt<'a>, testfns: Vec, @@ -72,7 +71,7 @@ struct TestCtxt<'a> { pub fn modify_for_testing(sess: &ParseSess, cfg: &ast::CrateConfig, krate: ast::Crate, - span_diagnostic: &diagnostic::SpanHandler) -> ast::Crate { + span_diagnostic: &errors::Handler) -> ast::Crate { // We generate the test harness when building in the 'test' // configuration, either with the '--test' or '--cfg test' // command line options. @@ -275,7 +274,7 @@ fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: Option, krate: ast::Crate, cfg: &ast::CrateConfig, - sd: &diagnostic::SpanHandler) -> ast::Crate { + sd: &errors::Handler) -> ast::Crate { // Remove the entry points let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); @@ -315,7 +314,7 @@ fn generate_test_harness(sess: &ParseSess, return res; } -fn strip_test_functions(diagnostic: &diagnostic::SpanHandler, krate: ast::Crate) +fn strip_test_functions(diagnostic: &errors::Handler, krate: ast::Crate) -> ast::Crate { // When not compiling with --test we should not compile the // #[test] functions @@ -500,7 +499,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { let main = ast::ItemFn(ecx.fn_decl(vec![], main_ret_ty), ast::Unsafety::Normal, ast::Constness::NotConst, - ::abi::Rust, empty_generics(), main_body); + ::abi::Rust, ast::Generics::default(), main_body); let main = P(ast::Item { ident: token::str_to_ident("main"), attrs: vec![main_attr], @@ -688,7 +687,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { Some(id) => vec![id], None => { let diag = cx.span_diagnostic; - diag.handler.bug("expected to find top-level re-export name, but found None"); + diag.bug("expected to find top-level re-export name, but found None"); } }; visible_path.extend(path); diff --git a/syntex_syntax/src/util/lev_distance.rs b/syntex_syntax/src/util/lev_distance.rs index 9bf96311..e0796c34 100644 --- a/syntex_syntax/src/util/lev_distance.rs +++ b/syntex_syntax/src/util/lev_distance.rs @@ -8,50 +8,64 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use ast::Name; use std::cmp; +use parse::token::InternedString; -pub fn lev_distance(me: &str, t: &str) -> usize { - if me.is_empty() { return t.chars().count(); } - if t.is_empty() { return me.chars().count(); } +/// To find the Levenshtein distance between two strings +pub fn lev_distance(a: &str, b: &str) -> usize { + // cases which don't require further computation + if a.is_empty() { + return b.chars().count(); + } else if b.is_empty() { + return a.chars().count(); + } - let mut dcol: Vec<_> = (0..t.len() + 1).collect(); + let mut dcol: Vec<_> = (0..b.len() + 1).collect(); let mut t_last = 0; - for (i, sc) in me.chars().enumerate() { - + for (i, sc) in a.chars().enumerate() { let mut current = i; dcol[0] = current + 1; - for (j, tc) in t.chars().enumerate() { - + for (j, tc) in b.chars().enumerate() { let next = dcol[j + 1]; - if sc == tc { dcol[j + 1] = current; } else { dcol[j + 1] = cmp::min(current, next); dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1; } - current = next; t_last = j; } - } - - dcol[t_last + 1] + } dcol[t_last + 1] } -pub fn max_suggestion_distance(name: &str) -> usize { - use std::cmp::max; - // As a loose rule to avoid obviously incorrect suggestions, clamp the - // maximum edit distance we will accept for a suggestion to one third of - // the typo'd name's length. - max(name.len(), 3) / 3 +/// To find the best match for a given string from an iterator of names +/// As a loose rule to avoid the obviously incorrect suggestions, it takes +/// an optional limit for the maximum allowable edit distance, which defaults +/// to one-third of the given word +pub fn find_best_match_for_name<'a, T>(iter_names: T, + lookup: &str, + dist: Option) -> Option + where T: Iterator { + let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d); + iter_names + .filter_map(|name| { + let dist = lev_distance(lookup, &name.as_str()); + match dist <= max_dist { // filter the unwanted cases + true => Some((name.as_str(), dist)), + false => None, + } + }) + .min_by_key(|&(_, val)| val) // extract the tuple containing the minimum edit distance + .map(|(s, _)| s) // and return only the string } #[test] fn test_lev_distance() { - use std::char::{ from_u32, MAX }; + use std::char::{from_u32, MAX}; // Test bytelength agnosticity for c in (0..MAX as u32) .filter_map(|i| from_u32(i)) diff --git a/syntex_syntax/src/util/move_map.rs b/syntex_syntax/src/util/move_map.rs index 95c24c66..e1078b71 100644 --- a/syntex_syntax/src/util/move_map.rs +++ b/syntex_syntax/src/util/move_map.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use owned_slice::OwnedSlice; - use std::ptr; pub trait MoveMap: Sized { @@ -69,11 +67,11 @@ impl MoveMap for Vec { } } -impl MoveMap for OwnedSlice { +impl MoveMap for ::ptr::P<[T]> { fn move_flat_map(self, f: F) -> Self where F: FnMut(T) -> I, I: IntoIterator { - OwnedSlice::from_vec(self.into_vec().move_flat_map(f)) + ::ptr::P::from_vec(self.into_vec().move_flat_map(f)) } } diff --git a/syntex_syntax/src/util/parser.rs b/syntex_syntax/src/util/parser.rs index bf3a8def..87ef96d8 100644 --- a/syntex_syntax/src/util/parser.rs +++ b/syntex_syntax/src/util/parser.rs @@ -60,7 +60,9 @@ pub enum AssocOp { /// `as` As, /// `..` range - DotDot + DotDot, + /// `:` + Colon, } #[derive(Debug, PartialEq, Eq)] @@ -100,6 +102,7 @@ impl AssocOp { Token::AndAnd => Some(LAnd), Token::OrOr => Some(LOr), Token::DotDot => Some(DotDot), + Token::Colon => Some(Colon), _ if t.is_keyword(keywords::As) => Some(As), _ => None } @@ -134,7 +137,7 @@ impl AssocOp { pub fn precedence(&self) -> usize { use self::AssocOp::*; match *self { - As => 14, + As | Colon => 14, Multiply | Divide | Modulus => 13, Add | Subtract => 12, ShiftLeft | ShiftRight => 11, @@ -158,7 +161,7 @@ impl AssocOp { Inplace | Assign | AssignOp(_) => Fixity::Right, As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | - LAnd | LOr => Fixity::Left, + LAnd | LOr | Colon => Fixity::Left, DotDot => Fixity::None } } @@ -168,7 +171,7 @@ impl AssocOp { match *self { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | - ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot => false + ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | Colon => false } } @@ -178,7 +181,7 @@ impl AssocOp { Assign | AssignOp(_) | Inplace => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | - LOr | DotDot => false + LOr | DotDot | Colon => false } } @@ -203,8 +206,7 @@ impl AssocOp { BitOr => Some(ast::BiBitOr), LAnd => Some(ast::BiAnd), LOr => Some(ast::BiOr), - Inplace | Assign | AssignOp(_) | As | DotDot => None + Inplace | Assign | AssignOp(_) | As | DotDot | Colon => None } } - } diff --git a/syntex_syntax/src/util/small_vector.rs b/syntex_syntax/src/util/small_vector.rs index ee183d7f..8b07b21c 100644 --- a/syntex_syntax/src/util/small_vector.rs +++ b/syntex_syntax/src/util/small_vector.rs @@ -127,13 +127,6 @@ impl SmallVector { } } - /// Deprecated: use `into_iter`. - #[unstable(feature = "rustc_private", issue = "0")] - #[rustc_deprecated(since = "1.0.0", reason = "use into_iter")] - pub fn move_iter(self) -> IntoIter { - self.into_iter() - } - pub fn len(&self) -> usize { match self.repr { Zero => 0, diff --git a/syntex_syntax/src/visit.rs b/syntex_syntax/src/visit.rs index cdc11fb2..b8dd5479 100644 --- a/syntex_syntax/src/visit.rs +++ b/syntex_syntax/src/visit.rs @@ -693,7 +693,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression) } ExprLit(_) => {} - ExprCast(ref subexpression, ref typ) => { + ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } @@ -786,8 +786,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { for &(_, ref input) in &ia.inputs { visitor.visit_expr(&input) } - for &(_, ref output, _) in &ia.outputs { - visitor.visit_expr(&output) + for output in &ia.outputs { + visitor.visit_expr(&output.expr) } } }