<commit_before>use super::{Parser, PathStyle, TokenType};
use rustc_errors::PResult;
use syntax::ast;
use syntax::attr;
use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::util::comments;
use syntax_pos::{Span, Symbol};

use log::debug;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
    Permitted,
    NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

impl<'a> Parser<'a> {
    /// Parses attributes that appear before an item.
    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            match self.token.kind {
                token::Pound => {
                    let inner_error_reason = if just_parsed_doc_comment {
                        "an inner attribute is not permitted following an outer doc comment"
                    } else if !attrs.is_empty() {
                        "an inner attribute is not permitted following an outer attribute"
                    } else {
                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                    };
                    let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted {
                        reason: inner_error_reason,
                        saw_doc_comment: just_parsed_doc_comment,
                        prev_attr_sp: attrs.last().and_then(|a| Some(a.span)),
                    };
                    let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                    attrs.push(attr);
                    just_parsed_doc_comment = false;
                }
                token::DocComment(s) => {
                    let attr = self.mk_doc_comment(s);
                    if attr.style != ast::AttrStyle::Outer {
                        let mut err = self.fatal("expected outer doc comment");
                        err.note(
                            "inner doc comments like this (starting with \
                                  `//!` or `/*!`) can only appear before items",
                        );
                        return Err(err);
                    }
                    attrs.push(attr);
                    self.bump();
                    just_parsed_doc_comment = true;
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
        let style = comments::doc_comment_style(&s.as_str());
        attr::mk_doc_comment(style, s, self.token.span)
    }

    /// Matches `attribute = # ! [ meta_item ]`.
    ///
    /// If `permit_inner` is `true`, then a leading `!` indicates an inner
    /// attribute.
    pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token);
        let inner_parse_policy = if permit_inner {
            InnerAttributeParsePolicy::Permitted
        } else {
            InnerAttributeParsePolicy::NotPermitted {
                reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
                saw_doc_comment: false,
                prev_attr_sp: None,
            }
        };
        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
    }

    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
    /// that prescribes how to handle inner attributes.
    fn parse_attribute_with_inner_parse_policy(
        &mut self,
        inner_parse_policy: InnerAttributeParsePolicy<'_>,
    ) -> PResult<'a, ast::Attribute> {
        debug!(
            "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
            inner_parse_policy, self.token
        );
        let (span, item, style) = match self.token.kind {
            token::Pound => {
                let lo = self.token.span;
                self.bump();

                if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                    self.expected_tokens.push(TokenType::Token(token::Not));
                }

                let style = if self.token == token::Not {
                    self.bump();
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                self.expect(&token::OpenDelim(token::Bracket))?;
                let item = self.parse_attr_item()?;
                self.expect(&token::CloseDelim(token::Bracket))?;
                let hi = self.prev_span;

                let attr_sp = lo.to(hi);

                // Emit error if inner attribute is encountered and not permitted
                if style == ast::AttrStyle::Inner {
                    if let InnerAttributeParsePolicy::NotPermitted {
                        reason,
                        saw_doc_comment,
                        prev_attr_sp,
                    } = inner_parse_policy
                    {
                        let prev_attr_note = if saw_doc_comment {
                            "previous doc comment"
                        } else {
                            "previous outer attribute"
                        };

                        let mut diagnostic = self.struct_span_err(attr_sp, reason);

                        if let Some(prev_attr_sp) = prev_attr_sp {
                            diagnostic
                                .span_label(attr_sp, "not permitted following an outer attibute")
                                .span_label(prev_attr_sp, prev_attr_note);
                        }

                        diagnostic
                            .note(
                                "inner attributes, like `#![no_std]`, annotate the item \
                                   enclosing them, and are usually found at the beginning of \
                                   source files. Outer attributes, like `#[test]`, annotate the \
                                   item following them.",
                            )
                            .emit()
                    }
                }

                (attr_sp, item, style)
            }
            _ => {
                let token_str = pprust::token_to_string(&self.token);
                return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
            }
        };

        Ok(attr::mk_attr_from_item(style, item, span))
    }

    /// Parses an inner part of an attribute (the path and following tokens).
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    ///     PATH `(` TOKEN_STREAM `)`
    ///     PATH `[` TOKEN_STREAM `]`
    ///     PATH `{` TOKEN_STREAM `}`
    ///     PATH
    ///     PATH `=` UNSUFFIXED_LIT
    /// The delimiters or `=` are still put into the resulting token stream.
    pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
        let item = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref item) => Some(item.clone()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(item) = item {
            self.bump();
            item
        } else {
            let path = self.parse_path(PathStyle::Mod)?;
            let args = self.parse_attr_args()?;
            ast::AttrItem { path, args }
        })
    }

    /// Parses attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.
    ///
    /// Matches `inner_attrs*`.
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            match self.token.kind {
                token::Pound => {
                    // Don't even try to parse if it's not an inner attribute.
                    if !self.look_ahead(1, |t| t == &token::Not) {
                        break;
                    }

                    let attr = self.parse_attribute(true)?;
                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                    attrs.push(attr);
                }
                token::DocComment(s) => {
                    // We need to get the position of this token before we bump.
                    let attr = self.mk_doc_comment(s);
                    if attr.style == ast::AttrStyle::Inner {
                        attrs.push(attr);
                        self.bump();
                    } else {
                        break;
                    }
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.kind.is_unsuffixed() {
            let msg = "suffixed literals are not allowed in attributes";
            self.struct_span_err(lit.span, msg)
                .help(
                    "instead of using a suffixed literal \
                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
                                    (1, 1.0, etc.).",
                )
                .emit()
        }

        Ok(lit)
    }

    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
        let cfg_predicate = self.parse_meta_item()?;
        self.expect(&token::Comma)?;

        // Presumably, the majority of the time there will only be one attr.
        let mut expanded_attrs = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            let lo = self.token.span;
            let item = self.parse_attr_item()?;
            expanded_attrs.push((item, lo.to(self.prev_span)));
            if !self.eat(&token::Comma) {
                break;
            }
        }

        Ok((cfg_predicate, expanded_attrs))
    }

    /// Matches `COMMASEP(meta_item_inner)`.
    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        // Presumably, the majority of the time there will only be one attr.
        let mut nmis = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            nmis.push(self.parse_meta_item_inner()?);
            if !self.eat(&token::Comma) {
                break;
            }
        }
        Ok(nmis)
    }

    /// Matches the following grammar (per RFC 1559).
    ///
    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(item) = nt_meta {
            return match item.meta(item.path.span) {
                Some(meta) => {
                    self.bump();
                    Ok(meta)
                }
                None => self.unexpected(),
            };
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let kind = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_span);
        Ok(ast::MetaItem { path, kind, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.check(&token::OpenDelim(token::Paren)) {
            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
            ast::MetaItemKind::List(list)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
            Err(ref mut err) => err.cancel(),
        }

        match self.parse_meta_item() {
            Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
            Err(ref mut err) => err.cancel(),
        }

        let found = pprust::token_to_string(&self.token);
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.struct_span_err(self.token.span, &msg))
    }
}
<commit_msg>parser::attr: remove .fatal calls<commit_after>use super::{Parser, PathStyle, TokenType};
use rustc_errors::PResult;
use syntax::ast;
use syntax::attr;
use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::util::comments;
use syntax_pos::{Span, Symbol};

use log::debug;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
    Permitted,
    NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

