<commit_before>use godcoin::{prelude::*, script::*};
use std::{error::Error, num::ParseIntError};

#[derive(Clone, Debug)]
pub enum BuildError {
    EmptyScript,
    ScriptSizeOverflow,
    UnknownOp(String),
    MissingArgForOp(String),
    WifError(WifError),
    AssetParseError(AssetError),
    Other(String),
}

pub fn build(ops: &[String]) -> Result<Script, BuildError> {
    let mut builder = Builder::new();

    let mut iter = ops.iter();
    while let Some(op) = iter.next() {
        builder = match op.as_ref() {
            // Push value
            "OP_FALSE" => builder.try_push(OpFrame::False),
            "OP_TRUE" => builder.try_push(OpFrame::True),
            "OP_PUBKEY" => match iter.next() {
                Some(key) => {
                    let key = PublicKey::from_wif(key).map_err(BuildError::WifError)?;
                    builder.try_push(OpFrame::PubKey(key))
                }
                None => return Err(BuildError::MissingArgForOp(op.to_owned())),
            },
            "OP_SCRIPTHASH" => match iter.next() {
                Some(hash) => {
                    let hash = ScriptHash::from_wif(hash).map_err(BuildError::WifError)?;
                    builder.try_push(OpFrame::ScriptHash(hash))
                }
                None => return Err(BuildError::MissingArgForOp(op.to_owned())),
            },
            "OP_ASSET" => {
                let asset = iter.next();
                if let Some(asset) = asset {
                    let asset = asset.parse().map_err(BuildError::AssetParseError)?;
                    builder.try_push(OpFrame::Asset(asset))
                } else {
                    return Err(BuildError::MissingArgForOp(op.to_owned()));
                }
            }
            // Arithmetic
            "OP_LOADAMT" => builder.try_push(OpFrame::OpLoadAmt),
            "OP_LOADREMAMT" => builder.try_push(OpFrame::OpLoadRemAmt),
            "OP_ADD" => builder.try_push(OpFrame::OpAdd),
            "OP_SUB" => builder.try_push(OpFrame::OpSub),
            "OP_MUL" => builder.try_push(OpFrame::OpMul),
            "OP_DIV" => builder.try_push(OpFrame::OpDiv),
            // Logic
            "OP_NOT" => builder.try_push(OpFrame::OpNot),
            "OP_IF" => builder.try_push(OpFrame::OpIf),
            "OP_ELSE" => builder.try_push(OpFrame::OpElse),
            "OP_ENDIF" => builder.try_push(OpFrame::OpEndIf),
            "OP_RETURN" => builder.try_push(OpFrame::OpReturn),
            // Crypto
            "OP_CHECKSIG" => builder.try_push(OpFrame::OpCheckSig),
            "OP_CHECKSIGFASTFAIL" => builder.try_push(OpFrame::OpCheckSigFastFail),
            "OP_CHECKMULTISIG" => {
                let threshold = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                let key_count = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                builder.try_push(OpFrame::OpCheckMultiSig(threshold, key_count))
            }
            "OP_CHECKMULTISIGFASTFAIL" => {
                let threshold = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                let key_count = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                builder.try_push(OpFrame::OpCheckMultiSigFastFail(threshold, key_count))
            }
            _ => return Err(BuildError::UnknownOp(op.to_owned())),
        }
        .ok_or(BuildError::ScriptSizeOverflow)?;
    }

    if !builder.as_ref().is_empty() {
        Ok(builder.build())
    } else {
        Err(BuildError::EmptyScript)
    }
}
<commit_msg>Use match expression instead of if-else<commit_after>use godcoin::{prelude::*, script::*};
use std::{error::Error, num::ParseIntError};

#[derive(Clone, Debug)]
pub enum BuildError {
    EmptyScript,
    ScriptSizeOverflow,
    UnknownOp(String),
    MissingArgForOp(String),
    WifError(WifError),
    AssetParseError(AssetError),
    Other(String),
}

pub fn build(ops: &[String]) -> Result<Script, BuildError> {
    let mut builder = Builder::new();

    let mut iter = ops.iter();
    while let Some(op) = iter.next() {
        builder = match op.as_ref() {
            // Push value
            "OP_FALSE" => builder.try_push(OpFrame::False),
            "OP_TRUE" => builder.try_push(OpFrame::True),
            "OP_PUBKEY" => match iter.next() {
                Some(key) => {
                    let key = PublicKey::from_wif(key).map_err(BuildError::WifError)?;
                    builder.try_push(OpFrame::PubKey(key))
                }
                None => return Err(BuildError::MissingArgForOp(op.to_owned())),
            },
            "OP_SCRIPTHASH" => match iter.next() {
                Some(hash) => {
                    let hash = ScriptHash::from_wif(hash).map_err(BuildError::WifError)?;
                    builder.try_push(OpFrame::ScriptHash(hash))
                }
                None => return Err(BuildError::MissingArgForOp(op.to_owned())),
            },
            "OP_ASSET" => match iter.next() {
                Some(asset) => {
                    let asset = asset.parse().map_err(BuildError::AssetParseError)?;
                    builder.try_push(OpFrame::Asset(asset))
                }
                None => return Err(BuildError::MissingArgForOp(op.to_owned())),
            },
            // Arithmetic
            "OP_LOADAMT" => builder.try_push(OpFrame::OpLoadAmt),
            "OP_LOADREMAMT" => builder.try_push(OpFrame::OpLoadRemAmt),
            "OP_ADD" => builder.try_push(OpFrame::OpAdd),
            "OP_SUB" => builder.try_push(OpFrame::OpSub),
            "OP_MUL" => builder.try_push(OpFrame::OpMul),
            "OP_DIV" => builder.try_push(OpFrame::OpDiv),
            // Logic
            "OP_NOT" => builder.try_push(OpFrame::OpNot),
            "OP_IF" => builder.try_push(OpFrame::OpIf),
            "OP_ELSE" => builder.try_push(OpFrame::OpElse),
            "OP_ENDIF" => builder.try_push(OpFrame::OpEndIf),
            "OP_RETURN" => builder.try_push(OpFrame::OpReturn),
            // Crypto
            "OP_CHECKSIG" => builder.try_push(OpFrame::OpCheckSig),
            "OP_CHECKSIGFASTFAIL" => builder.try_push(OpFrame::OpCheckSigFastFail),
            "OP_CHECKMULTISIG" => {
                let threshold = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                let key_count = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                builder.try_push(OpFrame::OpCheckMultiSig(threshold, key_count))
            }
            "OP_CHECKMULTISIGFASTFAIL" => {
                let threshold = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                let key_count = iter
                    .next()
                    .ok_or_else(|| BuildError::MissingArgForOp(op.to_owned()))?
                    .parse()
                    .map_err(|e: ParseIntError| BuildError::Other(e.description().to_owned()))?;
                builder.try_push(OpFrame::OpCheckMultiSigFastFail(threshold, key_count))
            }
            _ => return Err(BuildError::UnknownOp(op.to_owned())),
        }
        .ok_or(BuildError::ScriptSizeOverflow)?;
    }

    if !builder.as_ref().is_empty() {
        Ok(builder.build())
    } else {
        Err(BuildError::EmptyScript)
    }
}
<|endoftext|>


<commit_before>//! Layout handling

use rustwlc::handle::{WlcView, WlcOutput};
use std::rc::{Rc, Weak};