impl<'a> Parser<'a> {
    /// Parses attributes that appear before an item.
    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            match self.token.kind {
                token::Pound => {
                    let inner_error_reason = if just_parsed_doc_comment {
                        "an inner attribute is not permitted following an outer doc comment"
                    } else if !attrs.is_empty() {
                        "an inner attribute is not permitted following an outer attribute"
                    } else {
                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                    };
                    let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted {
                        reason: inner_error_reason,
                        saw_doc_comment: just_parsed_doc_comment,
                        prev_attr_sp: attrs.last().and_then(|a| Some(a.span)),
                    };
                    let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                    attrs.push(attr);
                    just_parsed_doc_comment = false;
                }
                token::DocComment(s) => {
                    let attr = self.mk_doc_comment(s);
                    if attr.style != ast::AttrStyle::Outer {
                        let span = self.token.span;
                        let mut err = self.struct_span_err(span, "expected outer doc comment");
                        err.note(
                            "inner doc comments like this (starting with \
                                  `//!` or `/*!`) can only appear before items",
                        );
                        return Err(err);
                    }
                    attrs.push(attr);
                    self.bump();
                    just_parsed_doc_comment = true;
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
        let style = comments::doc_comment_style(&s.as_str());
        attr::mk_doc_comment(style, s, self.token.span)
    }

    /// Matches `attribute = # ! [ meta_item ]`.
    ///
    /// If `permit_inner` is `true`, then a leading `!` indicates an inner
    /// attribute.
    pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token);
        let inner_parse_policy = if permit_inner {
            InnerAttributeParsePolicy::Permitted
        } else {
            InnerAttributeParsePolicy::NotPermitted {
                reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
                saw_doc_comment: false,
                prev_attr_sp: None,
            }
        };
        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
    }

    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
    /// that prescribes how to handle inner attributes.
    fn parse_attribute_with_inner_parse_policy(
        &mut self,
        inner_parse_policy: InnerAttributeParsePolicy<'_>,
    ) -> PResult<'a, ast::Attribute> {
        debug!(
            "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
            inner_parse_policy, self.token
        );
        let (span, item, style) = match self.token.kind {
            token::Pound => {
                let lo = self.token.span;
                self.bump();

                if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                    self.expected_tokens.push(TokenType::Token(token::Not));
                }

                let style = if self.token == token::Not {
                    self.bump();
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                self.expect(&token::OpenDelim(token::Bracket))?;
                let item = self.parse_attr_item()?;
                self.expect(&token::CloseDelim(token::Bracket))?;
                let hi = self.prev_span;

                let attr_sp = lo.to(hi);

                // Emit error if inner attribute is encountered and not permitted
                if style == ast::AttrStyle::Inner {
                    if let InnerAttributeParsePolicy::NotPermitted {
                        reason,
                        saw_doc_comment,
                        prev_attr_sp,
                    } = inner_parse_policy
                    {
                        let prev_attr_note = if saw_doc_comment {
                            "previous doc comment"
                        } else {
                            "previous outer attribute"
                        };

                        let mut diagnostic = self.struct_span_err(attr_sp, reason);

                        if let Some(prev_attr_sp) = prev_attr_sp {
                            diagnostic
                                .span_label(attr_sp, "not permitted following an outer attibute")
                                .span_label(prev_attr_sp, prev_attr_note);
                        }

                        diagnostic
                            .note(
                                "inner attributes, like `#![no_std]`, annotate the item \
                                   enclosing them, and are usually found at the beginning of \
                                   source files. Outer attributes, like `#[test]`, annotate the \
                                   item following them.",
                            )
                            .emit()
                    }
                }

                (attr_sp, item, style)
            }
            _ => {
                let token_str = pprust::token_to_string(&self.token);
                let msg = &format!("expected `#`, found `{}`", token_str);
                return Err(self.struct_span_err(self.token.span, msg));
            }
        };

        Ok(attr::mk_attr_from_item(style, item, span))
    }

    /// Parses an inner part of an attribute (the path and following tokens).
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    ///     PATH `(` TOKEN_STREAM `)`
    ///     PATH `[` TOKEN_STREAM `]`
    ///     PATH `{` TOKEN_STREAM `}`
    ///     PATH
    ///     PATH `=` UNSUFFIXED_LIT
    /// The delimiters or `=` are still put into the resulting token stream.
    pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
        let item = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref item) => Some(item.clone()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(item) = item {
            self.bump();
            item
        } else {
            let path = self.parse_path(PathStyle::Mod)?;
            let args = self.parse_attr_args()?;
            ast::AttrItem { path, args }
        })
    }

    /// Parses attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.
    ///
    /// Matches `inner_attrs*`.
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            match self.token.kind {
                token::Pound => {
                    // Don't even try to parse if it's not an inner attribute.
                    if !self.look_ahead(1, |t| t == &token::Not) {
                        break;
                    }

                    let attr = self.parse_attribute(true)?;
                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                    attrs.push(attr);
                }
                token::DocComment(s) => {
                    // We need to get the position of this token before we bump.
                    let attr = self.mk_doc_comment(s);
                    if attr.style == ast::AttrStyle::Inner {
                        attrs.push(attr);
                        self.bump();
                    } else {
                        break;
                    }
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.kind.is_unsuffixed() {
            let msg = "suffixed literals are not allowed in attributes";
            self.struct_span_err(lit.span, msg)
                .help(
                    "instead of using a suffixed literal \
                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
                                    (1, 1.0, etc.).",
                )
                .emit()
        }

        Ok(lit)
    }

    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
        let cfg_predicate = self.parse_meta_item()?;
        self.expect(&token::Comma)?;

        // Presumably, the majority of the time there will only be one attr.
        let mut expanded_attrs = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            let lo = self.token.span;
            let item = self.parse_attr_item()?;
            expanded_attrs.push((item, lo.to(self.prev_span)));
            if !self.eat(&token::Comma) {
                break;
            }
        }

        Ok((cfg_predicate, expanded_attrs))
    }

    /// Matches `COMMASEP(meta_item_inner)`.
    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        // Presumably, the majority of the time there will only be one attr.
        let mut nmis = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            nmis.push(self.parse_meta_item_inner()?);
            if !self.eat(&token::Comma) {
                break;
            }
        }
        Ok(nmis)
    }

    /// Matches the following grammar (per RFC 1559).
    ///
    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(item) = nt_meta {
            return match item.meta(item.path.span) {
                Some(meta) => {
                    self.bump();
                    Ok(meta)
                }
                None => self.unexpected(),
            };
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let kind = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_span);
        Ok(ast::MetaItem { path, kind, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.check(&token::OpenDelim(token::Paren)) {
            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
            ast::MetaItemKind::List(list)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
            Err(ref mut err) => err.cancel(),
        }

        match self.parse_meta_item() {
            Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
            Err(ref mut err) => err.cancel(),
        }

        let found = pprust::token_to_string(&self.token);
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.struct_span_err(self.token.span, &msg))
    }
}
<|endoftext|>


<commit_before>// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{self, MetaItem};
use syntax::attr::HasAttrs;
use syntax::codemap;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;

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) => (
        ::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)*) => (
        ::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 custom;

#[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 allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
    Span {
        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
            call_site: span,
            callee: codemap::NameAndSpan {
                format: codemap::MacroAttribute(Symbol::intern(attr_name)),
                span: Some(span),
                allow_internal_unstable: true,
            },
        }),
        ..span
    }
}