#[derive(PartialEq, Clone, Copy)]
pub enum ContainerType {
    Root,        /* Root container, only one exists */
    Output,      /* Output, like a monitor or head */
    Workspace,   /* A workspace */
    View         /* A view (aka a window) */
}

/// Types of container
enum ContainerTypes {
    /// Root container, only one exists
    Root,
    /// WlcOutput/monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Layout mode for a container
enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Like i3, everything (workspaces, containers, views) are containable.
pub trait Containable {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable>;

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<Box<Containable>>>;

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType;

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool;

    /// Removes this container and all of its children
    fn remove_container(&self);

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibilty: bool);

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64);

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64);

    /// Finds a parent container with the given type
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable>;
}

/// View specific functions
pub trait Viewable {
    /// Determines if the view is full screen
    fn is_fullscreen(&self) -> bool;

    /// Figures out if the view is focused
    fn is_active(&self) -> bool;

    /// Returns true if this view is a parent is an ancestor of the child
    fn is_parent_of<T: Containable>(&self, child: T) -> bool;

    /// Returns true if this view is a child is an decedent of the parent
    fn is_child_of<T: Containable>(&self, parent: T) -> bool;

    /// Gets the active workspace of the view
    fn active_workspace<T: Containable>(&self) -> T;
}

struct Container {
    handle: Option<WlcOutput>,

    parent: Box<Containable>,
    children: Vec<Rc<Box<Containable>>>,
    type_: ContainerType,
    layout: Layout,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for Container {

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable> {
        match self.type_ {
            ContainerType::Root => None,
            _ => Some(&*self.parent),
        }
    }
    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<Box<Containable>>> {
        self.children.iter().map(|child| Rc::downgrade(&child)).collect()
    }

    fn get_type(&self) -> ContainerType {
        self.type_
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) {
        for child in self.get_children() {
            if let Some(child) = child.upgrade() {
                if let Ok(child) = Rc::try_unwrap(child) {
                    child.remove_container();
                    drop(child);
                }
            }
        }
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibilty: bool) {
        self.visible = visibilty
    }

    /// Gets the X (width) and Y (height) dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Finds a parent container with the given type, if there is any
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable> {
        let mut container = self.get_parent();
        while container.is_some() && container.unwrap().get_type() != type_ {
            container = container.unwrap().get_parent();
        }
        container
    }
}

struct View {
    handle: Option<WlcView>,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}
<commit_msg>Implemented most of the methods for Containable on View, fixed visibility type<commit_after>//! Layout handling

use rustwlc::handle::{WlcView, WlcOutput};
use std::rc::{Rc, Weak};

#[derive(PartialEq, Clone, Copy)]
pub enum ContainerType {
    Root,        /* Root container, only one exists */
    Output,      /* Output, like a monitor or head */
    Workspace,   /* A workspace */
    View         /* A view (aka a window) */
}

/// Types of container
enum ContainerTypes {
    /// Root container, only one exists
    Root,
    /// WlcOutput/monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Layout mode for a container
enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Like i3, everything (workspaces, containers, views) are containable.
pub trait Containable {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable>;

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<Box<Containable>>>;

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType;

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool;

    /// Removes this container and all of its children
    fn remove_container(&self);

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool);

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64);

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64);

    /// Finds a parent container with the given type
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable>;
}

/// View specific functions
pub trait Viewable {
    /// Determines if the view is full screen
    fn is_fullscreen(&self) -> bool;

    /// Figures out if the view is focused
    fn is_active(&self) -> bool;

    /// Returns true if this view is a parent is an ancestor of the child
    fn is_parent_of<T: Containable>(&self, child: T) -> bool;

    /// Returns true if this view is a child is an decedent of the parent
    fn is_child_of<T: Containable>(&self, parent: T) -> bool;

    /// Gets the active workspace of the view
    fn active_workspace<T: Containable>(&self) -> T;
}

struct Container {
    handle: Option<WlcOutput>,

    parent: Box<Containable>,
    children: Vec<Rc<Box<Containable>>>,
    type_: ContainerType,
    layout: Layout,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for Container {

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable> {
        match self.type_ {
            ContainerType::Root => None,
            _ => Some(&*self.parent),
        }
    }
    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<Box<Containable>>> {
        self.children.iter().map(|child| Rc::downgrade(&child)).collect()
    }

    fn get_type(&self) -> ContainerType {
        self.type_
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) {
        for child in self.get_children() {
            if let Some(child) = child.upgrade() {
                if let Ok(child) = Rc::try_unwrap(child) {
                    child.remove_container();
                    drop(child);
                }
            }
        }
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the X (width) and Y (height) dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Finds a parent container with the given type, if there is any
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable> {
        let mut container = self.get_parent();
        while container.is_some() && container.unwrap().get_type() != type_ {
            container = container.unwrap().get_parent();
        }
        container
    }
}

struct View {
    handle: Option<WlcView>,
    parent: Box<Containable>,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for View {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable> {
        Some(&*self.parent)
    }

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<Box<Containable>>> {
        unimplemented!();
    }

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType {
        ContainerType::View
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) {
        unimplemented!();
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Finds a parent container with the given type
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable> {
        unimplemented!();
    }
}
<|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/. */

// http://dev.w3.org/csswg/css-syntax/#parsing

use std::ascii::AsciiExt;
use std::str::CowString;
use super::{Token, Parser, Delimiter};

#[deriving(Copy, Eq, PartialEq)]
pub enum Priority {
    Normal,
    Important,
}

pub fn parse_important(input: &mut Parser) -> Result<Priority, ()> {
    match input.next() {
        Ok(Token::Delim('!')) => {
            match try!(input.next()) {
                Token::Ident(ref value) if value.eq_ignore_ascii_case("important") => {
                    Ok(Priority::Important)
                }
                token => input.unexpected(token)
            }
        }
        token => {
            input.push_back_result(token);
            Ok(Priority::Normal)
        }
    }
}

pub enum AtRulePrelude<P, R> {
    WithoutBlock(R),
    WithBlock(P),
    OptionalBlock(P),
}

// FIXME: Use associated types
pub trait DeclarationParser<D> {
    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<D, ()> {
        let _ = name;
        let _ = input;
        Err(())
    }
}

pub trait AtRuleParser<P, R> {
    fn parse_prelude(&mut self, name: &str, input: &mut Parser)
                     -> Result<AtRulePrelude<P, R>, ()> {
        let _ = name;
        let _ = input;
        Err(())
    }

    fn parse_block(&mut self, prelude: P, input: &mut Parser) -> Result<R, ()> {
        let _ = prelude;
        let _ = input;
        Err(())
    }

    /// An `OptionalBlock` prelude was followed by `;`
    fn rule_without_block(&mut self, prelude: P) -> Result<R, ()> {
        let _ = prelude;
        Err(())
    }
}

pub trait QualifiedRuleParser<P, R> {
    fn parse_prelude(&mut self, input: &mut Parser) -> Result<P, ()> {
        let _ = input;
        Err(())
    }

    fn parse_block(&mut self, prelude: P, input: &mut Parser) -> Result<R, ()> {
        let _ = prelude;
        let _ = input;
        Err(())
    }
}

pub struct DeclarationListParser<'i: 't, 't: 'a, 'a, AP, I, P>
where P: DeclarationParser<I> + AtRuleParser<AP, I> {
    pub input: &'a mut Parser<'i, 't>,
    pub parser: P,
}

impl<'i, 't, 'a, AP, I, P> DeclarationListParser<'i, 't, 'a, AP, I, P>
where P: DeclarationParser<I> + AtRuleParser<AP, I> {
    pub fn new(input: &'a mut Parser<'i, 't>, parser: P)
               -> DeclarationListParser<'i, 't, 'a, AP, I, P> {
        DeclarationListParser {
            input: input,
            parser: parser,
        }
    }
}

impl<'i, 't, 'a, AP, I, P> Iterator<Result<I, ()>>
for DeclarationListParser<'i, 't, 'a, AP, I, P>
where P: DeclarationParser<I> + AtRuleParser<AP, I> {
    fn next(&mut self) -> Option<Result<I, ()>> {
        loop {
            match self.input.next() {
                Ok(Token::Semicolon) => {}
                Ok(Token::Ident(name)) => {
                    return Some(parse_declaration(name, self.input, &mut self.parser))
                }
                Ok(Token::AtKeyword(name)) => {
                    return Some(parse_at_rule(name, self.input, &mut self.parser))
                }
                Ok(_) => {
                    return Some(self.input.err_consume_until_after(Delimiter::Semicolon))
                }
                Err(()) => return None,
            }
        }
    }
}

pub struct RuleListParser<'i: 't, 't: 'a, 'a, R, QP, AP, P>
where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    pub input: &'a mut Parser<'i, 't>,
    pub parser: P,
    is_stylesheet: bool,
}

impl<'i: 't, 't: 'a, 'a, R, QP, AP, P> RuleListParser<'i, 't, 'a, R, QP, AP, P>
where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    pub fn new_for_stylesheet(input: &'a mut Parser<'i, 't>, parser: P)
                              -> RuleListParser<'i, 't, 'a, R, QP, AP, P> {
        RuleListParser {
            input: input,
            parser: parser,
            is_stylesheet: true,
        }
    }

    pub fn new_for_nested_rule(input: &'a mut Parser<'i, 't>, parser: P)
                               -> RuleListParser<'i, 't, 'a, R, QP, AP, P> {
        RuleListParser {
            input: input,
            parser: parser,
            is_stylesheet: false,
        }
    }
}

impl<'i, 't, 'a, R, QP, AP, P> Iterator<Result<R, ()>>
for RuleListParser<'i, 't, 'a, R, QP, AP, P>
where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    fn next(&mut self) -> Option<Result<R, ()>> {
        loop {
            match self.input.next() {
                Ok(Token::CDO) | Ok(Token::CDC) if self.is_stylesheet => {}
                Ok(Token::AtKeyword(name)) => {
                    return Some(parse_at_rule(name, self.input, &mut self.parser))
                }
                Ok(token) => {
                    self.input.push_back(token);
                    return Some(parse_qualified_rule(self.input, &mut self.parser))
                }
                Err(()) => return None,
            }
        }
    }
}

pub fn parse_one_declaration<D, P>(input: &mut Parser, parser: &mut P)
                                   -> Result<D, ()>
                                   where P: DeclarationParser<D> {
    input.parse_entirely(|input| {
        let name = try!(input.expect_ident());
        try!(input.expect_colon());
        parser.parse_value(name.as_slice(), input)
    })
}

pub fn parse_one_rule<QP, AP, R, P>(input: &mut Parser, parser: &mut P)
                                    -> Result<R, ()>
                                    where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    input.parse_entirely(|input| {
        match try!(input.next()) {
            Token::AtKeyword(name) => {
                parse_at_rule(name, input, parser)
            }
            token => {
                input.push_back(token);
                parse_qualified_rule(input, parser)
            }
        }
    })
}