pub fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Vec<Annotatable> {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let mut item = match annotatable {
        Annotatable::Item(item) => item,
        other => {
            cx.span_err(span, "`derive` can only be applied to items");
            return vec![other]
        }
    };

    let derive = Symbol::intern("derive");
    let mut derive_attrs = Vec::new();
    item = item.map_attrs(|attrs| {
        let partition = attrs.into_iter().partition(|attr| attr.name() == derive);
        derive_attrs = partition.0;
        partition.1
    });

    // Expand `#[derive]`s after other attribute macro invocations.
    if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
        return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
            attrs.push(cx.attribute(span, mitem.clone()));
            attrs.extend(derive_attrs);
            attrs
        }))];
    }

    let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
        if mitem.value_str().is_some() {
            cx.span_err(mitem.span, "unexpected value in `derive`");
        }

        let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
        if traits.is_empty() {
            cx.span_warn(mitem.span, "empty trait list in `derive`");
        }
        traits
    };

    let mut traits = get_traits(mitem, cx);
    for derive_attr in derive_attrs {
        traits.extend(get_traits(&derive_attr.value, cx));
    }

    // First, weed out malformed #[derive]
    traits.retain(|titem| {
        if titem.word().is_none() {
            cx.span_err(titem.span, "malformed `derive` entry");
            false
        } else {
            true
        }
    });

    // Next, check for old-style #[derive(Foo)]
    //
    // These all get expanded to `#[derive_Foo]` and will get expanded first. If
    // we actually add any attributes here then we return to get those expanded
    // and then eventually we'll come back to finish off the other derive modes.
    let mut new_attributes = Vec::new();
    traits.retain(|titem| {
        let tword = titem.word().unwrap();
        let tname = tword.name();

        if is_builtin_trait(tname) || {
            let derive_mode = ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(tname));
            cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| {
                if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false }
            }).unwrap_or(false)
        } {
            return true;
        }

        if !cx.ecfg.enable_custom_derive() {
            feature_gate::emit_feature_err(&cx.parse_sess,
                                           "custom_derive",
                                           titem.span,
                                           feature_gate::GateIssue::Language,
                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
        } else {
            let name = Symbol::intern(&format!("derive_{}", tname));
            if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
                cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
            }
            let mitem = cx.meta_word(titem.span, name);
            new_attributes.push(cx.attribute(mitem.span, mitem));
        }
        false
    });
    if new_attributes.len() > 0 {
        item = item.map(|mut i| {
            i.attrs.extend(new_attributes);
            if traits.len() > 0 {
                let list = cx.meta_list(mitem.span, derive, traits);
                i.attrs.push(cx.attribute(mitem.span, list));
            }
            i
        });
        return vec![Annotatable::Item(item)]
    }

    // Now check for macros-1.1 style custom #[derive].
    //
    // Expand each of them in order given, but *before* we expand any built-in
    // derive modes. The logic here is to:
    //
    // 1. Collect the remaining `#[derive]` annotations into a list. If
    //    there are any left, attach a `#[derive]` attribute to the item
    //    that we're currently expanding with the remaining derive modes.
    // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
    // 3. Expand the current item we're expanding, getting back a list of
    //    items that replace it.
    // 4. Extend the returned list with the current list of items we've
    //    collected so far.
    // 5. Return everything!
    //
    // If custom derive extensions end up threading through the `#[derive]`
    // attribute, we'll get called again later on to continue expanding
    // those modes.
    let macros_11_derive = traits.iter()
                                 .cloned()
                                 .enumerate()
                                 .filter(|&(_, ref name)| !is_builtin_trait(name.name().unwrap()))
                                 .next();
    if let Some((i, titem)) = macros_11_derive {
        let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
        let path = ast::Path::from_ident(titem.span, tname);
        let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();

        traits.remove(i);
        if traits.len() > 0 {
            item = item.map(|mut i| {
                let list = cx.meta_list(mitem.span, derive, traits);
                i.attrs.push(cx.attribute(mitem.span, list));
                i
            });
        }
        let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
        let mitem = cx.meta_list(titem.span, derive, vec![titem]);
        let item = Annotatable::Item(item);
        if let SyntaxExtension::CustomDerive(ref ext) = *ext {
            return ext.expand(cx, mitem.span, &mitem, item);
        } else {
            unreachable!()
        }
    }

    // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
    // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.

    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
    // `#[structural_match]` attribute.
    let (partial_eq, eq) = (Symbol::intern("PartialEq"), Symbol::intern("Eq"));
    if traits.iter().any(|t| t.name() == Some(partial_eq)) &&
       traits.iter().any(|t| t.name() == Some(eq)) {
        let structural_match = Symbol::intern("structural_match");
        let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
        let meta = cx.meta_word(span, structural_match);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
    // the same as the copy implementation.
    //
    // Add a marker attribute here picked up during #[derive(Clone)]
    let (copy, clone) = (Symbol::intern("Copy"), Symbol::intern("Clone"));
    if traits.iter().any(|t| t.name() == Some(clone)) &&
       traits.iter().any(|t| t.name() == Some(copy)) {
        let marker = Symbol::intern("rustc_copy_clone_marker");
        let span = allow_unstable(cx, span, "derive(Copy, Clone)");
        let meta = cx.meta_word(span, marker);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    let mut items = Vec::new();
    for titem in traits.iter() {
        let tname = titem.word().unwrap().name();
        let name = Symbol::intern(&format!("derive({})", tname));
        let mitem = cx.meta_word(titem.span, name);

        let span = Span {
            expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                call_site: titem.span,
                callee: codemap::NameAndSpan {
                    format: codemap::MacroAttribute(Symbol::intern(&format!("derive({})", tname))),
                    span: Some(titem.span),
                    allow_internal_unstable: true,
                },
            }),
            ..titem.span
        };

        let my_item = Annotatable::Item(item);
        expand_builtin(&tname.as_str(), cx, span, &mitem, &my_item, &mut |a| {
            items.push(a);
        });
        item = my_item.expect_item();
    }

    items.insert(0, Annotatable::Item(item));
    return items
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn is_builtin_trait(name: ast::Name) -> bool {
            match &*name.as_str() {
                $( $name )|+ => true,
                _ => false,
            }
        }

        fn expand_builtin(name: &str,
                          ecx: &mut ExtCtxt,
                          span: Span,
                          mitem: &MetaItem,
                          item: &Annotatable,
                          push: &mut FnMut(Annotatable)) {
            match name {
                $(
                    $name => {
                        warn_if_deprecated(ecx, span, $name);
                        $func(ecx, span, mitem, item, push);
                    }
                )*
                _ => panic!("not a builtin derive mode: {}", name),
            }
        }
    }
}

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,

    "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));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
            ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  mut span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>)
                  -> P<ast::Expr> {
    span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
        call_site: span,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute(Symbol::intern("derive")),
            span: Some(span),
            allow_internal_unstable: true,
        },
    });

    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![cx.stmt_expr(call)],
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span,
    }))
}
<commit_msg>Auto merge of #38947 - nrc:custom-derive-span, r=jseyfried<commit_after>// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{self, MetaItem};
use syntax::attr::HasAttrs;
use syntax::codemap;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;

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) => (
        ::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)*) => (
        ::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 custom;

#[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 allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
    Span {
        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
            call_site: span,
            callee: codemap::NameAndSpan {
                format: codemap::MacroAttribute(Symbol::intern(attr_name)),
                span: Some(span),
                allow_internal_unstable: true,
            },
        }),
        ..span
    }
}