fn parse_declaration<D, P>(name: CowString, input: &mut Parser, parser: &mut P)
                           -> Result<D, ()>
                           where P: DeclarationParser<D> {
    let result = input.parse_until_before(Delimiter::Semicolon).parse_entirely(|input| {
        try!(input.expect_colon());
        parser.parse_value(name.as_slice(), input)
    });
    match input.next() {
        Ok(Token::Semicolon) | Err(()) => result,
        _ => input.err_consume_until_after(Delimiter::Semicolon)
    }
}

fn parse_at_rule<R, AP, P>(name: CowString, input: &mut Parser, parser: &mut P)
                           -> Result<R, ()>
                           where P: AtRuleParser<AP, R> {
    let delimiters = Delimiter::Semicolon | Delimiter::CurlyBracketBlock;
    let result = try!(input.parse_until_before(delimiters).parse_entirely(|input| {
        parser.parse_prelude(name.as_slice(), input)
    }).or_else(|()| input.err_consume_until_after(delimiters)));
    match result {
        AtRulePrelude::WithoutBlock(rule) => {
            match input.next() {
                Ok(Token::Semicolon) | Err(()) => Ok(rule),
                _ => input.err_consume_until_after(delimiters)
            }
        }
        AtRulePrelude::WithBlock(prelude) => {
            match input.next() {
                Ok(Token::CurlyBracketBlock) => {
                    // FIXME: Make parse_entirely take `FnOnce`
                    // and remove this Option dance.
                    let mut prelude = Some(prelude);
                    input.parse_nested_block().parse_entirely(|input| {
                        parser.parse_block(prelude.take().unwrap(), input)
                    })
                }
                _ => input.err_consume_until_after(delimiters)
            }
        }
        AtRulePrelude::OptionalBlock(prelude) => {
            match input.next() {
                Ok(Token::Semicolon) | Err(()) => parser.rule_without_block(prelude),
                Ok(Token::CurlyBracketBlock) => {
                    // FIXME: Make parse_entirely take `FnOnce`
                    // and remove this Option dance.
                    let mut prelude = Some(prelude);
                    input.parse_nested_block().parse_entirely(|input| {
                        parser.parse_block(prelude.take().unwrap(), input)
                    })
                }
                _ => input.err_consume_until_after(delimiters)
            }
        }
    }
}

fn parse_qualified_rule<R, AP, P>(input: &mut Parser, parser: &mut P)
                                  -> Result<R, ()>
                                  where P: QualifiedRuleParser<AP, R> {
    let prelude = try!(input.parse_until_before(Delimiter::CurlyBracketBlock)
                            .parse_entirely(|input| {
        parser.parse_prelude(input)
    }).or_else(|()| input.err_consume_until_after(Delimiter::CurlyBracketBlock)));
    match input.next() {
        Ok(Token::CurlyBracketBlock) => {
            // FIXME: Make parse_entirely take `FnOnce`
            // and remove this Option dance.
            let mut prelude = Some(prelude);
            input.parse_nested_block().parse_entirely(|input| {
                parser.parse_block(prelude.take().unwrap(), input)
            })
        }
        _ => input.err_consume_until_after(Delimiter::CurlyBracketBlock)
    }
}
<commit_msg>Add DeclarationListParser::run and RuleListParser::run.<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/. */

// http://dev.w3.org/csswg/css-syntax/#parsing

use std::ascii::AsciiExt;
use std::str::CowString;
use super::{Token, Parser, Delimiter};

#[deriving(Copy, Eq, PartialEq)]
pub enum Priority {
    Normal,
    Important,
}

pub fn parse_important(input: &mut Parser) -> Result<Priority, ()> {
    match input.next() {
        Ok(Token::Delim('!')) => {
            match try!(input.next()) {
                Token::Ident(ref value) if value.eq_ignore_ascii_case("important") => {
                    Ok(Priority::Important)
                }
                token => input.unexpected(token)
            }
        }
        token => {
            input.push_back_result(token);
            Ok(Priority::Normal)
        }
    }
}