pub fn expand_derive(cx: &mut ExtCtxt,
                     span: Span,
                     mitem: &MetaItem,
                     annotatable: Annotatable)
                     -> Vec<Annotatable> {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let mut item = match annotatable {
        Annotatable::Item(item) => item,
        other => {
            cx.span_err(span, "`derive` can only be applied to items");
            return vec![other]
        }
    };

    let derive = Symbol::intern("derive");
    let mut derive_attrs = Vec::new();
    item = item.map_attrs(|attrs| {
        let partition = attrs.into_iter().partition(|attr| attr.name() == derive);
        derive_attrs = partition.0;
        partition.1
    });

    // Expand `#[derive]`s after other attribute macro invocations.
    if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
        return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
            attrs.push(cx.attribute(span, mitem.clone()));
            attrs.extend(derive_attrs);
            attrs
        }))];
    }

    let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
        if mitem.value_str().is_some() {
            cx.span_err(mitem.span, "unexpected value in `derive`");
        }

        let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
        if traits.is_empty() {
            cx.span_warn(mitem.span, "empty trait list in `derive`");
        }
        traits
    };

    let mut traits = get_traits(mitem, cx);
    for derive_attr in derive_attrs {
        traits.extend(get_traits(&derive_attr.value, cx));
    }

    // First, weed out malformed #[derive]
    traits.retain(|titem| {
        if titem.word().is_none() {
            cx.span_err(titem.span, "malformed `derive` entry");
            false
        } else {
            true
        }
    });

    // Next, check for old-style #[derive(Foo)]
    //
    // These all get expanded to `#[derive_Foo]` and will get expanded first. If
    // we actually add any attributes here then we return to get those expanded
    // and then eventually we'll come back to finish off the other derive modes.
    let mut new_attributes = Vec::new();
    traits.retain(|titem| {
        let tword = titem.word().unwrap();
        let tname = tword.name();

        if is_builtin_trait(tname) || {
            let derive_mode = ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(tname));
            cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| {
                if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false }
            }).unwrap_or(false)
        } {
            return true;
        }

        if !cx.ecfg.enable_custom_derive() {
            feature_gate::emit_feature_err(&cx.parse_sess,
                                           "custom_derive",
                                           titem.span,
                                           feature_gate::GateIssue::Language,
                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
        } else {
            let name = Symbol::intern(&format!("derive_{}", tname));
            if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
                cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
            }
            let mitem = cx.meta_word(titem.span, name);
            new_attributes.push(cx.attribute(mitem.span, mitem));
        }
        false
    });
    if new_attributes.len() > 0 {
        item = item.map(|mut i| {
            i.attrs.extend(new_attributes);
            if traits.len() > 0 {
                let list = cx.meta_list(mitem.span, derive, traits);
                i.attrs.push(cx.attribute(mitem.span, list));
            }
            i
        });
        return vec![Annotatable::Item(item)]
    }

    // Now check for macros-1.1 style custom #[derive].
    //
    // Expand each of them in order given, but *before* we expand any built-in
    // derive modes. The logic here is to:
    //
    // 1. Collect the remaining `#[derive]` annotations into a list. If
    //    there are any left, attach a `#[derive]` attribute to the item
    //    that we're currently expanding with the remaining derive modes.
    // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
    // 3. Expand the current item we're expanding, getting back a list of
    //    items that replace it.
    // 4. Extend the returned list with the current list of items we've
    //    collected so far.
    // 5. Return everything!
    //
    // If custom derive extensions end up threading through the `#[derive]`
    // attribute, we'll get called again later on to continue expanding
    // those modes.
    let macros_11_derive = traits.iter()
                                 .cloned()
                                 .enumerate()
                                 .filter(|&(_, ref name)| !is_builtin_trait(name.name().unwrap()))
                                 .next();
    if let Some((i, titem)) = macros_11_derive {
        let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
        let path = ast::Path::from_ident(titem.span, tname);
        let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();

        traits.remove(i);
        if traits.len() > 0 {
            item = item.map(|mut i| {
                let list = cx.meta_list(mitem.span, derive, traits);
                i.attrs.push(cx.attribute(mitem.span, list));
                i
            });
        }
        let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
        let mitem = cx.meta_list(titem.span, derive, vec![titem]);
        let item = Annotatable::Item(item);

        let span = Span {
            expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                call_site: mitem.span,
                callee: codemap::NameAndSpan {
                    format: codemap::MacroAttribute(Symbol::intern(&format!("derive({})", tname))),
                    span: None,
                    allow_internal_unstable: false,
                },
            }),
            ..mitem.span
        };

        if let SyntaxExtension::CustomDerive(ref ext) = *ext {
            return ext.expand(cx, span, &mitem, item);
        } else {
            unreachable!()
        }
    }

    // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
    // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.

    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
    // `#[structural_match]` attribute.
    let (partial_eq, eq) = (Symbol::intern("PartialEq"), Symbol::intern("Eq"));
    if traits.iter().any(|t| t.name() == Some(partial_eq)) &&
       traits.iter().any(|t| t.name() == Some(eq)) {
        let structural_match = Symbol::intern("structural_match");
        let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
        let meta = cx.meta_word(span, structural_match);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
    // the same as the copy implementation.
    //
    // Add a marker attribute here picked up during #[derive(Clone)]
    let (copy, clone) = (Symbol::intern("Copy"), Symbol::intern("Clone"));
    if traits.iter().any(|t| t.name() == Some(clone)) &&
       traits.iter().any(|t| t.name() == Some(copy)) {
        let marker = Symbol::intern("rustc_copy_clone_marker");
        let span = allow_unstable(cx, span, "derive(Copy, Clone)");
        let meta = cx.meta_word(span, marker);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    let mut items = Vec::new();
    for titem in traits.iter() {
        let tname = titem.word().unwrap().name();
        let name = Symbol::intern(&format!("derive({})", tname));
        let mitem = cx.meta_word(titem.span, name);

        let span = Span {
            expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                call_site: titem.span,
                callee: codemap::NameAndSpan {
                    format: codemap::MacroAttribute(name),
                    span: None,
                    allow_internal_unstable: true,
                },
            }),
            ..titem.span
        };

        let my_item = Annotatable::Item(item);
        expand_builtin(&tname.as_str(), cx, span, &mitem, &my_item, &mut |a| {
            items.push(a);
        });
        item = my_item.expect_item();
    }

    items.insert(0, Annotatable::Item(item));
    return items
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn is_builtin_trait(name: ast::Name) -> bool {
            match &*name.as_str() {
                $( $name )|+ => true,
                _ => false,
            }
        }

        fn expand_builtin(name: &str,
                          ecx: &mut ExtCtxt,
                          span: Span,
                          mitem: &MetaItem,
                          item: &Annotatable,
                          push: &mut FnMut(Annotatable)) {
            match name {
                $(
                    $name => {
                        warn_if_deprecated(ecx, span, $name);
                        $func(ecx, span, mitem, item, push);
                    }
                )*
                _ => panic!("not a builtin derive mode: {}", name),
            }
        }
    }
}

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,

    "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));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
            ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  mut span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>)
                  -> P<ast::Expr> {
    span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
        call_site: span,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute(Symbol::intern("derive")),
            span: Some(span),
            allow_internal_unstable: true,
        },
    });

    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![cx.stmt_expr(call)],
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span,
    }))
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;

use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::io;
use std::iter;
use std::net::SocketAddr;
use std::rc::Rc;

use futures::Future;
use futures::stream::{self, Stream};
use futures::sync::mpsc;
use tokio_core::io::{read_exact, write_all, Io};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;

const MAX_BUFFERED: usize = 5;

fn main() {
    // Parse out what address we're going to listen on, defaulting to "something
    // reasonable"
    let addr = env::args().skip(1).next();
    let addr = addr.unwrap_or("127.0.0.1:8080".to_string());
    let addr: SocketAddr = addr.parse().unwrap();

    // Create the global state of our program. This involves the event loop (a
    // `Core`) to run all our I/O on, a TCP listener which we're going to accept
    // connections form, and finally the global hash map we're storing all
    // connection state in.
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let srv = TcpListener::bind(&addr, &handle).unwrap();
    println!("listening on {}", addr);
    let map = Rc::new(RefCell::new(HashMap::new()));

    // Create a small loop which will spawn off a new task for all accepted
    // connections. Each task will handle the messages for that connection
    // specifically, as well as listening for messages from other connections.
    //
    // Note that `futures::lazy` here is used for the call to `Io::split` below
    // in the `client` function, but it can mostly just be ignored.
    let srv = srv.incoming().for_each(|(socket, addr)| {
        let map = map.clone();
        handle.spawn(futures::lazy(move || {
            client(socket, addr, map)
        }));
        Ok(())
    });

    core.run(srv).unwrap();
}

/// Internal state saved for each client.
///
/// The "global hash map" is a hash of socket addresses to instances of this
/// type. An instance is available for all connected clients.
struct Client {
    // A channel to send messages over to be received and written out.
    tx: mpsc::UnboundedSender<Vec<u8>>,

    // Current number of pending messages. If too many messages are pending then
    // messages to this client are dropped on the floor.
    size: usize,
}

fn client(socket: TcpStream,
          addr: SocketAddr,
          map: Rc<RefCell<HashMap<SocketAddr, Client>>>)
          -> Box<Future<Item=(), Error=()>> {
    // First up, register our new client by creating an entry in the global
    // state map.
    let (tx, rx) = mpsc::unbounded();
    assert!(map.borrow_mut().insert(addr, Client {
        tx: tx,
        size: 0,
    }).is_none());

    // Next, we call the `Io::split` function here to easily work with both
    // halves of the socket as an instance of `Read` and `Write`. This'll allow
    // us to independently define the logic below without having to worry about
    // Rust's ownership of the original value.
    let (reader, writer) = socket.split();

    // Here we define how to read the socket. A small infinite iterator is
    // created to form a loop over reading messages off the socket. We use the
    // `read_exact` combinator to read messages from the socket, and once a
    // message is read it's dispatched to all other clients.
    //
    // Note that once a message is read we finish one iteration of the `fold`
    // and the reader is then passed on to the next to execute.
    //
    // Also note that this is where the backpressure logic for connected clients
    // comes into play. We don't send messages to clients that have too many
    // messages queued up already.
    let map2 = map.clone();
    let infinite = stream::iter(iter::repeat(()).map(Ok::<(), io::Error>));
    let reader = infinite.fold(reader, move |reader, ()| {
        let size = read_exact(reader, [0u8]);

        let msg = size.and_then(|(rd, size)| {
            let buf = vec![0u8; size[0] as usize];
            read_exact(rd, buf)
        });

        let map = map2.clone();
        msg.map(move |(rd, buf)| {
            for peer in map.borrow_mut().values_mut() {
                if peer.size < MAX_BUFFERED {
                    peer.size += 1;
                    peer.tx.send(buf.clone()).unwrap();
                }
            }
            rd
        })
    });

    // Here we define how to write messages to our client. This simply involves
    // iterating over all messages coming off the channel and writing them out
    // as per our protocol.
    let map2 = map.clone();
    let rx1 = rx.map_err(|_| -> ::std::io::Error { unreachable!() });
    let writer = rx1.fold(writer, move |writer, msg| {
        map2.borrow_mut().get_mut(&addr).unwrap().size -= 1;
        write_all(writer, [msg.len() as u8]).and_then(|(wr, _)| {
            write_all(wr, msg).map(|p| p.0)
        })
    });

    // Finally, we `select` over the read and the write halves. This means that
    // once either hits an error or finishes we're done. Note that the most
    // likely thing to happen here is the `reader` hits an error due to EOF (in
    // line with our use of `read_exact` above) which will cause the `select`
    // future to resolve.
    //
    // Once the reader/writer halves are done, we deregister ourselves from the
    // global map of connections. to free up our resources.
    let reader = reader.map(|_| ()).map_err(|_| ());
    let writer = writer.map(|_| ()).map_err(|_| ());
    Box::new(reader.select(writer).then(move |_| {
        assert!(map.borrow_mut().remove(&addr).is_some());
        Ok(())
    }))
}
<commit_msg>::std::io -> io<commit_after>extern crate futures;
extern crate tokio_core;

use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::io;
use std::iter;
use std::net::SocketAddr;
use std::rc::Rc;

use futures::Future;
use futures::stream::{self, Stream};
use futures::sync::mpsc;
use tokio_core::io::{read_exact, write_all, Io};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;

const MAX_BUFFERED: usize = 5;

fn main() {
    // Parse out what address we're going to listen on, defaulting to "something
    // reasonable"
    let addr = env::args().skip(1).next();
    let addr = addr.unwrap_or("127.0.0.1:8080".to_string());
    let addr: SocketAddr = addr.parse().unwrap();

    // Create the global state of our program. This involves the event loop (a
    // `Core`) to run all our I/O on, a TCP listener which we're going to accept
    // connections form, and finally the global hash map we're storing all
    // connection state in.
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let srv = TcpListener::bind(&addr, &handle).unwrap();
    println!("listening on {}", addr);
    let map = Rc::new(RefCell::new(HashMap::new()));

    // Create a small loop which will spawn off a new task for all accepted
    // connections. Each task will handle the messages for that connection
    // specifically, as well as listening for messages from other connections.
    //
    // Note that `futures::lazy` here is used for the call to `Io::split` below
    // in the `client` function, but it can mostly just be ignored.
    let srv = srv.incoming().for_each(|(socket, addr)| {
        let map = map.clone();
        handle.spawn(futures::lazy(move || {
            client(socket, addr, map)
        }));
        Ok(())
    });

    core.run(srv).unwrap();
}

/// Internal state saved for each client.
///
/// The "global hash map" is a hash of socket addresses to instances of this
/// type. An instance is available for all connected clients.
struct Client {
    // A channel to send messages over to be received and written out.
    tx: mpsc::UnboundedSender<Vec<u8>>,

    // Current number of pending messages. If too many messages are pending then
    // messages to this client are dropped on the floor.
    size: usize,
}

fn client(socket: TcpStream,
          addr: SocketAddr,
          map: Rc<RefCell<HashMap<SocketAddr, Client>>>)
          -> Box<Future<Item=(), Error=()>> {
    // First up, register our new client by creating an entry in the global
    // state map.
    let (tx, rx) = mpsc::unbounded();
    assert!(map.borrow_mut().insert(addr, Client {
        tx: tx,
        size: 0,
    }).is_none());

    // Next, we call the `Io::split` function here to easily work with both
    // halves of the socket as an instance of `Read` and `Write`. This'll allow
    // us to independently define the logic below without having to worry about
    // Rust's ownership of the original value.
    let (reader, writer) = socket.split();

    // Here we define how to read the socket. A small infinite iterator is
    // created to form a loop over reading messages off the socket. We use the
    // `read_exact` combinator to read messages from the socket, and once a
    // message is read it's dispatched to all other clients.
    //
    // Note that once a message is read we finish one iteration of the `fold`
    // and the reader is then passed on to the next to execute.
    //
    // Also note that this is where the backpressure logic for connected clients
    // comes into play. We don't send messages to clients that have too many
    // messages queued up already.
    let map2 = map.clone();
    let infinite = stream::iter(iter::repeat(()).map(Ok::<(), io::Error>));
    let reader = infinite.fold(reader, move |reader, ()| {
        let size = read_exact(reader, [0u8]);

        let msg = size.and_then(|(rd, size)| {
            let buf = vec![0u8; size[0] as usize];
            read_exact(rd, buf)
        });

        let map = map2.clone();
        msg.map(move |(rd, buf)| {
            for peer in map.borrow_mut().values_mut() {
                if peer.size < MAX_BUFFERED {
                    peer.size += 1;
                    peer.tx.send(buf.clone()).unwrap();
                }
            }
            rd
        })
    });

    // Here we define how to write messages to our client. This simply involves
    // iterating over all messages coming off the channel and writing them out
    // as per our protocol.
    let map2 = map.clone();
    let rx1 = rx.map_err(|_| -> io::Error { unreachable!() });
    let writer = rx1.fold(writer, move |writer, msg| {
        map2.borrow_mut().get_mut(&addr).unwrap().size -= 1;
        write_all(writer, [msg.len() as u8]).and_then(|(wr, _)| {
            write_all(wr, msg).map(|p| p.0)
        })
    });

    // Finally, we `select` over the read and the write halves. This means that
    // once either hits an error or finishes we're done. Note that the most
    // likely thing to happen here is the `reader` hits an error due to EOF (in
    // line with our use of `read_exact` above) which will cause the `select`
    // future to resolve.
    //
    // Once the reader/writer halves are done, we deregister ourselves from the
    // global map of connections. to free up our resources.
    let reader = reader.map(|_| ()).map_err(|_| ());
    let writer = writer.map(|_| ()).map_err(|_| ());
    Box::new(reader.select(writer).then(move |_| {
        assert!(map.borrow_mut().remove(&addr).is_some());
        Ok(())
    }))
}
<|endoftext|>


<commit_before>// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A radix trie for storing integers in sorted order

use prelude::*;

// FIXME: #3469: need to manually update TrieNode when SHIFT changes
const SHIFT: uint = 4;
const SIZE: uint = 1 << SHIFT;
const MASK: uint = SIZE - 1;

enum Child<T> {
    Internal(~TrieNode<T>),
    External(uint, T),
    Nothing
}

pub struct TrieMap<T> {
    priv root: TrieNode<T>,
    priv length: uint
}

impl<T> BaseIter<(uint, &T)> for TrieMap<T> {
    /// Visit all key-value pairs in order
    #[inline(always)]
    pure fn each(&self, f: fn(&(uint, &self/T)) -> bool) {
        self.root.each(f)
    }
    #[inline(always)]
    pure fn size_hint(&self) -> Option<uint> { Some(self.len()) }
}

impl<T> ReverseIter<(uint, &T)> for TrieMap<T> {
    /// Visit all key-value pairs in reverse order
    #[inline(always)]
    pure fn each_reverse(&self, f: fn(&(uint, &self/T)) -> bool) {
        self.root.each_reverse(f)
    }
}

impl<T> Container for TrieMap<T> {
    /// Return the number of elements in the map
    #[inline(always)]
    pure fn len(&self) -> uint { self.length }

    /// Return true if the map contains no elements
    #[inline(always)]
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T: Copy> Mutable for TrieMap<T> {
    /// Clear the map, removing all values.
    #[inline(always)]
    fn clear(&mut self) {
        self.root = TrieNode::new();
        self.length = 0;
    }
}

impl<T: Copy> Map<uint, T> for TrieMap<T> {
    /// Return true if the map contains a value for the specified key
    #[inline(always)]
    pure fn contains_key(&self, key: &uint) -> bool {
        self.find(key).is_some()
    }

    /// Visit all keys in order
    #[inline(always)]
    pure fn each_key(&self, f: fn(&uint) -> bool) {
        self.each(|&(k, _)| f(&k))
    }

    /// Visit all values in order
    #[inline(always)]
    pure fn each_value(&self, f: fn(&T) -> bool) { self.each(|&(_, v)| f(v)) }