pub enum AtRulePrelude<P, R> {
    WithoutBlock(R),
    WithBlock(P),
    OptionalBlock(P),
}

// FIXME: Use associated types
pub trait DeclarationParser<D> {
    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<D, ()> {
        let _ = name;
        let _ = input;
        Err(())
    }
}

pub trait AtRuleParser<P, R> {
    fn parse_prelude(&mut self, name: &str, input: &mut Parser)
                     -> Result<AtRulePrelude<P, R>, ()> {
        let _ = name;
        let _ = input;
        Err(())
    }

    fn parse_block(&mut self, prelude: P, input: &mut Parser) -> Result<R, ()> {
        let _ = prelude;
        let _ = input;
        Err(())
    }

    /// An `OptionalBlock` prelude was followed by `;`
    fn rule_without_block(&mut self, prelude: P) -> Result<R, ()> {
        let _ = prelude;
        Err(())
    }
}

pub trait QualifiedRuleParser<P, R> {
    fn parse_prelude(&mut self, input: &mut Parser) -> Result<P, ()> {
        let _ = input;
        Err(())
    }

    fn parse_block(&mut self, prelude: P, input: &mut Parser) -> Result<R, ()> {
        let _ = prelude;
        let _ = input;
        Err(())
    }
}

pub struct DeclarationListParser<'i: 't, 't: 'a, 'a, AP, I, P>
where P: DeclarationParser<I> + AtRuleParser<AP, I> {
    pub input: &'a mut Parser<'i, 't>,
    pub parser: P,
}

impl<'i, 't, 'a, AP, I, P> DeclarationListParser<'i, 't, 'a, AP, I, P>
where P: DeclarationParser<I> + AtRuleParser<AP, I> {
    pub fn new(input: &'a mut Parser<'i, 't>, parser: P)
               -> DeclarationListParser<'i, 't, 'a, AP, I, P> {
        DeclarationListParser {
            input: input,
            parser: parser,
        }
    }

    /// Parse until the input is exhausted, and ignore all results.
    /// This can be useful when `parser` collects results by mutating itself.
    pub fn run(mut self) -> P {
        while let Some(_) = self.next() {}
        self.parser
    }
}

impl<'i, 't, 'a, AP, I, P> Iterator<Result<I, ()>>
for DeclarationListParser<'i, 't, 'a, AP, I, P>
where P: DeclarationParser<I> + AtRuleParser<AP, I> {
    fn next(&mut self) -> Option<Result<I, ()>> {
        loop {
            match self.input.next() {
                Ok(Token::Semicolon) => {}
                Ok(Token::Ident(name)) => {
                    return Some(parse_declaration(name, self.input, &mut self.parser))
                }
                Ok(Token::AtKeyword(name)) => {
                    return Some(parse_at_rule(name, self.input, &mut self.parser))
                }
                Ok(_) => {
                    return Some(self.input.err_consume_until_after(Delimiter::Semicolon))
                }
                Err(()) => return None,
            }
        }
    }
}

pub struct RuleListParser<'i: 't, 't: 'a, 'a, R, QP, AP, P>
where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    pub input: &'a mut Parser<'i, 't>,
    pub parser: P,
    is_stylesheet: bool,
}

impl<'i: 't, 't: 'a, 'a, R, QP, AP, P> RuleListParser<'i, 't, 'a, R, QP, AP, P>
where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    pub fn new_for_stylesheet(input: &'a mut Parser<'i, 't>, parser: P)
                              -> RuleListParser<'i, 't, 'a, R, QP, AP, P> {
        RuleListParser {
            input: input,
            parser: parser,
            is_stylesheet: true,
        }
    }

    pub fn new_for_nested_rule(input: &'a mut Parser<'i, 't>, parser: P)
                               -> RuleListParser<'i, 't, 'a, R, QP, AP, P> {
        RuleListParser {
            input: input,
            parser: parser,
            is_stylesheet: false,
        }
    }

    /// Parse until the input is exhausted, and ignore all results.
    /// This can be useful when `parser` collects results by mutating itself.
    pub fn run(mut self) -> P {
        while let Some(_) = self.next() {}
        self.parser
    }
}

impl<'i, 't, 'a, R, QP, AP, P> Iterator<Result<R, ()>>
for RuleListParser<'i, 't, 'a, R, QP, AP, P>
where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    fn next(&mut self) -> Option<Result<R, ()>> {
        loop {
            match self.input.next() {
                Ok(Token::CDO) | Ok(Token::CDC) if self.is_stylesheet => {}
                Ok(Token::AtKeyword(name)) => {
                    return Some(parse_at_rule(name, self.input, &mut self.parser))
                }
                Ok(token) => {
                    self.input.push_back(token);
                    return Some(parse_qualified_rule(self.input, &mut self.parser))
                }
                Err(()) => return None,
            }
        }
    }
}

pub fn parse_one_declaration<D, P>(input: &mut Parser, parser: &mut P)
                                   -> Result<D, ()>
                                   where P: DeclarationParser<D> {
    input.parse_entirely(|input| {
        let name = try!(input.expect_ident());
        try!(input.expect_colon());
        parser.parse_value(name.as_slice(), input)
    })
}

pub fn parse_one_rule<QP, AP, R, P>(input: &mut Parser, parser: &mut P)
                                    -> Result<R, ()>
                                    where P: QualifiedRuleParser<QP, R> + AtRuleParser<AP, R> {
    input.parse_entirely(|input| {
        match try!(input.next()) {
            Token::AtKeyword(name) => {
                parse_at_rule(name, input, parser)
            }
            token => {
                input.push_back(token);
                parse_qualified_rule(input, parser)
            }
        }
    })
}

fn parse_declaration<D, P>(name: CowString, input: &mut Parser, parser: &mut P)
                           -> Result<D, ()>
                           where P: DeclarationParser<D> {
    let result = input.parse_until_before(Delimiter::Semicolon).parse_entirely(|input| {
        try!(input.expect_colon());
        parser.parse_value(name.as_slice(), input)
    });
    match input.next() {
        Ok(Token::Semicolon) | Err(()) => result,
        _ => input.err_consume_until_after(Delimiter::Semicolon)
    }
}

fn parse_at_rule<R, AP, P>(name: CowString, input: &mut Parser, parser: &mut P)
                           -> Result<R, ()>
                           where P: AtRuleParser<AP, R> {
    let delimiters = Delimiter::Semicolon | Delimiter::CurlyBracketBlock;
    let result = try!(input.parse_until_before(delimiters).parse_entirely(|input| {
        parser.parse_prelude(name.as_slice(), input)
    }).or_else(|()| input.err_consume_until_after(delimiters)));
    match result {
        AtRulePrelude::WithoutBlock(rule) => {
            match input.next() {
                Ok(Token::Semicolon) | Err(()) => Ok(rule),
                _ => input.err_consume_until_after(delimiters)
            }
        }
        AtRulePrelude::WithBlock(prelude) => {
            match input.next() {
                Ok(Token::CurlyBracketBlock) => {
                    // FIXME: Make parse_entirely take `FnOnce`
                    // and remove this Option dance.
                    let mut prelude = Some(prelude);
                    input.parse_nested_block().parse_entirely(|input| {
                        parser.parse_block(prelude.take().unwrap(), input)
                    })
                }
                _ => input.err_consume_until_after(delimiters)
            }
        }
        AtRulePrelude::OptionalBlock(prelude) => {
            match input.next() {
                Ok(Token::Semicolon) | Err(()) => parser.rule_without_block(prelude),
                Ok(Token::CurlyBracketBlock) => {
                    // FIXME: Make parse_entirely take `FnOnce`
                    // and remove this Option dance.
                    let mut prelude = Some(prelude);
                    input.parse_nested_block().parse_entirely(|input| {
                        parser.parse_block(prelude.take().unwrap(), input)
                    })
                }
                _ => input.err_consume_until_after(delimiters)
            }
        }
    }
}