    /// Return the value corresponding to the key in the map
    #[inline(hint)]
    pure fn find(&self, key: &uint) -> Option<&self/T> {
        let mut node: &self/TrieNode<T> = &self.root;
        let mut idx = 0;
        loop {
            match node.children[chunk(*key, idx)] {
              Internal(ref x) => node = &**x,
              External(stored, ref value) => {
                if stored == *key {
                    return Some(value)
                } else {
                    return None
                }
              }
              Nothing => return None
            }
            idx += 1;
        }
    }

    /// Insert a key-value pair into the map. An existing value for a
    /// key is replaced by the new value. Return true if the key did
    /// not already exist in the map.
    #[inline(always)]
    fn insert(&mut self, key: uint, value: T) -> bool {
        let ret = insert(&mut self.root.count,
                         &mut self.root.children[chunk(key, 0)],
                         key, value, 1);
        if ret { self.length += 1 }
        ret
    }

    /// Remove a key-value pair from the map. Return true if the key
    /// was present in the map, otherwise false.
    #[inline(always)]
    fn remove(&mut self, key: &uint) -> bool {
        let ret = remove(&mut self.root.count,
                         &mut self.root.children[chunk(*key, 0)],
                         *key, 1);
        if ret { self.length -= 1 }
        ret
    }
}

impl<T: Copy> TrieMap<T> {
    #[inline(always)]
    static pure fn new() -> TrieMap<T> {
        TrieMap{root: TrieNode::new(), length: 0}
    }
}

impl<T> TrieMap<T> {
    /// Visit all keys in reverse order
    #[inline(always)]
    pure fn each_key_reverse(&self, f: fn(&uint) -> bool) {
        self.each_reverse(|&(k, _)| f(&k))
    }

    /// Visit all values in reverse order
    #[inline(always)]
    pure fn each_value_reverse(&self, f: fn(&T) -> bool) {
        self.each_reverse(|&(_, v)| f(v))
    }

    /// Iterate over the map and mutate the contained values
    fn mutate_values(&mut self, f: fn(uint, &mut T) -> bool) {
        self.root.mutate_values(f)
    }
}

pub struct TrieSet {
    priv map: TrieMap<()>
}

impl BaseIter<uint> for TrieSet {
    /// Visit all values in order
    pure fn each(&self, f: fn(&uint) -> bool) { self.map.each_key(f) }
    pure fn size_hint(&self) -> Option<uint> { Some(self.len()) }
}

impl ReverseIter<uint> for TrieSet {
    /// Visit all values in reverse order
    pure fn each_reverse(&self, f: fn(&uint) -> bool) {
        self.map.each_key_reverse(f)
    }
}

impl Container for TrieSet {
    /// Return the number of elements in the set
    #[inline(always)]
    pure fn len(&self) -> uint { self.map.len() }

    /// Return true if the set contains no elements
    #[inline(always)]
    pure fn is_empty(&self) -> bool { self.map.is_empty() }
}

impl Mutable for TrieSet {
    /// Clear the set, removing all values.
    #[inline(always)]
    fn clear(&mut self) { self.map.clear() }
}

impl TrieSet {
    /// Return true if the set contains a value
    #[inline(always)]
    pure fn contains(&self, value: &uint) -> bool {
        self.map.contains_key(value)
    }

    /// Add a value to the set. Return true if the value was not already
    /// present in the set.
    #[inline(always)]
    fn insert(&mut self, value: uint) -> bool { self.map.insert(value, ()) }

    /// Remove a value from the set. Return true if the value was
    /// present in the set.
    #[inline(always)]
    fn remove(&mut self, value: &uint) -> bool { self.map.remove(value) }
}

struct TrieNode<T> {
    count: uint,
    children: [Child<T> * 16] // FIXME: #3469: can't use the SIZE constant yet
}

impl<T: Copy> TrieNode<T> {
    #[inline(always)]
    static pure fn new() -> TrieNode<T> {
        TrieNode{count: 0, children: [Nothing, ..SIZE]}
    }
}

impl<T> TrieNode<T> {
    pure fn each(&self, f: fn(&(uint, &self/T)) -> bool) {
        for uint::range(0, self.children.len()) |idx| {
            match self.children[idx] {
                Internal(ref x) => x.each(f),
                External(k, ref v) => if !f(&(k, v)) { return },
                Nothing => ()
            }
        }
    }

    pure fn each_reverse(&self, f: fn(&(uint, &self/T)) -> bool) {
        for uint::range_rev(self.children.len(), 0) |idx| {
            match self.children[idx - 1] {
                Internal(ref x) => x.each(f),
                External(k, ref v) => if !f(&(k, v)) { return },
                Nothing => ()
            }
        }
    }

    fn mutate_values(&mut self, f: fn(uint, &mut T) -> bool) {
        for vec::each_mut(self.children) |child| {
            match *child {
                Internal(ref mut x) => x.mutate_values(f),
                External(k, ref mut v) => if !f(k, v) { return },
                Nothing => ()
            }
        }
    }
}

// if this was done via a trait, the key could be generic
#[inline(always)]
pure fn chunk(n: uint, idx: uint) -> uint {
    let real_idx = uint::bytes - 1 - idx;
    (n >> (SHIFT * real_idx)) & MASK
}

fn insert<T: Copy>(count: &mut uint, child: &mut Child<T>, key: uint,
                   value: T, idx: uint) -> bool {
    match *child {
      External(stored_key, stored_value) => {
          if stored_key == key {
              false // already in the trie
          } else {
              // conflict - split the node
              let mut new = ~TrieNode::new();
              insert(&mut new.count,
                     &mut new.children[chunk(stored_key, idx)],
                     stored_key, stored_value, idx + 1);
              insert(&mut new.count, &mut new.children[chunk(key, idx)], key,
                     value, idx + 1);
              *child = Internal(new);
              true
          }
      }
      Internal(ref mut x) => {
        insert(&mut x.count, &mut x.children[chunk(key, idx)], key, value,
               idx + 1)
      }
      Nothing => {
        *count += 1;
        *child = External(key, value);
        true
      }
    }
}

fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
             idx: uint) -> bool {
    let (ret, this) = match *child {
      External(stored, _) => {
          if stored == key { (true, true) } else { (false, false) }
      }
      Internal(ref mut x) => {
          let ret = remove(&mut x.count, &mut x.children[chunk(key, idx)],
                           key, idx + 1);
          (ret, x.count == 0)
      }
      Nothing => (false, false)
    };

    if this {
        *child = Nothing;
        *count -= 1;
    }
    ret
}

#[cfg(test)]
pub fn check_integrity<T>(trie: &TrieNode<T>) {
    assert trie.count != 0;

    let mut sum = 0;

    for trie.children.each |x| {
        match *x {
          Nothing => (),
          Internal(ref y) => {
              check_integrity(&**y);
              sum += 1
          }
          External(_, _) => { sum += 1 }
        }
    }

    assert sum == trie.count;
}

#[cfg(test)]
mod tests {
    use super::*;
    use uint;

    #[test]
    fn test_step() {
        let mut trie = TrieMap::new();
        let n = 300;

        for uint::range_step(1, n, 2) |x| {
            assert trie.insert(x, x + 1);
            assert trie.contains_key(&x);
            check_integrity(&trie.root);
        }

        for uint::range_step(0, n, 2) |x| {
            assert !trie.contains_key(&x);
            assert trie.insert(x, x + 1);
            check_integrity(&trie.root);
        }

        for uint::range(0, n) |x| {
            assert trie.contains_key(&x);
            assert !trie.insert(x, x + 1);
            check_integrity(&trie.root);
        }

        for uint::range_step(1, n, 2) |x| {
            assert trie.remove(&x);
            assert !trie.contains_key(&x);
            check_integrity(&trie.root);
        }

        for uint::range_step(0, n, 2) |x| {
            assert trie.contains_key(&x);
            assert !trie.insert(x, x + 1);
            check_integrity(&trie.root);
        }
    }
}
<commit_msg>auto merge of #5237 : thestinger/rust/iter, r=nikomatsakis<commit_after>// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A radix trie for storing integers in sorted order

use prelude::*;

// FIXME: #3469: need to manually update TrieNode when SHIFT changes
const SHIFT: uint = 4;
const SIZE: uint = 1 << SHIFT;
const MASK: uint = SIZE - 1;

enum Child<T> {
    Internal(~TrieNode<T>),
    External(uint, T),
    Nothing
}

pub struct TrieMap<T> {
    priv root: TrieNode<T>,
    priv length: uint
}

impl<T> BaseIter<(uint, &T)> for TrieMap<T> {
    /// Visit all key-value pairs in order
    #[inline(always)]
    pure fn each(&self, f: fn(&(uint, &self/T)) -> bool) {
        self.root.each(f);
    }
    #[inline(always)]
    pure fn size_hint(&self) -> Option<uint> { Some(self.len()) }
}

impl<T> ReverseIter<(uint, &T)> for TrieMap<T> {
    /// Visit all key-value pairs in reverse order
    #[inline(always)]
    pure fn each_reverse(&self, f: fn(&(uint, &self/T)) -> bool) {
        self.root.each_reverse(f);
    }
}

impl<T> Container for TrieMap<T> {
    /// Return the number of elements in the map
    #[inline(always)]
    pure fn len(&self) -> uint { self.length }

    /// Return true if the map contains no elements
    #[inline(always)]
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T: Copy> Mutable for TrieMap<T> {
    /// Clear the map, removing all values.
    #[inline(always)]
    fn clear(&mut self) {
        self.root = TrieNode::new();
        self.length = 0;
    }
}

impl<T: Copy> Map<uint, T> for TrieMap<T> {
    /// Return true if the map contains a value for the specified key
    #[inline(always)]
    pure fn contains_key(&self, key: &uint) -> bool {
        self.find(key).is_some()
    }

    /// Visit all keys in order
    #[inline(always)]
    pure fn each_key(&self, f: fn(&uint) -> bool) {
        self.each(|&(k, _)| f(&k))
    }

    /// Visit all values in order
    #[inline(always)]
    pure fn each_value(&self, f: fn(&T) -> bool) { self.each(|&(_, v)| f(v)) }

    /// Return the value corresponding to the key in the map
    #[inline(hint)]
    pure fn find(&self, key: &uint) -> Option<&self/T> {
        let mut node: &self/TrieNode<T> = &self.root;
        let mut idx = 0;
        loop {
            match node.children[chunk(*key, idx)] {
              Internal(ref x) => node = &**x,
              External(stored, ref value) => {
                if stored == *key {
                    return Some(value)
                } else {
                    return None
                }
              }
              Nothing => return None
            }
            idx += 1;
        }
    }

    /// Insert a key-value pair into the map. An existing value for a
    /// key is replaced by the new value. Return true if the key did
    /// not already exist in the map.
    #[inline(always)]
    fn insert(&mut self, key: uint, value: T) -> bool {
        let ret = insert(&mut self.root.count,
                         &mut self.root.children[chunk(key, 0)],
                         key, value, 1);
        if ret { self.length += 1 }
        ret
    }

    /// Remove a key-value pair from the map. Return true if the key
    /// was present in the map, otherwise false.
    #[inline(always)]
    fn remove(&mut self, key: &uint) -> bool {
        let ret = remove(&mut self.root.count,
                         &mut self.root.children[chunk(*key, 0)],
                         *key, 1);
        if ret { self.length -= 1 }
        ret
    }
}

impl<T: Copy> TrieMap<T> {
    #[inline(always)]
    static pure fn new() -> TrieMap<T> {
        TrieMap{root: TrieNode::new(), length: 0}
    }
}

impl<T> TrieMap<T> {
    /// Visit all keys in reverse order
    #[inline(always)]
    pure fn each_key_reverse(&self, f: fn(&uint) -> bool) {
        self.each_reverse(|&(k, _)| f(&k))
    }

    /// Visit all values in reverse order
    #[inline(always)]
    pure fn each_value_reverse(&self, f: fn(&T) -> bool) {
        self.each_reverse(|&(_, v)| f(v))
    }

    /// Iterate over the map and mutate the contained values
    fn mutate_values(&mut self, f: fn(uint, &mut T) -> bool) {
        self.root.mutate_values(f);
    }
}

pub struct TrieSet {
    priv map: TrieMap<()>
}

impl BaseIter<uint> for TrieSet {
    /// Visit all values in order
    pure fn each(&self, f: fn(&uint) -> bool) { self.map.each_key(f) }
    pure fn size_hint(&self) -> Option<uint> { Some(self.len()) }
}

impl ReverseIter<uint> for TrieSet {
    /// Visit all values in reverse order
    pure fn each_reverse(&self, f: fn(&uint) -> bool) {
        self.map.each_key_reverse(f)
    }
}

impl Container for TrieSet {
    /// Return the number of elements in the set
    #[inline(always)]
    pure fn len(&self) -> uint { self.map.len() }

    /// Return true if the set contains no elements
    #[inline(always)]
    pure fn is_empty(&self) -> bool { self.map.is_empty() }
}

impl Mutable for TrieSet {
    /// Clear the set, removing all values.
    #[inline(always)]
    fn clear(&mut self) { self.map.clear() }
}

impl TrieSet {
    /// Return true if the set contains a value
    #[inline(always)]
    pure fn contains(&self, value: &uint) -> bool {
        self.map.contains_key(value)
    }

    /// Add a value to the set. Return true if the value was not already
    /// present in the set.
    #[inline(always)]
    fn insert(&mut self, value: uint) -> bool { self.map.insert(value, ()) }

    /// Remove a value from the set. Return true if the value was
    /// present in the set.
    #[inline(always)]
    fn remove(&mut self, value: &uint) -> bool { self.map.remove(value) }
}

struct TrieNode<T> {
    count: uint,
    children: [Child<T> * 16] // FIXME: #3469: can't use the SIZE constant yet
}

impl<T: Copy> TrieNode<T> {
    #[inline(always)]
    static pure fn new() -> TrieNode<T> {
        TrieNode{count: 0, children: [Nothing, ..SIZE]}
    }
}

impl<T> TrieNode<T> {
    pure fn each(&self, f: fn(&(uint, &self/T)) -> bool) -> bool {
        for uint::range(0, self.children.len()) |idx| {
            match self.children[idx] {
                Internal(ref x) => if !x.each(f) { return false },
                External(k, ref v) => if !f(&(k, v)) { return false },
                Nothing => ()
            }
        }
        true
    }

    pure fn each_reverse(&self, f: fn(&(uint, &self/T)) -> bool) -> bool {
        for uint::range_rev(self.children.len(), 0) |idx| {
            match self.children[idx - 1] {
                Internal(ref x) => if !x.each_reverse(f) { return false },
                External(k, ref v) => if !f(&(k, v)) { return false },
                Nothing => ()
            }
        }
        true
    }

    fn mutate_values(&mut self, f: fn(uint, &mut T) -> bool) -> bool {
        for vec::each_mut(self.children) |child| {
            match *child {
                Internal(ref mut x) => if !x.mutate_values(f) {
                    return false
                },
                External(k, ref mut v) => if !f(k, v) { return false },
                Nothing => ()
            }
        }
        true
    }
}

// if this was done via a trait, the key could be generic
#[inline(always)]
pure fn chunk(n: uint, idx: uint) -> uint {
    let real_idx = uint::bytes - 1 - idx;
    (n >> (SHIFT * real_idx)) & MASK
}

fn insert<T: Copy>(count: &mut uint, child: &mut Child<T>, key: uint,
                   value: T, idx: uint) -> bool {
    match *child {
      External(stored_key, stored_value) => {
          if stored_key == key {
              false // already in the trie
          } else {
              // conflict - split the node
              let mut new = ~TrieNode::new();
              insert(&mut new.count,
                     &mut new.children[chunk(stored_key, idx)],
                     stored_key, stored_value, idx + 1);
              insert(&mut new.count, &mut new.children[chunk(key, idx)], key,
                     value, idx + 1);
              *child = Internal(new);
              true
          }
      }
      Internal(ref mut x) => {
        insert(&mut x.count, &mut x.children[chunk(key, idx)], key, value,
               idx + 1)
      }
      Nothing => {
        *count += 1;
        *child = External(key, value);
        true
      }
    }
}

fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
             idx: uint) -> bool {
    let (ret, this) = match *child {
      External(stored, _) => {
          if stored == key { (true, true) } else { (false, false) }
      }
      Internal(ref mut x) => {
          let ret = remove(&mut x.count, &mut x.children[chunk(key, idx)],
                           key, idx + 1);
          (ret, x.count == 0)
      }
      Nothing => (false, false)
    };

    if this {
        *child = Nothing;
        *count -= 1;
    }
    ret
}