fn parse_qualified_rule<R, AP, P>(input: &mut Parser, parser: &mut P)
                                  -> Result<R, ()>
                                  where P: QualifiedRuleParser<AP, R> {
    let prelude = try!(input.parse_until_before(Delimiter::CurlyBracketBlock)
                            .parse_entirely(|input| {
        parser.parse_prelude(input)
    }).or_else(|()| input.err_consume_until_after(Delimiter::CurlyBracketBlock)));
    match input.next() {
        Ok(Token::CurlyBracketBlock) => {
            // FIXME: Make parse_entirely take `FnOnce`
            // and remove this Option dance.
            let mut prelude = Some(prelude);
            input.parse_nested_block().parse_entirely(|input| {
                parser.parse_block(prelude.take().unwrap(), input)
            })
        }
        _ => input.err_consume_until_after(Delimiter::CurlyBracketBlock)
    }
}
<|endoftext|>


<commit_before>// Copyright 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.

//! Lints in the Rust compiler.
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_plugin` respectively.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![cfg_attr(test, feature(test))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(i128_type)]
#![feature(macro_vis_matcher)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![cfg_attr(stage0, feature(never_type))]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate log;
extern crate rustc_mir;
extern crate syntax_pos;

use rustc::lint;
use rustc::lint::builtin::BARE_TRAIT_OBJECT;
use rustc::session;
use rustc::util;

use session::Session;
use syntax::epoch::Epoch;
use lint::LintId;
use lint::FutureIncompatibleInfo;

mod bad_style;
mod builtin;
mod types;
mod unused;

use bad_style::*;
use builtin::*;
use types::*;
use unused::*;

/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
    macro_rules! add_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_early_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_early_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_builtin_with_new {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name::new());
                )*}
            )
    }

    macro_rules! add_early_builtin_with_new {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_early_pass($sess, false, box $name::new());
                )*}
            )
    }

    macro_rules! add_lint_group {
        ($sess:ident, $name:expr, $($lint:ident),*) => (
            store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
            )
    }

    add_early_builtin!(sess,
                       UnusedParens,
                       UnusedImportBraces,
                       AnonymousParameters,
                       UnusedDocComment,
                       IgnoredGenericBounds,
                       );

    add_early_builtin_with_new!(sess,
                                DeprecatedAttr,
                                );

    add_builtin!(sess,
                 HardwiredLints,
                 WhileTrue,
                 ImproperCTypes,
                 VariantSizeDifferences,
                 BoxPointers,
                 UnusedAttributes,
                 PathStatements,
                 UnusedResults,
                 NonCamelCaseTypes,
                 NonSnakeCase,
                 NonUpperCaseGlobals,
                 NonShorthandFieldPatterns,
                 UnsafeCode,
                 UnusedAllocation,
                 MissingCopyImplementations,
                 UnstableFeatures,
                 UnconditionalRecursion,
                 InvalidNoMangleItems,
                 PluginAsLibrary,
                 MutableTransmutes,
                 UnionsWithDropFields,
                 UnreachablePub,
                 );

    add_builtin_with_new!(sess,
                          TypeLimits,
                          MissingDoc,
                          MissingDebugImplementations,
                          );

    add_lint_group!(sess,
                    "bad_style",
                    NON_CAMEL_CASE_TYPES,
                    NON_SNAKE_CASE,
                    NON_UPPER_CASE_GLOBALS);

    add_lint_group!(sess,
                    "nonstandard_style",
                    NON_CAMEL_CASE_TYPES,
                    NON_SNAKE_CASE,
                    NON_UPPER_CASE_GLOBALS);

    add_lint_group!(sess,
                    "unused",
                    UNUSED_IMPORTS,
                    UNUSED_VARIABLES,
                    UNUSED_ASSIGNMENTS,
                    DEAD_CODE,
                    UNUSED_MUT,
                    UNREACHABLE_CODE,
                    UNREACHABLE_PATTERNS,
                    UNUSED_MUST_USE,
                    UNUSED_UNSAFE,
                    PATH_STATEMENTS,
                    UNUSED_ATTRIBUTES,
                    UNUSED_MACROS,
                    UNUSED_ALLOCATION,
                    UNUSED_DOC_COMMENT,
                    UNUSED_EXTERN_CRATES,
                    UNUSED_FEATURES,
                    UNUSED_PARENS);

    add_lint_group!(sess,
                    "rust_2018_idioms",
                    BARE_TRAIT_OBJECT,
                    UNREACHABLE_PUB);

    // Guidelines for creating a future incompatibility lint:
    //
    // - Create a lint defaulting to warn as normal, with ideally the same error
    //   message you would normally give
    // - Add a suitable reference, typically an RFC or tracking issue. Go ahead
    //   and include the full URL, sort items in ascending order of issue numbers.
    // - Later, change lint to error
    // - Eventually, remove lint
    store.register_future_incompatible(sess,
                                       vec![
        FutureIncompatibleInfo {
            id: LintId::of(PRIVATE_IN_PUBLIC),
            reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE),
            reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
            reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(SAFE_EXTERN_STATICS),
            reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
            reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
            reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LEGACY_IMPORTS),
            reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
            reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
            reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
            reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(ANONYMOUS_PARAMETERS),
            reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
            reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
            reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(SAFE_PACKED_BORROWS),
            reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
            reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
            reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
            epoch: Some(Epoch::Epoch2018),
        }
        ]);

    // Register renamed and removed lints
    store.register_renamed("unknown_features", "unused_features");
    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
    store.register_removed("negate_unsigned", "cast a signed value instead");
    store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
    // This was renamed to raw_pointer_derive, which was then removed,
    // so it is also considered removed
    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
    store.register_removed("drop_with_repr_extern", "drop flags have been removed");
    store.register_removed("fat_ptr_transmutes", "was accidentally removed back in 2014");
    store.register_removed("deprecated_attr", "use `deprecated` instead");
    store.register_removed("transmute_from_fn_item_types",
        "always cast functions before transmuting them");
    store.register_removed("hr_lifetime_in_assoc_type",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/33685");
    store.register_removed("inaccessible_extern_crate",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36886");
    store.register_removed("super_or_self_in_global_path",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36888");
    store.register_removed("overlapping_inherent_impls",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36889");
    store.register_removed("illegal_floating_point_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36890");
    store.register_removed("illegal_struct_or_enum_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36891");
    store.register_removed("lifetime_underscore",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
    store.register_removed("extra_requirement_in_impl",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
}
<commit_msg>register removed lints<commit_after>// Copyright 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.

//! Lints in the Rust compiler.
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_plugin` respectively.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![cfg_attr(test, feature(test))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(i128_type)]
#![feature(macro_vis_matcher)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![cfg_attr(stage0, feature(never_type))]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate log;
extern crate rustc_mir;
extern crate syntax_pos;

use rustc::lint;
use rustc::lint::builtin::BARE_TRAIT_OBJECT;
use rustc::session;
use rustc::util;

use session::Session;
use syntax::epoch::Epoch;
use lint::LintId;
use lint::FutureIncompatibleInfo;