#[cfg(test)]
pub fn check_integrity<T>(trie: &TrieNode<T>) {
    assert trie.count != 0;

    let mut sum = 0;

    for trie.children.each |x| {
        match *x {
          Nothing => (),
          Internal(ref y) => {
              check_integrity(&**y);
              sum += 1
          }
          External(_, _) => { sum += 1 }
        }
    }

    assert sum == trie.count;
}

#[cfg(test)]
mod tests {
    use super::*;
    use uint;

    #[test]
    fn test_step() {
        let mut trie = TrieMap::new();
        let n = 300;

        for uint::range_step(1, n, 2) |x| {
            assert trie.insert(x, x + 1);
            assert trie.contains_key(&x);
            check_integrity(&trie.root);
        }

        for uint::range_step(0, n, 2) |x| {
            assert !trie.contains_key(&x);
            assert trie.insert(x, x + 1);
            check_integrity(&trie.root);
        }

        for uint::range(0, n) |x| {
            assert trie.contains_key(&x);
            assert !trie.insert(x, x + 1);
            check_integrity(&trie.root);
        }

        for uint::range_step(1, n, 2) |x| {
            assert trie.remove(&x);
            assert !trie.contains_key(&x);
            check_integrity(&trie.root);
        }

        for uint::range_step(0, n, 2) |x| {
            assert trie.contains_key(&x);
            assert !trie.insert(x, x + 1);
            check_integrity(&trie.root);
        }
    }

    #[test]
    fn test_each() {
        let mut m = TrieMap::new();

        assert m.insert(3, 6);
        assert m.insert(0, 0);
        assert m.insert(4, 8);
        assert m.insert(2, 4);
        assert m.insert(1, 2);

        let mut n = 0;
        for m.each |&(k, v)| {
            assert k == n;
            assert *v == n * 2;
            n += 1;
        }
    }

    #[test]
    fn test_each_break() {
        let mut m = TrieMap::new();

        for uint::range_rev(uint::max_value, uint::max_value - 10000) |x| {
            m.insert(x, x / 2);
        }

        let mut n = uint::max_value - 9999;
        for m.each |&(k, v)| {
            if n == uint::max_value - 5000 { break }
            assert n < uint::max_value - 5000;

            assert k == n;
            assert *v == n / 2;
            n += 1;
        }
    }

    #[test]
    fn test_each_reverse() {
        let mut m = TrieMap::new();

        assert m.insert(3, 6);
        assert m.insert(0, 0);
        assert m.insert(4, 8);
        assert m.insert(2, 4);
        assert m.insert(1, 2);

        let mut n = 4;
        for m.each_reverse |&(k, v)| {
            assert k == n;
            assert *v == n * 2;
            n -= 1;
        }
    }

    #[test]
    fn test_each_reverse_break() {
        let mut m = TrieMap::new();

        for uint::range_rev(uint::max_value, uint::max_value - 10000) |x| {
            m.insert(x, x / 2);
        }

        let mut n = uint::max_value;
        for m.each_reverse |&(k, v)| {
            if n == uint::max_value - 5000 { break }
            assert n > uint::max_value - 5000;

            assert k == n;
            assert *v == n / 2;
            n -= 1;
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::AttrBinding;
use dom::bindings::utils::{Reflectable, Reflector, DOMString};
use dom::bindings::utils::reflect_dom_object;
use dom::namespace::{Namespace, Null};
use dom::window::Window;

use std::util;

pub struct Attr {
    reflector_: Reflector,
    local_name: DOMString,
    value: DOMString,
    name: DOMString,
    namespace: Namespace,
    prefix: Option<DOMString>
}

impl Reflectable for Attr {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        &mut self.reflector_
    }
}

impl Attr {
    fn new_inherited(local_name: DOMString, value: DOMString,
                     name: DOMString, namespace: Namespace,
                     prefix: Option<DOMString>) -> Attr {
        Attr {
            reflector_: Reflector::new(),
            local_name: local_name,
            value: value,
            name: name, //TODO: Intern attribute names
            namespace: namespace,
            prefix: prefix
        }
    }

    pub fn new(window: &Window, local_name: DOMString, value: DOMString) -> @mut Attr {
        let name = local_name.clone();
        Attr::new_helper(window, local_name, value, name, Null, None)
    }

    pub fn new_ns(window: &Window, local_name: DOMString, value: DOMString,
                  name: DOMString, namespace: Namespace,
                  prefix: Option<DOMString>) -> @mut Attr {
        Attr::new_helper(window, name, value, local_name, namespace, prefix)
    }

    fn new_helper(window: &Window, name: DOMString, value: DOMString, local_name: DOMString,
                  namespace: Namespace, prefix: Option<DOMString>) -> @mut Attr {
        let attr = Attr::new_inherited(name, value, local_name, namespace, prefix);
        reflect_dom_object(@mut attr, window, AttrBinding::Wrap)
    }

    pub fn set_value(&mut self, mut value: DOMString) -> DOMString {
        util::swap(&mut self.value, &mut value);
        value
    }
}

impl Attr {
    pub fn LocalName(&self) -> DOMString {
        self.local_name.clone()
    }

    pub fn Value(&self) -> DOMString {
        self.value.clone()
    }

    pub fn SetValue(&mut self, value: DOMString) {
        self.value = value;
    }

    pub fn Name(&self) -> DOMString {
        self.name.clone()
    }

    pub fn GetNamespaceURI(&self) -> Option<DOMString> {
        self.namespace.to_str().map(|s| s.to_owned())
    }

    pub fn GetPrefix(&self) -> Option<DOMString> {
        self.prefix.clone()
    }
}
<commit_msg>Avoid mixing up local name and name when creating attributes.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::AttrBinding;
use dom::bindings::utils::{Reflectable, Reflector, DOMString};
use dom::bindings::utils::reflect_dom_object;
use dom::namespace::{Namespace, Null};
use dom::window::Window;

use std::util;

pub struct Attr {
    reflector_: Reflector,
    local_name: DOMString,
    value: DOMString,
    name: DOMString,
    namespace: Namespace,
    prefix: Option<DOMString>
}

impl Reflectable for Attr {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        &mut self.reflector_
    }
}

impl Attr {
    fn new_inherited(local_name: DOMString, value: DOMString,
                     name: DOMString, namespace: Namespace,
                     prefix: Option<DOMString>) -> Attr {
        Attr {
            reflector_: Reflector::new(),
            local_name: local_name,
            value: value,
            name: name, //TODO: Intern attribute names
            namespace: namespace,
            prefix: prefix
        }
    }

    pub fn new(window: &Window, local_name: DOMString, value: DOMString) -> @mut Attr {
        let name = local_name.clone();
        Attr::new_helper(window, local_name, value, name, Null, None)
    }

    pub fn new_ns(window: &Window, local_name: DOMString, value: DOMString,
                  name: DOMString, namespace: Namespace,
                  prefix: Option<DOMString>) -> @mut Attr {
        Attr::new_helper(window, local_name, value, name, namespace, prefix)
    }

    fn new_helper(window: &Window, local_name: DOMString, value: DOMString,
                  name: DOMString, namespace: Namespace,
                  prefix: Option<DOMString>) -> @mut Attr {
        let attr = Attr::new_inherited(local_name, value, name, namespace, prefix);
        reflect_dom_object(@mut attr, window, AttrBinding::Wrap)
    }

    pub fn set_value(&mut self, mut value: DOMString) -> DOMString {
        util::swap(&mut self.value, &mut value);
        value
    }
}

impl Attr {
    pub fn LocalName(&self) -> DOMString {
        self.local_name.clone()
    }

    pub fn Value(&self) -> DOMString {
        self.value.clone()
    }

    pub fn SetValue(&mut self, value: DOMString) {
        self.value = value;
    }

    pub fn Name(&self) -> DOMString {
        self.name.clone()
    }

    pub fn GetNamespaceURI(&self) -> Option<DOMString> {
        self.namespace.to_str().map(|s| s.to_owned())
    }

    pub fn GetPrefix(&self) -> Option<DOMString> {
        self.prefix.clone()
    }
}
<|endoftext|>