mod bad_style;
mod builtin;
mod types;
mod unused;

use bad_style::*;
use builtin::*;
use types::*;
use unused::*;

/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
    macro_rules! add_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_early_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_early_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_builtin_with_new {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name::new());
                )*}
            )
    }

    macro_rules! add_early_builtin_with_new {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_early_pass($sess, false, box $name::new());
                )*}
            )
    }

    macro_rules! add_lint_group {
        ($sess:ident, $name:expr, $($lint:ident),*) => (
            store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
            )
    }

    add_early_builtin!(sess,
                       UnusedParens,
                       UnusedImportBraces,
                       AnonymousParameters,
                       UnusedDocComment,
                       IgnoredGenericBounds,
                       );

    add_early_builtin_with_new!(sess,
                                DeprecatedAttr,
                                );

    add_builtin!(sess,
                 HardwiredLints,
                 WhileTrue,
                 ImproperCTypes,
                 VariantSizeDifferences,
                 BoxPointers,
                 UnusedAttributes,
                 PathStatements,
                 UnusedResults,
                 NonCamelCaseTypes,
                 NonSnakeCase,
                 NonUpperCaseGlobals,
                 NonShorthandFieldPatterns,
                 UnsafeCode,
                 UnusedAllocation,
                 MissingCopyImplementations,
                 UnstableFeatures,
                 UnconditionalRecursion,
                 InvalidNoMangleItems,
                 PluginAsLibrary,
                 MutableTransmutes,
                 UnionsWithDropFields,
                 UnreachablePub,
                 );

    add_builtin_with_new!(sess,
                          TypeLimits,
                          MissingDoc,
                          MissingDebugImplementations,
                          );

    add_lint_group!(sess,
                    "bad_style",
                    NON_CAMEL_CASE_TYPES,
                    NON_SNAKE_CASE,
                    NON_UPPER_CASE_GLOBALS);

    add_lint_group!(sess,
                    "nonstandard_style",
                    NON_CAMEL_CASE_TYPES,
                    NON_SNAKE_CASE,
                    NON_UPPER_CASE_GLOBALS);

    add_lint_group!(sess,
                    "unused",
                    UNUSED_IMPORTS,
                    UNUSED_VARIABLES,
                    UNUSED_ASSIGNMENTS,
                    DEAD_CODE,
                    UNUSED_MUT,
                    UNREACHABLE_CODE,
                    UNREACHABLE_PATTERNS,
                    UNUSED_MUST_USE,
                    UNUSED_UNSAFE,
                    PATH_STATEMENTS,
                    UNUSED_ATTRIBUTES,
                    UNUSED_MACROS,
                    UNUSED_ALLOCATION,
                    UNUSED_DOC_COMMENT,
                    UNUSED_EXTERN_CRATES,
                    UNUSED_FEATURES,
                    UNUSED_PARENS);

    add_lint_group!(sess,
                    "rust_2018_idioms",
                    BARE_TRAIT_OBJECT,
                    UNREACHABLE_PUB);

    // Guidelines for creating a future incompatibility lint:
    //
    // - Create a lint defaulting to warn as normal, with ideally the same error
    //   message you would normally give
    // - Add a suitable reference, typically an RFC or tracking issue. Go ahead
    //   and include the full URL, sort items in ascending order of issue numbers.
    // - Later, change lint to error
    // - Eventually, remove lint
    store.register_future_incompatible(sess,
                                       vec![
        FutureIncompatibleInfo {
            id: LintId::of(PRIVATE_IN_PUBLIC),
            reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE),
            reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
            reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(SAFE_EXTERN_STATICS),
            reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
            reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
            reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LEGACY_IMPORTS),
            reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
            reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
            reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
            reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(ANONYMOUS_PARAMETERS),
            reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
            reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
            reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(SAFE_PACKED_BORROWS),
            reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
            reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
            epoch: None,
        },
        FutureIncompatibleInfo {
            id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
            reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
            epoch: Some(Epoch::Epoch2018),
        }
        ]);

    // Register renamed and removed lints
    store.register_renamed("unknown_features", "unused_features");
    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
    store.register_removed("negate_unsigned", "cast a signed value instead");
    store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
    // This was renamed to raw_pointer_derive, which was then removed,
    // so it is also considered removed
    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
    store.register_removed("drop_with_repr_extern", "drop flags have been removed");
    store.register_removed("fat_ptr_transmutes", "was accidentally removed back in 2014");
    store.register_removed("deprecated_attr", "use `deprecated` instead");
    store.register_removed("transmute_from_fn_item_types",
        "always cast functions before transmuting them");
    store.register_removed("hr_lifetime_in_assoc_type",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/33685");
    store.register_removed("inaccessible_extern_crate",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36886");
    store.register_removed("super_or_self_in_global_path",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36888");
    store.register_removed("overlapping_inherent_impls",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36889");
    store.register_removed("illegal_floating_point_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36890");
    store.register_removed("illegal_struct_or_enum_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36891");
    store.register_removed("lifetime_underscore",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
    store.register_removed("extra_requirement_in_impl",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
    store.register_removed("coerce_never",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
    store.register_removed("resolve_trait_on_defaulted_unit",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
}
<|endoftext|>


<commit_before>use std::slice::raw::buf_as_slice;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

pub enum Object { }

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	ptr: *const c_void,
}

pub struct Method {
	ptr: *mut c_void,
}

pub struct Class {
	ptr: *mut Object,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> Class;
	pub fn class_getName(cls: Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: Class) -> size_t;
	pub fn class_getInstanceMethod(cls: Class, sel: Sel) -> Method;
	pub fn class_getInstanceVariable(cls: Class, name: *const c_char) -> Ivar;
	pub fn class_copyIvarList(cls: Class, outCount: *mut c_uint) -> *mut Ivar;
	pub fn class_addMethod(cls: Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: Class, name: *const c_char, extraBytes: size_t) -> Class;
	pub fn objc_disposeClassPair(cls: Class);
	pub fn objc_registerClassPair(cls: Class);

	pub fn object_setInstanceVariable(obj: *mut Object, name: *const c_char, value: *mut c_void) -> Ivar;
	pub fn object_getInstanceVariable(obj: *mut Object, name: *const c_char, outValue: *mut *mut c_void) -> Ivar;
	pub fn object_setIvar(obj: *mut Object, ivar: Ivar, value: *mut Object);
	pub fn object_getIvar(obj: *mut Object, ivar: Ivar) -> *mut Object;
	pub fn object_getClass(obj: *mut Object) -> Class;

	pub fn ivar_getName(ivar: Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: Method) -> Sel;
	pub fn method_getImplementation(method: Method) -> Imp;
	pub fn method_getTypeEncoding(method: Method) -> *const c_char;
	pub fn method_getNumberOfArguments(method: Method) -> c_uint;
	pub fn method_setImplementation(method: Method, imp: Imp) -> Imp;
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(*self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(*self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Clone for Ivar {
	fn clone(&self) -> Ivar { *self }
}

impl Method {
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(*self)
		}
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(*self);
			c_str_to_static_slice(encoding)
		}
	}

	pub fn arguments(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(*self) as uint
		}
	}

	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(*self)
		}
	}

	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(*self, imp)
	}
}

impl Object {
	pub fn class(&self) -> Class {
		unsafe {
			object_getClass(self as *const Object as *mut Object)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

impl Class {
	pub fn get(name: &str) -> Option<Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.ptr.is_null() {
			None
		} else {
			Some(cls)
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(*self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<Method> {
		let method = unsafe {
			class_getInstanceMethod(*self, sel)
		};
		if method.ptr.is_null() {
			None
		} else {
			Some(method)
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<Ivar> {
		let ivar = name.with_c_str(|name| unsafe {
			class_getInstanceVariable(*self, name)
		});
		if ivar.ptr.is_null() {
			None
		} else {
			Some(ivar)
		}
	}

	pub fn instance_variables(&self) -> Vec<Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(*self, &mut count) as *const Ivar;
			let vec = buf_as_slice(ivars, count as uint, |ivars| {
				ivars.to_vec()
			});
			libc::free(ivars as *mut c_void);
			vec
		}
	}
}

impl Clone for Class {
	fn clone(&self) -> Class { *self }
}

pub trait Message { }

impl Message for Object { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

impl ToMessage for Class {
	fn as_ptr(&self) -> *mut Object {
		self.ptr
	}
}
<commit_msg>Made Ivars pointers.<commit_after>use std::slice::raw::buf_as_slice;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

pub enum Object { }

pub struct Sel {
	ptr: *const c_void,
}

pub enum Ivar { }

pub struct Method {
	ptr: *mut c_void,
}

pub struct Class {
	ptr: *mut Object,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> Class;
	pub fn class_getName(cls: Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: Class) -> size_t;
	pub fn class_getInstanceMethod(cls: Class, sel: Sel) -> Method;
	pub fn class_getInstanceVariable(cls: Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyIvarList(cls: Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: Class, name: *const c_char, extraBytes: size_t) -> Class;
	pub fn objc_disposeClassPair(cls: Class);
	pub fn objc_registerClassPair(cls: Class);

	pub fn object_getClass(obj: *mut Object) -> Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: Method) -> Sel;
	pub fn method_getImplementation(method: Method) -> Imp;
	pub fn method_getTypeEncoding(method: Method) -> *const c_char;
	pub fn method_getNumberOfArguments(method: Method) -> c_uint;
	pub fn method_setImplementation(method: Method, imp: Imp) -> Imp;
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(*self)
		}
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(*self);
			c_str_to_static_slice(encoding)
		}
	}

	pub fn arguments(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(*self) as uint
		}
	}

	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(*self)
		}
	}

	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(*self, imp)
	}
}

impl Object {
	pub fn class(&self) -> Class {
		unsafe {
			object_getClass(self as *const Object as *mut Object)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

impl Class {
	pub fn get(name: &str) -> Option<Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.ptr.is_null() {
			None
		} else {
			Some(cls)
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(*self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<Method> {
		let method = unsafe {
			class_getInstanceMethod(*self, sel)
		};
		if method.ptr.is_null() {
			None
		} else {
			Some(method)
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		let ivar = name.with_c_str(|name| unsafe {
			class_getInstanceVariable(*self, name)
		});
		if ivar.is_null() {
			None
		} else {
			Some(unsafe { &*ivar })
		}
	}

	pub fn instance_variables(&self) -> Vec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(*self, &mut count);
			let vec = buf_as_slice(ivars as *const _, count as uint, |ivars| {
				ivars.to_vec()
			});
			libc::free(ivars as *mut c_void);
			vec
		}
	}
}

impl Clone for Class {
	fn clone(&self) -> Class { *self }
}

pub trait Message { }

impl Message for Object { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

impl ToMessage for Class {
	fn as_ptr(&self) -> *mut Object {
		self.ptr
	}
}
<|endoftext|>


<commit_before>use datum::*;
use primitive::*;
use numeric::LNumeric;
use core::hashmap::linear::LinearMap;
use core::num::Zero::zero;
use core::num::One::one;

struct Runtime {
    stdin: @io::Reader,
    stdout: @io::Writer,
    stderr: @io::Writer,
    global: LinearMap<~str, @LDatum>,
    syntax: LinearMap<~str, PrimSyntax>,
}

#[deriving(Eq)]
enum RuntimeError {
    UnboundVariable(~str),
    NotCallable,
    NotList,
    ArgNumError,
    TypeError,
    DivideByZeroError,
    NilEval,
}

impl ToStr for RuntimeError {
    fn to_str(&self) -> ~str {
        err_to_str(self)
    }
}

priv fn err_to_str(&err: &RuntimeError) -> ~str {
    match err {
        UnboundVariable(name) => ~"unbound variable: " + copy name,
        NotCallable => ~"not callable",
        NotList => ~"not list",
        ArgNumError => ~"bad number of arguments",
        TypeError => ~"type error",
        DivideByZeroError => ~"divide by zero",
        NilEval => ~"() cannot be evaluated",
    }
}

fn load_prelude() -> LinearMap<~str, @LDatum> {
    let mut map = LinearMap::new();
    for vec::each(prelude()) |&pair| {
        let (key, func) = pair;
        map.insert(key, @LPrim(func));
    }
    map
}

fn load_prelude_macro() -> LinearMap<~str, PrimSyntax> {
    let mut map = LinearMap::new();
    for vec::each(syntax_prelude()) |&pair| {
        let (key, syntax) = pair;
        map.insert(key, syntax);
    }
    map
}

priv fn call_prim1(args: ~[@LDatum],
                op: &fn(@LDatum) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 1 {
        op(args[0])
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_prim2(args: ~[@LDatum],
                    op: &fn(&LNumeric, &LNumeric) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 2 {
        match *args[0] {
            LNum(lhs) => match *args[1] {
                LNum(rhs) => op(&lhs, &rhs),
                _ => Err(TypeError),
            },
            _ => Err(TypeError),
        }
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_foldl(args: ~[@LDatum],
                    a0: LNumeric,
                    op: &fn(&LNumeric, &LNumeric) -> Result<LNumeric, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    let mut res = a0;
    let mut err = false;
    do args.each |&arg| {
        match *arg {
            LNum(a) => {
                match op(&res, &a) {
                    Ok(n) => {
                        res = n;
                        err = false;
                    },
                    _ => {
                        err = true;
                    }
                }
            },
            _ => {
                err = true;
            }
        }
        !err
    }
    if err {
        Err(TypeError)
    } else {
        Ok(@LNum(res))
    }
}

priv impl Runtime {
    fn get_syntax(&self, val: @LDatum) -> Option<PrimSyntax> {
        match copy *val {
            LIdent(name) => match self.syntax.find(&name) {
                Some(syn) => Some(*syn),
                None => None,
            },
            _ => None,
        }
    }

    fn run_syntax(&mut self, syn: PrimSyntax, args: ~[@LDatum]) -> Result<@LDatum, RuntimeError> {
        match syn {
            SynIf => if args.len() == 3 {
                    do result::chain(self.eval(args[0])) |cond| {
                        match *cond {
                            LBool(true) => self.eval(args[1]),
                            LBool(false) => self.eval(args[2]),
                            _ => Err(TypeError),
                        }
                    }
                } else {
                    Err(ArgNumError)
                },
        }
    }

    fn call_prim(&mut self, f: PFunc, args: ~[@LDatum]) -> Result<@LDatum, RuntimeError> {
        match f {
            PEval => do call_prim1(args) |arg| {
                self.eval(arg)
            },
            PAdd => do call_num_foldl(args, zero()) |&lhs, &rhs| { Ok(lhs + rhs) },
            PSub => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs - rhs) },
            PMul => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs * rhs) },
            PDiv => do call_num_foldl(args, one()) |&lhs, &rhs| {
                if rhs.is_zero() {
                    Err(DivideByZeroError)
                } else {
                    Ok(lhs / rhs)
                }
            },
            PCar => do call_prim1(args) |arg| {
                match *arg {
                    LCons(h, _) => Ok(h),
                    _ => Err(TypeError),
                }
            },
            PCdr => do call_prim1(args) |arg| {
                match *arg {
                    LCons(_, t) => Ok(t),
                    _ => Err(TypeError),
                }
            },
        }
    }
}

pub impl Runtime {
    fn new_std() -> Runtime {
        Runtime {
            stdin: io::stdin(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            global: load_prelude(),
            syntax: load_prelude_macro(),
        }
    }

    fn eval(&mut self, val: @LDatum) -> Result<@LDatum, RuntimeError> {
        match copy *val {
            LIdent(name) =>
                match self.global.find(&name) {
                    Some(&datum) => Ok(datum),
                    None => Err(UnboundVariable(name)),
                },
            LCons(fexpr, aexpr) =>
                match aexpr.to_list() {
                    None => Err(NotList),
                    Some(aexprs) => {
                        match self.get_syntax(fexpr) {
                            Some(syntax) =>
                                self.run_syntax(syntax, aexprs),
                            None =>
                                match self.eval(fexpr) {
                                    Ok(@LPrim(f)) => {
                                        match result::map_vec(aexprs, |&expr| self.eval(expr)) {
                                            Ok(args) => self.call_prim(f, args),
                                            Err(e) => Err(e),
                                        }
                                    }
                                    Ok(_) => Err(NotCallable),
                                    Err(e) => Err(e),
                                },
                        }
                    },
                },
            LQuote(val) => Ok(val),
            LNil => Err(NilEval),
            _ => Ok(val),
        }
    }

}
<commit_msg>remove mutable context for now<commit_after>use datum::*;
use primitive::*;
use numeric::LNumeric;
use core::hashmap::linear::LinearMap;
use core::num::Zero::zero;
use core::num::One::one;

struct Runtime {
    stdin: @io::Reader,
    stdout: @io::Writer,
    stderr: @io::Writer,
    global: LinearMap<~str, @LDatum>,
    syntax: LinearMap<~str, PrimSyntax>,
}

#[deriving(Eq)]
enum RuntimeError {
    UnboundVariable(~str),
    NotCallable,
    NotList,
    ArgNumError,
    TypeError,
    DivideByZeroError,
    NilEval,
}

impl ToStr for RuntimeError {
    fn to_str(&self) -> ~str {
        err_to_str(self)
    }
}

priv fn err_to_str(&err: &RuntimeError) -> ~str {
    match err {
        UnboundVariable(name) => ~"unbound variable: " + copy name,
        NotCallable => ~"not callable",
        NotList => ~"not list",
        ArgNumError => ~"bad number of arguments",
        TypeError => ~"type error",
        DivideByZeroError => ~"divide by zero",
        NilEval => ~"() cannot be evaluated",
    }
}

fn load_prelude() -> LinearMap<~str, @LDatum> {
    let mut map = LinearMap::new();
    for vec::each(prelude()) |&pair| {
        let (key, func) = pair;
        map.insert(key, @LPrim(func));
    }
    map
}

fn load_prelude_macro() -> LinearMap<~str, PrimSyntax> {
    let mut map = LinearMap::new();
    for vec::each(syntax_prelude()) |&pair| {
        let (key, syntax) = pair;
        map.insert(key, syntax);
    }
    map
}

priv fn call_prim1(args: ~[@LDatum],
                op: &fn(@LDatum) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 1 {
        op(args[0])
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_prim2(args: ~[@LDatum],
                    op: &fn(&LNumeric, &LNumeric) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 2 {
        match *args[0] {
            LNum(lhs) => match *args[1] {
                LNum(rhs) => op(&lhs, &rhs),
                _ => Err(TypeError),
            },
            _ => Err(TypeError),
        }
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_foldl(args: ~[@LDatum],
                    a0: LNumeric,
                    op: &fn(&LNumeric, &LNumeric) -> Result<LNumeric, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    let mut res = a0;
    let mut err = false;
    do args.each |&arg| {
        match *arg {
            LNum(a) => {
                match op(&res, &a) {
                    Ok(n) => {
                        res = n;
                        err = false;
                    },
                    _ => {
                        err = true;
                    }
                }
            },
            _ => {
                err = true;
            }
        }
        !err
    }
    if err {
        Err(TypeError)
    } else {
        Ok(@LNum(res))
    }
}

priv impl Runtime {
    fn get_syntax(&self, val: @LDatum) -> Option<PrimSyntax> {
        match copy *val {
            LIdent(name) => match self.syntax.find(&name) {
                Some(syn) => Some(*syn),
                None => None,
            },
            _ => None,
        }
    }

    fn run_syntax(&self, syn: PrimSyntax, args: ~[@LDatum]) -> Result<@LDatum, RuntimeError> {
        match syn {
            SynIf => if args.len() == 3 {
                    do result::chain(self.eval(args[0])) |cond| {
                        match *cond {
                            LBool(true) => self.eval(args[1]),
                            LBool(false) => self.eval(args[2]),
                            _ => Err(TypeError),
                        }
                    }
                } else {
                    Err(ArgNumError)
                },
        }
    }

    fn call_prim(&self, f: PFunc, args: ~[@LDatum]) -> Result<@LDatum, RuntimeError> {
        match f {
            PEval => do call_prim1(args) |arg| {
                self.eval(arg)
            },
            PAdd => do call_num_foldl(args, zero()) |&lhs, &rhs| { Ok(lhs + rhs) },
            PSub => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs - rhs) },
            PMul => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs * rhs) },
            PDiv => do call_num_foldl(args, one()) |&lhs, &rhs| {
                if rhs.is_zero() {
                    Err(DivideByZeroError)
                } else {
                    Ok(lhs / rhs)
                }
            },
            PCar => do call_prim1(args) |arg| {
                match *arg {
                    LCons(h, _) => Ok(h),
                    _ => Err(TypeError),
                }
            },
            PCdr => do call_prim1(args) |arg| {
                match *arg {
                    LCons(_, t) => Ok(t),
                    _ => Err(TypeError),
                }
            },
        }
    }
}

pub impl Runtime {
    fn new_std() -> Runtime {
        Runtime {
            stdin: io::stdin(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            global: load_prelude(),
            syntax: load_prelude_macro(),
        }
    }

    fn eval(&self, val: @LDatum) -> Result<@LDatum, RuntimeError> {
        match copy *val {
            LIdent(name) =>
                match self.global.find(&name) {
                    Some(&datum) => Ok(datum),
                    None => Err(UnboundVariable(name)),
                },
            LCons(fexpr, aexpr) =>
                match aexpr.to_list() {
                    None => Err(NotList),
                    Some(aexprs) => {
                        match self.get_syntax(fexpr) {
                            Some(syntax) =>
                                self.run_syntax(syntax, aexprs),
                            None =>
                                match self.eval(fexpr) {
                                    Ok(@LPrim(f)) => {
                                        match result::map_vec(aexprs, |&expr| self.eval(expr)) {
                                            Ok(args) => self.call_prim(f, args),
                                            Err(e) => Err(e),
                                        }
                                    }
                                    Ok(_) => Err(NotCallable),
                                    Err(e) => Err(e),
                                },
                        }
                    },
                },
            LQuote(val) => Ok(val),
            LNil => Err(NilEval),
            _ => Ok(val),
        }
    }

}
<|endoftext|>