<commit_before>// Copyright 2016 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 support library for macro authors when defining new macros.
//!
//! This library, provided by the standard distribution, provides the types
//! consumed in the interfaces of procedurally defined macro definitions.
//! Currently the primary use of this crate is to provide the ability to define
//! new custom derive modes through `#[proc_macro_derive]`.
//!
//! Note that this crate is intentionally very bare-bones currently. The main
//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
//! implementations, indicating that it can only go to and come from a string.
//! This functionality is intended to be expanded over time as more surface
//! area for macro authors is stabilized.
//!
//! See [the book](../book/procedural-macros.html) for more.

#![crate_name = "proc_macro"]
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![deny(warnings)]
#![deny(missing_docs)]

#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(lang_items)]

extern crate syntax;

use std::fmt;
use std::str::FromStr;

use syntax::errors::DiagnosticBuilder;
use syntax::parse;
use syntax::tokenstream::TokenStream as TokenStream_;

/// The main type provided by this crate, representing an abstract stream of
/// tokens.
///
/// This is both the input and output of `#[proc_macro_derive]` definitions.
/// Currently it's required to be a list of valid Rust items, but this
/// restriction may be lifted in the future.
///
/// The API of this type is intentionally bare-bones, but it'll be expanded over
/// time!
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
pub struct TokenStream {
    inner: TokenStream_,
}

/// Error returned from `TokenStream::from_str`.
#[derive(Debug)]
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
pub struct LexError {
    _inner: (),
}

/// Permanently unstable internal implementation details of this crate. This
/// should not be used.
///
/// These methods are used by the rest of the compiler to generate instances of
/// `TokenStream` to hand to macro definitions, as well as consume the output.
///
/// Note that this module is also intentionally separate from the rest of the
/// crate. This allows the `#[unstable]` directive below to naturally apply to
/// all of the contents.
#[unstable(feature = "proc_macro_internals", issue = "27812")]
#[doc(hidden)]
pub mod __internal {
    use std::cell::Cell;
    use std::rc::Rc;

    use syntax::ast;
    use syntax::ptr::P;
    use syntax::parse::{self, token, ParseSess};
    use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_};

    use super::{TokenStream, LexError};

    pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
        TokenStream {
            inner: TokenTree::Token(item.span, token::Interpolated(Rc::new(token::NtItem(item))))
                .into()
        }
    }

    pub fn token_stream_wrap(inner: TokenStream_) -> TokenStream {
        TokenStream {
            inner: inner
        }
    }

    pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
        with_parse_sess(move |sess| {
            let mut parser = parse::stream_to_parser(sess, stream.inner);
            let mut items = Vec::new();

            while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) {
                items.push(item)
            }

            Ok(items)
        })
    }

    pub fn token_stream_inner(stream: TokenStream) -> TokenStream_ {
        stream.inner
    }

    pub trait Registry {
        fn register_custom_derive(&mut self,
                                  trait_name: &str,
                                  expand: fn(TokenStream) -> TokenStream,
                                  attributes: &[&'static str]);

        fn register_attr_proc_macro(&mut self,
                                    name: &str,
                                    expand: fn(TokenStream, TokenStream) -> TokenStream);

        fn register_bang_proc_macro(&mut self,
                                    name: &str,
                                    expand: fn(TokenStream) -> TokenStream);
    }

    // Emulate scoped_thread_local!() here essentially
    thread_local! {
        static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
    }

    pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
        where F: FnOnce() -> R
    {
        struct Reset { prev: *const ParseSess }

        impl Drop for Reset {
            fn drop(&mut self) {
                CURRENT_SESS.with(|p| p.set(self.prev));
            }
        }

        CURRENT_SESS.with(|p| {
            let _reset = Reset { prev: p.get() };
            p.set(sess);
            f()
        })
    }

    pub fn with_parse_sess<F, R>(f: F) -> R
        where F: FnOnce(&ParseSess) -> R
    {
        let p = CURRENT_SESS.with(|p| p.get());
        assert!(!p.is_null(), "proc_macro::__internal::with_parse_sess() called \
                               before set_parse_sess()!");
        f(unsafe { &*p })
    }
}

fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
    err.cancel();
    LexError { _inner: () }
}

#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl FromStr for TokenStream {
    type Err = LexError;

    fn from_str(src: &str) -> Result<TokenStream, LexError> {
        __internal::with_parse_sess(|sess| {
            let src = src.to_string();
            let name = "<proc-macro source code>".to_string();
            let stream = parse::parse_stream_from_source_str(name, src, sess);
            Ok(__internal::token_stream_wrap(stream))
        })
    }
}

#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl fmt::Display for TokenStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.inner.fmt(f)
    }
}
<commit_msg>Add doc attributes to proc_macro crate<commit_after>// Copyright 2016 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 support library for macro authors when defining new macros.
//!
//! This library, provided by the standard distribution, provides the types
//! consumed in the interfaces of procedurally defined macro definitions.
//! Currently the primary use of this crate is to provide the ability to define
//! new custom derive modes through `#[proc_macro_derive]`.
//!
//! Note that this crate is intentionally very bare-bones currently. The main
//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
//! implementations, indicating that it can only go to and come from a string.
//! This functionality is intended to be expanded over time as more surface
//! area for macro authors is stabilized.
//!
//! See [the book](../book/procedural-macros.html) for more.

#![crate_name = "proc_macro"]
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![deny(warnings)]
#![deny(missing_docs)]
#![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/",
       html_playground_url = "https://play.rust-lang.org/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(deny(warnings))),
       test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]

#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(lang_items)]

extern crate syntax;

use std::fmt;
use std::str::FromStr;

use syntax::errors::DiagnosticBuilder;
use syntax::parse;
use syntax::tokenstream::TokenStream as TokenStream_;

/// The main type provided by this crate, representing an abstract stream of
/// tokens.
///
/// This is both the input and output of `#[proc_macro_derive]` definitions.
/// Currently it's required to be a list of valid Rust items, but this
/// restriction may be lifted in the future.
///
/// The API of this type is intentionally bare-bones, but it'll be expanded over
/// time!
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
pub struct TokenStream {
    inner: TokenStream_,
}

/// Error returned from `TokenStream::from_str`.
#[derive(Debug)]
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
pub struct LexError {
    _inner: (),
}

/// Permanently unstable internal implementation details of this crate. This
/// should not be used.
///
/// These methods are used by the rest of the compiler to generate instances of
/// `TokenStream` to hand to macro definitions, as well as consume the output.
///
/// Note that this module is also intentionally separate from the rest of the
/// crate. This allows the `#[unstable]` directive below to naturally apply to
/// all of the contents.
#[unstable(feature = "proc_macro_internals", issue = "27812")]
#[doc(hidden)]
pub mod __internal {
    use std::cell::Cell;
    use std::rc::Rc;

    use syntax::ast;
    use syntax::ptr::P;
    use syntax::parse::{self, token, ParseSess};
    use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_};

    use super::{TokenStream, LexError};

    pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
        TokenStream {
            inner: TokenTree::Token(item.span, token::Interpolated(Rc::new(token::NtItem(item))))
                .into()
        }
    }

    pub fn token_stream_wrap(inner: TokenStream_) -> TokenStream {
        TokenStream {
            inner: inner
        }
    }

    pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
        with_parse_sess(move |sess| {
            let mut parser = parse::stream_to_parser(sess, stream.inner);
            let mut items = Vec::new();

            while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) {
                items.push(item)
            }

            Ok(items)
        })
    }

    pub fn token_stream_inner(stream: TokenStream) -> TokenStream_ {
        stream.inner
    }

    pub trait Registry {
        fn register_custom_derive(&mut self,
                                  trait_name: &str,
                                  expand: fn(TokenStream) -> TokenStream,
                                  attributes: &[&'static str]);

        fn register_attr_proc_macro(&mut self,
                                    name: &str,
                                    expand: fn(TokenStream, TokenStream) -> TokenStream);

        fn register_bang_proc_macro(&mut self,
                                    name: &str,
                                    expand: fn(TokenStream) -> TokenStream);
    }

    // Emulate scoped_thread_local!() here essentially
    thread_local! {
        static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
    }

    pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
        where F: FnOnce() -> R
    {
        struct Reset { prev: *const ParseSess }

        impl Drop for Reset {
            fn drop(&mut self) {
                CURRENT_SESS.with(|p| p.set(self.prev));
            }
        }

        CURRENT_SESS.with(|p| {
            let _reset = Reset { prev: p.get() };
            p.set(sess);
            f()
        })
    }

    pub fn with_parse_sess<F, R>(f: F) -> R
        where F: FnOnce(&ParseSess) -> R
    {
        let p = CURRENT_SESS.with(|p| p.get());
        assert!(!p.is_null(), "proc_macro::__internal::with_parse_sess() called \
                               before set_parse_sess()!");
        f(unsafe { &*p })
    }
}

fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
    err.cancel();
    LexError { _inner: () }
}

#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl FromStr for TokenStream {
    type Err = LexError;

    fn from_str(src: &str) -> Result<TokenStream, LexError> {
        __internal::with_parse_sess(|sess| {
            let src = src.to_string();
            let name = "<proc-macro source code>".to_string();
            let stream = parse::parse_stream_from_source_str(name, src, sess);
            Ok(__internal::token_stream_wrap(stream))
        })
    }
}

#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl fmt::Display for TokenStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.inner.fmt(f)
    }
}
<|endoftext|>


<commit_before>use crate::ty::{self, TypeFoldable};

use rustc_data_structures::fx::FxHashSet;
use syntax::symbol::InternedString;

use std::fmt;

// FIXME(eddyb) this module uses `pub(crate)` for things used only
// from `ppaux` - when that is removed, they can be re-privatized.

struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
        match *r {
            ty::ReLateBound(_, ty::BrNamed(_, name)) => {
                self.0.insert(name);
            },
            _ => {},
        }
        r.super_visit_with(self)
    }
}

#[derive(Debug)]
pub struct PrintContext {
    pub(crate) is_debug: bool,
    pub(crate) is_verbose: bool,
    pub(crate) identify_regions: bool,
    pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
    pub(crate) region_index: usize,
    pub(crate) binder_depth: usize,
}

impl PrintContext {
    pub(crate) fn new() -> Self {
        ty::tls::with_opt(|tcx| {
            let (is_verbose, identify_regions) = tcx.map(
                |tcx| (tcx.sess.verbose(), tcx.sess.opts.debugging_opts.identify_regions)
            ).unwrap_or((false, false));
            PrintContext {
                is_debug: false,
                is_verbose: is_verbose,
                identify_regions: identify_regions,
                used_region_names: None,
                region_index: 0,
                binder_depth: 0,
            }
        })
    }
    pub(crate) fn prepare_late_bound_region_info<'tcx, T>(&mut self, value: &ty::Binder<T>)
    where T: TypeFoldable<'tcx>
    {
        let mut collector = LateBoundRegionNameCollector(Default::default());
        value.visit_with(&mut collector);
        self.used_region_names = Some(collector.0);
        self.region_index = 0;
    }
}

pub trait Print<'tcx> {
    fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result;
    fn print_to_string(&self, cx: &mut PrintContext) -> String {
        let mut result = String::new();
        let _ = self.print(&mut result, cx);
        result
    }
    fn print_display<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
        let old_debug = cx.is_debug;
        cx.is_debug = false;
        let result = self.print(f, cx);
        cx.is_debug = old_debug;
        result
    }
    fn print_display_to_string(&self, cx: &mut PrintContext) -> String {
        let mut result = String::new();
        let _ = self.print_display(&mut result, cx);
        result
    }
    fn print_debug<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
        let old_debug = cx.is_debug;
        cx.is_debug = true;
        let result = self.print(f, cx);
        cx.is_debug = old_debug;
        result
    }
    fn print_debug_to_string(&self, cx: &mut PrintContext) -> String {
        let mut result = String::new();
        let _ = self.print_debug(&mut result, cx);
        result
    }
}
<commit_msg>rustc: don't support missing TLS TyCtxt in ty::print.<commit_after>use crate::ty::{self, TypeFoldable};

use rustc_data_structures::fx::FxHashSet;
use syntax::symbol::InternedString;

use std::fmt;

// FIXME(eddyb) this module uses `pub(crate)` for things used only
// from `ppaux` - when that is removed, they can be re-privatized.

struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
        match *r {
            ty::ReLateBound(_, ty::BrNamed(_, name)) => {
                self.0.insert(name);
            },
            _ => {},
        }
        r.super_visit_with(self)
    }
}

#[derive(Debug)]
pub struct PrintContext {
    pub(crate) is_debug: bool,
    pub(crate) is_verbose: bool,
    pub(crate) identify_regions: bool,
    pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
    pub(crate) region_index: usize,
    pub(crate) binder_depth: usize,
}

impl PrintContext {
    pub(crate) fn new() -> Self {
        ty::tls::with(|tcx| {
            let (is_verbose, identify_regions) =
                (tcx.sess.verbose(), tcx.sess.opts.debugging_opts.identify_regions);
            PrintContext {
                is_debug: false,
                is_verbose: is_verbose,
                identify_regions: identify_regions,
                used_region_names: None,
                region_index: 0,
                binder_depth: 0,
            }
        })
    }
    pub(crate) fn prepare_late_bound_region_info<'tcx, T>(&mut self, value: &ty::Binder<T>)
    where T: TypeFoldable<'tcx>
    {
        let mut collector = LateBoundRegionNameCollector(Default::default());
        value.visit_with(&mut collector);
        self.used_region_names = Some(collector.0);
        self.region_index = 0;
    }
}

pub trait Print<'tcx> {
    fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result;
    fn print_to_string(&self, cx: &mut PrintContext) -> String {
        let mut result = String::new();
        let _ = self.print(&mut result, cx);
        result
    }
    fn print_display<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
        let old_debug = cx.is_debug;
        cx.is_debug = false;
        let result = self.print(f, cx);
        cx.is_debug = old_debug;
        result
    }
    fn print_display_to_string(&self, cx: &mut PrintContext) -> String {
        let mut result = String::new();
        let _ = self.print_display(&mut result, cx);
        result
    }
    fn print_debug<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
        let old_debug = cx.is_debug;
        cx.is_debug = true;
        let result = self.print(f, cx);
        cx.is_debug = old_debug;
        result
    }
    fn print_debug_to_string(&self, cx: &mut PrintContext) -> String {
        let mut result = String::new();
        let _ = self.print_debug(&mut result, cx);
        result
    }
}
<|endoftext|>


<commit_before>use cpu;
use cpu::Cpu;

#[inline(always)]
fn get_shifter_val(instr_data: &cpu::InstrDataDProc::Type, cpu: &Cpu) -> (u32, bool) {
    use cpu::InstrDataDProc as InstrData;

    let shifter_bits = instr_data.get::<InstrData::shifter_operand>();
    let c_bit = cpu.cpsr.get::<cpu::Psr::c_bit>() == 1;

    if instr_data.get::<InstrData::i_bit>() == 1 {
        let immed_8 = extract_bits!(shifter_bits, 0 => 7);
        let rotate_imm = extract_bits!(shifter_bits, 8 => 11);

        let res = immed_8.rotate_right(rotate_imm * 2);
        if rotate_imm == 0 {
            return (res, c_bit);
        } else {
            return (res, extract_bits!(res, 31 => 31) == 1);
        }
    }

    let pre_shift: u32 = cpu.regs[extract_bits!(shifter_bits, 0 => 3) as usize];
    let amount = if extract_bits!(shifter_bits, 4 => 4) == 0 {
        extract_bits!(shifter_bits, 7 => 11) as u8
    } else {
        cpu.regs[extract_bits!(shifter_bits, 8 => 11) as usize] as u8
    };

    match extract_bits!(shifter_bits, 4 => 6) {
        0b000 | 0b001 => { // LSL
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount < 32 {
                let res = pre_shift << amount;
                return (res, extract_bits!(pre_shift, (32 - amount) as usize => (32 - amount) as usize) == 1)
            } else if amount == 32 {
                return (0, extract_bits!(pre_shift, 0 => 0) == 1)
            } else {
                return (0, false)
            }
        },
        0b010 | 0b011 => { // LSR
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount < 32 {
                let res = pre_shift >> amount;
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            } else if amount == 32 {
                return (0, extract_bits!(pre_shift, 31 => 31) == 1)
            } else {
                return (0, false)
            }
        },
        0b100 => { // ASR immedate
            if amount == 0 {
                if extract_bits!(pre_shift, 31 => 31) == 0 {
                    return (0, false)
                } else {
                    return (0xFFFFFFFF, true)
                }
            } else {
                let res = ((pre_shift as i32) >> amount) as u32;
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            }
        },
        0b101 => { // ASR register
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount < 32 {
                let res = ((pre_shift as i32) >> amount) as u32;
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            } else {
                if extract_bits!(pre_shift, 31 => 31) == 0 {
                    return (0, false)
                } else {
                    return (0xFFFFFFFF, true)
                }
            }
        },
        0b110 => { // ROR immediate
            if amount == 0 {
                let res = ((c_bit as u32) << 31) | (pre_shift >> 1);
                return (res, extract_bits!(pre_shift, 0 => 0) == 1)
            } else {
                let res = pre_shift.rotate_right(amount as u32);
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            }
        },
        0b111 => { // ROR register
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount & 0xF == 0 {
                return (pre_shift, extract_bits!(pre_shift, 31 => 31) == 1)
            } else {
                let amount = amount & 0xF;
                let res = pre_shift.rotate_right(amount as u32);
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            }
        }
        _ => {
            panic!("Unhandled shifter operation!");
        }
    }
}

enum ProcessInstrBitOp {
    AND,
    AND_NOT,
    OR,
    XOR,
}

#[inline(always)]
fn instr_bitwise(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, op: ProcessInstrBitOp) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (mut shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();

    let val = match op {
        ProcessInstrBitOp::AND => cpu.regs[rn as usize] & shifter_val,
        ProcessInstrBitOp::AND_NOT => cpu.regs[rn as usize] & !shifter_val,
        ProcessInstrBitOp::OR => cpu.regs[rn as usize] | shifter_val,
        ProcessInstrBitOp::XOR => cpu.regs[rn as usize] ^ shifter_val,
    };

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);
            cpu.cpsr.set::<cpu::Psr::c_bit>(shifter_carry as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = val;
        return 4;
    }
}

#[inline(always)]
fn instr_move(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, negate: bool) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (mut src_val, shifter_carry) = get_shifter_val(&data, cpu);
    if negate {
        src_val = !src_val;
    }

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(src_val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((src_val == 0) as u32);
            cpu.cpsr.set::<cpu::Psr::c_bit>(shifter_carry as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(src_val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = src_val;
        return 4;
    }
}

#[inline(always)]
fn instr_test(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, equiv: bool) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let (mut shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();
    let val = if equiv {
        cpu.regs[rn as usize] ^ shifter_val
    } else {
        cpu.regs[rn as usize] & shifter_val
    };

    cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
    cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);
    cpu.cpsr.set::<cpu::Psr::c_bit>(shifter_carry as u32);

    4
}

#[inline(always)]
pub fn add(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();

    let val = cpu.regs[rn as usize] + shifter_val;

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);

            let u_overflow = cpu.regs[rn as usize].checked_add(shifter_val).is_none();
            let s_overflow = (cpu.regs[rn as usize] as i32).checked_add(shifter_val as i32).is_none();
            cpu.cpsr.set::<cpu::Psr::c_bit>(u_overflow as u32);
            cpu.cpsr.set::<cpu::Psr::v_bit>(s_overflow as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = val;
        return 4;
    }
}

#[inline(always)]
pub fn and(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::AND)
}

#[inline(always)]
pub fn bic(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::AND_NOT)
}

#[inline(always)]
pub fn eor(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::XOR)
}

#[inline(always)]
pub fn orr(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::OR)
}

#[inline(always)]
pub fn mov(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_move(cpu, data, false)
}

#[inline(always)]
pub fn mvn(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_move(cpu, data, true)
}

#[inline(always)]
pub fn rsb(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();

    let val = shifter_val - cpu.regs[rn as usize];

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);

            let u_underflow = !shifter_val.checked_sub(cpu.regs[rn as usize]).is_none();
            let s_overflow = (shifter_val as i32).checked_sub(cpu.regs[rn as usize] as i32).is_none();
            cpu.cpsr.set::<cpu::Psr::c_bit>(u_underflow as u32);
            cpu.cpsr.set::<cpu::Psr::v_bit>(s_overflow as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = val;
        return 4;
    }
}

#[inline(always)]
pub fn sub(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();

    let val = cpu.regs[rn as usize] - shifter_val;

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);

            let u_underflow = !cpu.regs[rn as usize].checked_sub(shifter_val).is_none();
            let s_overflow = (cpu.regs[rn as usize] as i32).checked_sub(shifter_val as i32).is_none();
            cpu.cpsr.set::<cpu::Psr::c_bit>(u_underflow as u32);
            cpu.cpsr.set::<cpu::Psr::v_bit>(s_overflow as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = val;
        return 4;
    }
}

#[inline(always)]
pub fn teq(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_test(cpu, data, true)
}

#[inline(always)]
pub fn tst(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_test(cpu, data, false)
}
<commit_msg>Unify various logical data processing operations<commit_after>use cpu;
use cpu::Cpu;

#[inline(always)]
fn get_shifter_val(instr_data: &cpu::InstrDataDProc::Type, cpu: &Cpu) -> (u32, bool) {
    use cpu::InstrDataDProc as InstrData;

    let shifter_bits = instr_data.get::<InstrData::shifter_operand>();
    let c_bit = cpu.cpsr.get::<cpu::Psr::c_bit>() == 1;

    if instr_data.get::<InstrData::i_bit>() == 1 {
        let immed_8 = extract_bits!(shifter_bits, 0 => 7);
        let rotate_imm = extract_bits!(shifter_bits, 8 => 11);

        let res = immed_8.rotate_right(rotate_imm * 2);
        if rotate_imm == 0 {
            return (res, c_bit);
        } else {
            return (res, extract_bits!(res, 31 => 31) == 1);
        }
    }

    let pre_shift: u32 = cpu.regs[extract_bits!(shifter_bits, 0 => 3) as usize];
    let amount = if extract_bits!(shifter_bits, 4 => 4) == 0 {
        extract_bits!(shifter_bits, 7 => 11) as u8
    } else {
        cpu.regs[extract_bits!(shifter_bits, 8 => 11) as usize] as u8
    };

    match extract_bits!(shifter_bits, 4 => 6) {
        0b000 | 0b001 => { // LSL
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount < 32 {
                let res = pre_shift << amount;
                return (res, extract_bits!(pre_shift, (32 - amount) as usize => (32 - amount) as usize) == 1)
            } else if amount == 32 {
                return (0, extract_bits!(pre_shift, 0 => 0) == 1)
            } else {
                return (0, false)
            }
        },
        0b010 | 0b011 => { // LSR
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount < 32 {
                let res = pre_shift >> amount;
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            } else if amount == 32 {
                return (0, extract_bits!(pre_shift, 31 => 31) == 1)
            } else {
                return (0, false)
            }
        },
        0b100 => { // ASR immedate
            if amount == 0 {
                if extract_bits!(pre_shift, 31 => 31) == 0 {
                    return (0, false)
                } else {
                    return (0xFFFFFFFF, true)
                }
            } else {
                let res = ((pre_shift as i32) >> amount) as u32;
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            }
        },
        0b101 => { // ASR register
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount < 32 {
                let res = ((pre_shift as i32) >> amount) as u32;
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            } else {
                if extract_bits!(pre_shift, 31 => 31) == 0 {
                    return (0, false)
                } else {
                    return (0xFFFFFFFF, true)
                }
            }
        },
        0b110 => { // ROR immediate
            if amount == 0 {
                let res = ((c_bit as u32) << 31) | (pre_shift >> 1);
                return (res, extract_bits!(pre_shift, 0 => 0) == 1)
            } else {
                let res = pre_shift.rotate_right(amount as u32);
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            }
        },
        0b111 => { // ROR register
            if amount == 0 {
                return (pre_shift, c_bit)
            } else if amount & 0xF == 0 {
                return (pre_shift, extract_bits!(pre_shift, 31 => 31) == 1)
            } else {
                let amount = amount & 0xF;
                let res = pre_shift.rotate_right(amount as u32);
                return (res, extract_bits!(pre_shift, (amount - 1) as usize => (amount - 1) as usize) == 1)
            }
        }
        _ => {
            panic!("Unhandled shifter operation!");
        }
    }
}

enum ProcessInstrBitOp {
    AND,
    AND_NOT,
    OR,
    XOR,
}

#[inline(always)]
fn instr_bitwise(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, op: ProcessInstrBitOp) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (mut shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();

    let val = match op {
        ProcessInstrBitOp::AND => cpu.regs[rn as usize] & shifter_val,
        ProcessInstrBitOp::AND_NOT => cpu.regs[rn as usize] & !shifter_val,
        ProcessInstrBitOp::OR => cpu.regs[rn as usize] | shifter_val,
        ProcessInstrBitOp::XOR => cpu.regs[rn as usize] ^ shifter_val,
    };

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);
            cpu.cpsr.set::<cpu::Psr::c_bit>(shifter_carry as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = val;
        return 4;
    }
}

enum ProcessInstrLogicalOp {
    ADD,
    REVERSE_SUB,
    SUB,
}

#[inline(always)]
fn instr_logical(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, op: ProcessInstrLogicalOp) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;

    let base_val = cpu.regs[data.get::<InstrData::rn>() as usize];
    let (shifter_val, _) = get_shifter_val(&data, cpu);

    let (val, carry_bit, overflow_bit) = match op {
        ProcessInstrLogicalOp::ADD => {
            let val = base_val + shifter_val;
            let u_overflow = base_val.checked_add(shifter_val).is_none();
            let s_overflow = (base_val as i32).checked_add(shifter_val as i32).is_none();
            (val, u_overflow, s_overflow)
        },
        ProcessInstrLogicalOp::REVERSE_SUB => {
            let val = shifter_val - base_val;
            let u_overflow = shifter_val.checked_sub(base_val).is_none();
            let s_overflow = (shifter_val as i32).checked_sub(base_val as i32).is_none();
            (val, u_overflow, s_overflow)
        }
        ProcessInstrLogicalOp::SUB => {
            let val = base_val - shifter_val;
            let u_overflow = base_val.checked_sub(shifter_val).is_none();
            let s_overflow = (base_val as i32).checked_sub(shifter_val as i32).is_none();
            (val, u_overflow, s_overflow)
        }
    };

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);
            cpu.cpsr.set::<cpu::Psr::c_bit>(carry_bit as u32);
            cpu.cpsr.set::<cpu::Psr::v_bit>(overflow_bit as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = val;
        return 4;
    }
}

#[inline(always)]
fn instr_move(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, negate: bool) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let dst_reg = data.get::<InstrData::rd>();
    let s_bit = data.get::<InstrData::s_bit>() == 1;
    let (mut src_val, shifter_carry) = get_shifter_val(&data, cpu);
    if negate {
        src_val = !src_val;
    }

    if s_bit {
        if dst_reg == 15 {
            cpu.spsr_make_current();
        } else {
            cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(src_val, 31 => 31));
            cpu.cpsr.set::<cpu::Psr::z_bit>((src_val == 0) as u32);
            cpu.cpsr.set::<cpu::Psr::c_bit>(shifter_carry as u32);
        }
    }

    if dst_reg == 15 {
        cpu.branch(src_val);
        return 0;
    } else {
        cpu.regs[dst_reg as usize] = src_val;
        return 4;
    }
}

#[inline(always)]
fn instr_test(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type, equiv: bool) -> u32 {
    use cpu::InstrDataDProc as InstrData;

    if !cpu::cond_passed(data.get::<InstrData::cond>(), &cpu.cpsr) {
        return 4;
    }

    let (mut shifter_val, shifter_carry) = get_shifter_val(&data, cpu);
    let rn = data.get::<InstrData::rn>();
    let val = if equiv {
        cpu.regs[rn as usize] ^ shifter_val
    } else {
        cpu.regs[rn as usize] & shifter_val
    };

    cpu.cpsr.set::<cpu::Psr::n_bit>(extract_bits!(val, 31 => 31));
    cpu.cpsr.set::<cpu::Psr::z_bit>((val == 0) as u32);
    cpu.cpsr.set::<cpu::Psr::c_bit>(shifter_carry as u32);

    4
}

#[inline(always)]
pub fn add(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_logical(cpu, data, ProcessInstrLogicalOp::ADD)
}

#[inline(always)]
pub fn and(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::AND)
}

#[inline(always)]
pub fn bic(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::AND_NOT)
}

#[inline(always)]
pub fn eor(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::XOR)
}

#[inline(always)]
pub fn orr(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_bitwise(cpu, data, ProcessInstrBitOp::OR)
}

#[inline(always)]
pub fn mov(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_move(cpu, data, false)
}

#[inline(always)]
pub fn mvn(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_move(cpu, data, true)
}

#[inline(always)]
pub fn rsb(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_logical(cpu, data, ProcessInstrLogicalOp::REVERSE_SUB)
}

#[inline(always)]
pub fn sub(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_logical(cpu, data, ProcessInstrLogicalOp::SUB)
}

#[inline(always)]
pub fn teq(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_test(cpu, data, true)
}

#[inline(always)]
pub fn tst(cpu: &mut Cpu, data: cpu::InstrDataDProc::Type) -> u32 {
    instr_test(cpu, data, false)
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use appkit::NSRect;

use std::libc::{c_double, c_long};
use std::libc;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
pub type id = libc::intptr_t;

pub static nil: id = 0 as id;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
		                 types: *libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *libc::c_char, value: *libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *libc::c_char, outValue: **libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL) -> id;
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *libc::c_char) -> SEL;
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    unsafe {
        name.to_c_str().with_ref(|c_string| objc_getClass(c_string))
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    unsafe {
        name.to_c_str().with_ref(|c_string| sel_registerName(c_string))
    }
}

/// A trait that allows syntax like:
///
///     let string = "NSString".send("alloc").send("initWithCString:", "Hello world!");
pub trait ObjCMethodCall {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id;
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double;
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A) -> c_long;
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A);
}

impl ObjCMethodCall for id {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(self, selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(self, selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(self, selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(self, selector.as_selector())
    }
}

/// A convenience implementation that allows methods on class names to be called directly, as in:
///
///     "NSString".send("alloc")
impl<'a> ObjCMethodCall for &'a str {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(class(self), selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(class(self), selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(class(self), selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(class(self), selector.as_selector())
    }
}

/// A trait that allows C strings to be used as selectors without having to convert them first.
pub trait ObjCSelector {
    fn as_selector(self) -> SEL;
}

impl<'a> ObjCSelector for &'a str {
    #[inline]
    fn as_selector(self) -> SEL {
        // TODO(pcwalton): Cache somehow.
        unsafe {
            self.to_c_str().with_ref(|c_string| sel_registerName(c_string))
        }
    }
}

impl ObjCSelector for SEL {
    #[inline]
    fn as_selector(self) -> SEL {
        self
    }
}

/// Traits that simulate variadic parameters for convenience when sending messages.
trait ObjCMethodArgs {
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id;
}
trait ObjCMethodDoubleArgs {
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> c_double;
}
trait ObjCMethodLongArgs {
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long;
}
trait ObjCMethodVoidArgs {
    unsafe fn send_void_args(self, receiver: id, selector: SEL);
}

impl ObjCMethodArgs for () {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id(receiver, selector)
    }
}

impl ObjCMethodArgs for (id, id, id, id, id) {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        let (first, second, third, fourth, fifth) = self;
        invoke_msg_id_id_id_id_id_id(receiver, selector, first, second, third, fourth, fifth)
    }
}

impl ObjCMethodArgs for NSRect {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id_NSRect(receiver, selector, &self)
    }
}

impl ObjCMethodDoubleArgs for () {
    #[inline]
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> f64 {
        invoke_msg_double(receiver, selector)
    }
}

impl ObjCMethodLongArgs for () {
    #[inline]
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long {
        invoke_msg_long(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for () {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for bool {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_bool(receiver, selector, self)
    }
}

impl ObjCMethodVoidArgs for id {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_id(receiver, selector, self)
    }
}

/// A trait that simulates variadic parameters for method calls.

#[cfg(test)]
mod test {
    use std::libc;
    use super::*;

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp = "NSApplication".send("sharedApplication", ());
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println("doSomething");
            return this;
        }

        let NSObject = class("NSObject");
        let MyObject = "MyObject".to_c_str().with_ref(|s| {
            unsafe {
                objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
            }
        });
        unsafe {
            let doSomething = selector("doSomething");
            let _ = "@@:".to_c_str().with_ref(|types| {
                class_addMethod(MyObject, doSomething, MyObject_doSomething, types)
            });

            objc_registerClassPair(MyObject);

            let mut obj: id = MyObject.send("alloc", ());
            obj = obj.send("init", ());
            obj.send_void("doSomething", ());
        }
    }
}

#[link(name = "msgsend")]
extern {
    fn invoke_msg_double(theReceiver: id, theSelector: SEL) -> f64;
    fn invoke_msg_id(theReceiver: id, theSelector: SEL) -> id;
    fn invoke_msg_id_id_id_id_id_id(theReceiver: id,
                                    theSelector: SEL,
                                    a: id,
                                    b: id,
                                    c: id,
                                    d: id,
                                    e: id)
                                    -> id;
    fn invoke_msg_id_NSRect(theReceiver: id, theSelector: SEL, a: &NSRect) -> id;
    fn invoke_msg_long(theReceiver: id, theSelector: SEL) -> c_long;
    fn invoke_msg_void(theReceiver: id, theSelector: SEL);
    fn invoke_msg_void_bool(theReceiver: id, theSelector: SEL, a: bool);
    fn invoke_msg_void_id(theReceiver: id, theSelector: SEL, a: id);
}

<commit_msg>Rust make check fix<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use appkit::NSRect;

use std::libc::{c_double, c_long};
use std::libc;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
pub type id = libc::intptr_t;

pub static nil: id = 0 as id;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
		                 types: *libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *libc::c_char, value: *libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *libc::c_char, outValue: **libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL) -> id;
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *libc::c_char) -> SEL;
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    unsafe {
        name.to_c_str().with_ref(|c_string| objc_getClass(c_string))
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    unsafe {
        name.to_c_str().with_ref(|c_string| sel_registerName(c_string))
    }
}

/// A trait that allows syntax like:
///
///     let string = "NSString".send("alloc").send("initWithCString:", "Hello world!");
pub trait ObjCMethodCall {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id;
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double;
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A) -> c_long;
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A);
}

impl ObjCMethodCall for id {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(self, selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(self, selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(self, selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(self, selector.as_selector())
    }
}

/// A convenience implementation that allows methods on class names to be called directly, as in:
///
///     "NSString".send("alloc")
impl<'a> ObjCMethodCall for &'a str {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(class(self), selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(class(self), selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(class(self), selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(class(self), selector.as_selector())
    }
}

/// A trait that allows C strings to be used as selectors without having to convert them first.
pub trait ObjCSelector {
    fn as_selector(self) -> SEL;
}

impl<'a> ObjCSelector for &'a str {
    #[inline]
    fn as_selector(self) -> SEL {
        // TODO(pcwalton): Cache somehow.
        unsafe {
            self.to_c_str().with_ref(|c_string| sel_registerName(c_string))
        }
    }
}

impl ObjCSelector for SEL {
    #[inline]
    fn as_selector(self) -> SEL {
        self
    }
}

/// Traits that simulate variadic parameters for convenience when sending messages.
trait ObjCMethodArgs {
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id;
}
trait ObjCMethodDoubleArgs {
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> c_double;
}
trait ObjCMethodLongArgs {
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long;
}
trait ObjCMethodVoidArgs {
    unsafe fn send_void_args(self, receiver: id, selector: SEL);
}

impl ObjCMethodArgs for () {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id(receiver, selector)
    }
}

impl ObjCMethodArgs for (id, id, id, id, id) {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        let (first, second, third, fourth, fifth) = self;
        invoke_msg_id_id_id_id_id_id(receiver, selector, first, second, third, fourth, fifth)
    }
}

impl ObjCMethodArgs for NSRect {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id_NSRect(receiver, selector, &self)
    }
}

impl ObjCMethodDoubleArgs for () {
    #[inline]
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> f64 {
        invoke_msg_double(receiver, selector)
    }
}

impl ObjCMethodLongArgs for () {
    #[inline]
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long {
        invoke_msg_long(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for () {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for bool {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_bool(receiver, selector, self)
    }
}

impl ObjCMethodVoidArgs for id {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_id(receiver, selector, self)
    }
}

/// A trait that simulates variadic parameters for method calls.

#[cfg(test)]
mod test {
    use std::libc;
    use super::*;

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp = "NSApplication".send("sharedApplication", ());
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let NSObject = class("NSObject");
        let MyObject = "MyObject".to_c_str().with_ref(|s| {
            unsafe {
                objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
            }
        });
        unsafe {
            let doSomething = selector("doSomething");
            let _ = "@@:".to_c_str().with_ref(|types| {
                class_addMethod(MyObject, doSomething, MyObject_doSomething, types)
            });

            objc_registerClassPair(MyObject);

            let mut obj: id = MyObject.send("alloc", ());
            obj = obj.send("init", ());
            obj.send_void("doSomething", ());
        }
    }
}

#[link(name = "msgsend")]
extern {
    fn invoke_msg_double(theReceiver: id, theSelector: SEL) -> f64;
    fn invoke_msg_id(theReceiver: id, theSelector: SEL) -> id;
    fn invoke_msg_id_id_id_id_id_id(theReceiver: id,
                                    theSelector: SEL,
                                    a: id,
                                    b: id,
                                    c: id,
                                    d: id,
                                    e: id)
                                    -> id;
    fn invoke_msg_id_NSRect(theReceiver: id, theSelector: SEL, a: &NSRect) -> id;
    fn invoke_msg_long(theReceiver: id, theSelector: SEL) -> c_long;
    fn invoke_msg_void(theReceiver: id, theSelector: SEL);
    fn invoke_msg_void_bool(theReceiver: id, theSelector: SEL, a: bool);
    fn invoke_msg_void_id(theReceiver: id, theSelector: SEL, a: id);
}

<|endoftext|>


<commit_before>extern crate rand;

use super::std;

use super::bus::Bus;
use super::io::{Audio, Display, Input, Pixel};
use super::io::{SCREEN_WIDTH, SCREEN_HEIGHT};
use super::memory::Memory;

// Constants
///////////////////////////////////////////////////////////////////////

const FRAME_RATE:u64 = 17;

// Processor
////////////////////////////////////////////////////////////////////////

pub struct Processor {
    oc:u16, // Opt Code
    pc:u16, // Program Counter
    sp:u16, // Stack Pointer
    index:u16, // Index

    delay_timer:u8,
    sound_timer:u8,

    draw_flag:bool,

    v:[u8;0x10],
    stack:[u16;0x10],
    screen:[bool;SCREEN_WIDTH*SCREEN_HEIGHT],
    keys:[bool;0x10],
}

impl Default for Processor {
    fn default() -> Processor {
        Processor{
            oc:0x0,
            pc:0x200,
            sp:0x0,
            index:0x0,

            delay_timer:0x0,
            sound_timer:0x0,

            draw_flag:false,

            v:[0x0;0x10],
            stack:[0x0;0x10],
            screen:[false;SCREEN_WIDTH*SCREEN_HEIGHT],
            keys:[false;0x10],
        }
    }
}

impl Processor {

    // non-self functions

    fn read_address(pointer:u16, memory:&Memory) -> u16 {
        let top = (memory.read_memory(pointer) as u16) << 0x8;
        let bot = (memory.read_memory(pointer + 0x1) & 0xFF) as u16;
        top | bot
    }

    // &self functions

    // &mut self functions

    fn load_optcode(&mut self, memory:&Memory){
        self.oc = Processor::read_address(self.pc, memory);
    }

    fn run_optcode<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        let b1 = (self.oc & 0xF000) >> 0xC;
        let b2 = ((self.oc & 0x0F00) >> 0x8) as usize;
        let b3 = ((self.oc & 0x00F0) >> 0x4) as usize;
        let b4 = (self.oc & 0x000F) >> 0x0;

        match (b1, b2, b3, b4) {
            (0x0,0x0,0xE,0x0) => { // clear the screen
                self.screen[..]
                        .copy_from_slice(&[false;SCREEN_WIDTH*SCREEN_HEIGHT]);
                self.pc += 2;
            },
            (0x0,0x0,0xE,0xE) => { // return from subroutine
                self.sp -= 1;
                self.pc = self.stack[self.sp as usize];
                self.pc += 2;
            },
            (0x0,_,_,_) => { // call RCA 1802 program at address NNN
                /* TODO */
                panic!("TODO -- 0x0NNN");
            },
            (0x1,_,_,_) => { // jump to address NNN
                self.pc = self.oc & 0x0FFF;
            },
            (0x2,_,_,_) => { // call subroutine at NNN
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;
                self.pc = self.oc & 0x0FFF;
            },
            (0x3,x,_,_) => { // skip next instruction if VX == NN
                match self.v[x] == (self.oc & 0x00FF) as u8 {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0x4,x,_,_) => { // skip next instruction if VX != NN
                match self.v[x] != (self.oc & 0x00FF) as u8 {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0x5,x,y,0x0) => { // skip next instruction if VX == VY
                match self.v[x] == self.v[y] {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0x6,x,_,_) => { // set VX to NN
                self.v[x] = (self.oc & 0x00FF) as u8;
                self.pc += 2;
            },
            (0x7,x,_,_) => { // add NN to VX
                self.v[x] = self.v[x].wrapping_add((self.oc & 0x00FF) as u8);
                self.pc += 2;
            },
            (0x8,x,y,0x0) => { // set VX to VY
                self.v[x] = self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x1) => { // or VX with VY
                self.v[x] |= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x2) => { // and VX with VY
                self.v[x] &= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x3) => { // xor VX with VY
                self.v[x] ^= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x4) => { // add VY to VX. VF = if carry {1} else {0}
                let (value, flag) = self.v[x].overflowing_add(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0x8,x,y,0x5) => { // sub VY from VX. VF = if borrow {0} else {1}
                let (value, flag) = self.v[x].overflowing_sub(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0x6) => { // shift VX right. VF set to dropped bit.
                self.v[0xF] = self.v[x] & 0x1;
                self.v[x] >>= 1;
                self.pc += 2;
            },
            (0x8,x,y,0x7) => { // set VX to VY - VX. if borrow {0} else {1}
                let (value, flag) =  self.v[y].overflowing_sub(self.v[x]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0xE) => { // shift VX left. VF set to dropped bit.
               self.v[0xF] = (self.v[x] >> 0x7) & 0x1;
               self.v[x] <<= 1;
               self.pc += 2;
            },
            (0x9,x,y,0x0) => { // skip next instruction if VX != VY
                match self.v[x] != self.v[y] {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0xA,_,_,_) => { // set I to NNN
                self.index = self.oc & 0x0FFF;
                self.pc += 2;
            },
            (0xB,_,_,_) => { // jump to address NNN + V0
                self.pc = (self.oc & 0x0FFF) + (self.v[0] as u16);
            },
            (0xC,x,_,_) => { // set VX to random number & NN
                self.v[x] = rand::random::<u8>() & (self.oc & 0xFF) as u8;
                self.pc += 2;
            },
            (0xD,x,y,n) => { // complicated
                let x = self.v[x] as usize;
                let y = self.v[y] as usize;
                self.draw_sprite(x, y, n as usize, &bus.memory);
                self.pc += 2;
            },
            (0xE,x,0x9,0xE) => { // skip next if key in VX is pressed;
                match self.keys[self.v[x] as usize] {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0xE,x,0xA,0x1) => { // skip next if key in VX is not pressed;
                match self.keys[self.v[x] as usize] {
                    true  => self.pc += 2,
                    false => self.pc += 4,
                }
            },
            (0xF,x,0x0,0x7) => {
                self.v[x] = self.delay_timer;
                self.pc += 2;
            },
            (0xF,x,0x0,0xA) => { // a keypress is awaited, then stored in v[x]
                self.v[x] = bus.input.get_key();
            },
            (0xF,x,0x1,0x5) => { // set delay timer to VX
                self.delay_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0x8) => {
                self.sound_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0xE) => {
                let (value, flag) = self.index.overflowing_add(self.v[x] as u16);
                self.index = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0xF,x,0x2,0x9) => {
                self.index = (self.v[x] as u16)*5;
                self.pc += 2;
            },
            (0xF,x,0x3,0x3) => {
                let i = self.index;
                let vx = self.v[x];
                bus.memory.write_memory(i,vx/100);
                bus.memory.write_memory(i+1,(vx/10)%100);
                bus.memory.write_memory(i+2,(vx%100)%10);
                self.pc += 2;
            },
            (0xF,x,0x5,0x5) => { // stores V0 to VX (inclusive) starting at I
                let index = self.index;
                bus.memory.set_range(index, &self.v[0..(x+1)]);
                self.pc += 2;
            },
            (0xF,x,0x6,0x5) => { // fills V0 to VX (inclusive) starting from I
                for i in 0..(x+1) as u16{
                    self.v[i as usize] = bus.memory.read_memory(self.index + i);
                }
                self.pc += 2;
            },
            _ => panic!("unknown instruction received"),
        };
    }

    fn decrement_delay_timer(&mut self){
        if self.delay_timer > 0x0 {
            self.delay_timer -= 0x1;
        }
    }

    fn decrement_sound_timer(&mut self, audio:&Audio){
        if self.sound_timer > 0x0 {
            if self.sound_timer == 0x1 {
                audio.beep();
            }
            self.sound_timer -= 0x1;
        }
    }

    fn print_screen(&self, display:&mut Display){
        for row in 0..SCREEN_HEIGHT {
            for col in 0..SCREEN_WIDTH {
                let pixel = match self.screen[SCREEN_WIDTH*row + col] {
                    true => Pixel::On,
                    false => Pixel::Off,
                };
                let _ = display.set(row, col, pixel);
            }
        }
        display.refresh();
    }

    fn draw_sprite(&mut self, x:usize, y:usize, height:usize, memory:&Memory){
        self.v[0xF] = 0x0;
        let location = x + y*SCREEN_WIDTH;
        let index = self.index as usize;
        for i in 0..height {
            if y + i < SCREEN_HEIGHT {
                let byte = memory.read_memory((index + i) as u16) as usize;
                self.draw_byte(location + i*SCREEN_WIDTH, byte);
            }
        }
    }

    fn draw_byte(&mut self, loc:usize, byte:usize){
        for i in 0..8 {
            if (byte & (0x80 >> i)) != 0 {
                self.draw_flag = true;
                if self.screen[loc+i] {self.v[0xF] = 0x1};
                self.screen[loc+i] ^= true;
            }
        }
    }

    fn set_pushed(&mut self, input:&Input){
        self.keys[..].copy_from_slice(&[false;0x10]);
        for key in input.get_keys(){
            self.keys[key as usize] = true;
        }
    }
    // pub &mut self functions

    pub fn cycle<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        self.load_optcode(&bus.memory);
        self.run_optcode(bus);
        self.decrement_delay_timer();
        self.decrement_sound_timer(&bus.audio);

        self.set_pushed(&bus.input);
        if self.draw_flag {
            self.print_screen(&mut bus.display);
            self.draw_flag = false;
            std::thread::sleep(std::time::Duration::from_millis(FRAME_RATE));
        }
    }
}
<commit_msg>made keys unregistered after use or a second after being pressed<commit_after>extern crate rand;

use super::std;
use super::std::time::{Duration, Instant};

use super::bus::Bus;
use super::io::{Audio, Display, Input, Pixel};
use super::io::{SCREEN_WIDTH, SCREEN_HEIGHT};
use super::memory::Memory;

// Constants
///////////////////////////////////////////////////////////////////////

const FRAME_RATE:u64 = 17;

// Processor
////////////////////////////////////////////////////////////////////////

#[derive(Clone, Copy)]
enum Key {
    Up,
    Down(Instant),
}

pub struct Processor {
    oc:u16, // Opt Code
    pc:u16, // Program Counter
    sp:u16, // Stack Pointer
    index:u16, // Index

    delay_timer:u8,
    sound_timer:u8,

    draw_flag:bool,

    v:[u8;0x10],
    stack:[u16;0x10],
    screen:[bool;SCREEN_WIDTH*SCREEN_HEIGHT],
    keys:[Key;0x10],
}

impl Default for Processor {
    fn default() -> Processor {
        Processor{
            oc:0x0,
            pc:0x200,
            sp:0x0,
            index:0x0,

            delay_timer:0x0,
            sound_timer:0x0,

            draw_flag:false,

            v:[0x0;0x10],
            stack:[0x0;0x10],
            screen:[false;SCREEN_WIDTH*SCREEN_HEIGHT],
            keys:[Key::Up;0x10],
        }
    }
}

impl Processor {

    // non-self functions

    fn read_address(pointer:u16, memory:&Memory) -> u16 {
        let top = (memory.read_memory(pointer) as u16) << 0x8;
        let bot = (memory.read_memory(pointer + 0x1) & 0xFF) as u16;
        top | bot
    }

    // &self functions

    // &mut self functions

    fn load_optcode(&mut self, memory:&Memory){
        self.oc = Processor::read_address(self.pc, memory);
    }

    fn run_optcode<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        let b1 = (self.oc & 0xF000) >> 0xC;
        let b2 = ((self.oc & 0x0F00) >> 0x8) as usize;
        let b3 = ((self.oc & 0x00F0) >> 0x4) as usize;
        let b4 = (self.oc & 0x000F) >> 0x0;

        match (b1, b2, b3, b4) {
            (0x0,0x0,0xE,0x0) => { // clear the screen
                self.screen[..]
                        .copy_from_slice(&[false;SCREEN_WIDTH*SCREEN_HEIGHT]);
                self.pc += 2;
            },
            (0x0,0x0,0xE,0xE) => { // return from subroutine
                self.sp -= 1;
                self.pc = self.stack[self.sp as usize];
                self.pc += 2;
            },
            (0x0,_,_,_) => { // call RCA 1802 program at address NNN
                /* TODO */
                panic!("TODO -- 0x0NNN");
            },
            (0x1,_,_,_) => { // jump to address NNN
                self.pc = self.oc & 0x0FFF;
            },
            (0x2,_,_,_) => { // call subroutine at NNN
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;
                self.pc = self.oc & 0x0FFF;
            },
            (0x3,x,_,_) => { // skip next instruction if VX == NN
                match self.v[x] == (self.oc & 0x00FF) as u8 {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0x4,x,_,_) => { // skip next instruction if VX != NN
                match self.v[x] != (self.oc & 0x00FF) as u8 {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0x5,x,y,0x0) => { // skip next instruction if VX == VY
                match self.v[x] == self.v[y] {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0x6,x,_,_) => { // set VX to NN
                self.v[x] = (self.oc & 0x00FF) as u8;
                self.pc += 2;
            },
            (0x7,x,_,_) => { // add NN to VX
                self.v[x] = self.v[x].wrapping_add((self.oc & 0x00FF) as u8);
                self.pc += 2;
            },
            (0x8,x,y,0x0) => { // set VX to VY
                self.v[x] = self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x1) => { // or VX with VY
                self.v[x] |= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x2) => { // and VX with VY
                self.v[x] &= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x3) => { // xor VX with VY
                self.v[x] ^= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x4) => { // add VY to VX. VF = if carry {1} else {0}
                let (value, flag) = self.v[x].overflowing_add(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0x8,x,y,0x5) => { // sub VY from VX. VF = if borrow {0} else {1}
                let (value, flag) = self.v[x].overflowing_sub(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0x6) => { // shift VX right. VF set to dropped bit.
                self.v[0xF] = self.v[x] & 0x1;
                self.v[x] >>= 1;
                self.pc += 2;
            },
            (0x8,x,y,0x7) => { // set VX to VY - VX. if borrow {0} else {1}
                let (value, flag) =  self.v[y].overflowing_sub(self.v[x]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0xE) => { // shift VX left. VF set to dropped bit.
               self.v[0xF] = (self.v[x] >> 0x7) & 0x1;
               self.v[x] <<= 1;
               self.pc += 2;
            },
            (0x9,x,y,0x0) => { // skip next instruction if VX != VY
                match self.v[x] != self.v[y] {
                    true  => self.pc += 4,
                    false => self.pc += 2,
                }
            },
            (0xA,_,_,_) => { // set I to NNN
                self.index = self.oc & 0x0FFF;
                self.pc += 2;
            },
            (0xB,_,_,_) => { // jump to address NNN + V0
                self.pc = (self.oc & 0x0FFF) + (self.v[0] as u16);
            },
            (0xC,x,_,_) => { // set VX to random number & NN
                self.v[x] = rand::random::<u8>() & (self.oc & 0xFF) as u8;
                self.pc += 2;
            },
            (0xD,x,y,n) => { // complicated
                let x = self.v[x] as usize;
                let y = self.v[y] as usize;
                self.draw_sprite(x, y, n as usize, &bus.memory);
                self.pc += 2;
            },
            (0xE,x,0x9,0xE) => { // skip next if key in VX is pressed;
                match self.keys[self.v[x] as usize] {
                    Key::Down(_) => self.pc += 4,
                    Key::Up => self.pc += 2,
                }
                self.keys[self.v[x] as usize] = Key::Up;
            },
            (0xE,x,0xA,0x1) => { // skip next if key in VX is not pressed;
                match self.keys[self.v[x] as usize] {
                    Key::Down(_)  => self.pc += 2,
                    Key::Up => self.pc += 4,
                }
                self.keys[self.v[x] as usize] = Key::Up;
            },
            (0xF,x,0x0,0x7) => {
                self.v[x] = self.delay_timer;
                self.pc += 2;
            },
            (0xF,x,0x0,0xA) => { // a keypress is awaited, then stored in v[x]
                self.v[x] = bus.input.get_key();
            },
            (0xF,x,0x1,0x5) => { // set delay timer to VX
                self.delay_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0x8) => {
                self.sound_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0xE) => {
                let (value, flag) = self.index.overflowing_add(self.v[x] as u16);
                self.index = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0xF,x,0x2,0x9) => {
                self.index = (self.v[x] as u16)*5;
                self.pc += 2;
            },
            (0xF,x,0x3,0x3) => {
                let i = self.index;
                let vx = self.v[x];
                bus.memory.write_memory(i,vx/100);
                bus.memory.write_memory(i+1,(vx/10)%100);
                bus.memory.write_memory(i+2,(vx%100)%10);
                self.pc += 2;
            },
            (0xF,x,0x5,0x5) => { // stores V0 to VX (inclusive) starting at I
                let index = self.index;
                bus.memory.set_range(index, &self.v[0..(x+1)]);
                self.pc += 2;
            },
            (0xF,x,0x6,0x5) => { // fills V0 to VX (inclusive) starting from I
                for i in 0..(x+1) as u16{
                    self.v[i as usize] = bus.memory.read_memory(self.index + i);
                }
                self.pc += 2;
            },
            _ => panic!("unknown instruction received"),
        };
    }

    fn decrement_delay_timer(&mut self){
        if self.delay_timer > 0x0 {
            self.delay_timer -= 0x1;
        }
    }

    fn decrement_sound_timer(&mut self, audio:&Audio){
        if self.sound_timer > 0x0 {
            if self.sound_timer == 0x1 {
                audio.beep();
            }
            self.sound_timer -= 0x1;
        }
    }

    fn print_screen(&self, display:&mut Display){
        for row in 0..SCREEN_HEIGHT {
            for col in 0..SCREEN_WIDTH {
                let pixel = match self.screen[SCREEN_WIDTH*row + col] {
                    true => Pixel::On,
                    false => Pixel::Off,
                };
                let _ = display.set(row, col, pixel);
            }
        }
        display.refresh();
    }

    fn draw_sprite(&mut self, x:usize, y:usize, height:usize, memory:&Memory){
        self.v[0xF] = 0x0;
        let location = x + y*SCREEN_WIDTH;
        let index = self.index as usize;
        for i in 0..height {
            if y + i < SCREEN_HEIGHT {
                let byte = memory.read_memory((index + i) as u16) as usize;
                self.draw_byte(location + i*SCREEN_WIDTH, byte);
            }
        }
    }

    fn draw_byte(&mut self, loc:usize, byte:usize){
        for i in 0..8 {
            if (byte & (0x80 >> i)) != 0 {
                self.draw_flag = true;
                if self.screen[loc+i] {self.v[0xF] = 0x1};
                self.screen[loc+i] ^= true;
            }
        }
    }

    fn set_pushed(&mut self, input:&Input){
        let timeout = Duration::new(1,0);

        for key in &mut self.keys {
            *key = match *key {
                Key::Down(x) if x.elapsed() > timeout => Key::Up,
                _ => *key,
            };
        }

        for key in input.get_keys(){
            self.keys[key as usize] = Key::Down(Instant::now());
        }
    }
    // pub &mut self functions

    pub fn cycle<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        self.load_optcode(&bus.memory);
        self.run_optcode(bus);
        self.decrement_delay_timer();
        self.decrement_sound_timer(&bus.audio);

        if self.draw_flag {
            self.print_screen(&mut bus.display);
            self.draw_flag = false;
            std::thread::sleep(Duration::from_millis(FRAME_RATE));
        }
        self.set_pushed(&bus.input);
    }
}
<|endoftext|>


<commit_before>pub use expectest::prelude::{be_ok, be_err};

pub use sql::lexer::Tokenizer;
pub use sql::parser::Parser;
pub use sql::query_executer::QueryExecuter;

describe! create_table_queries {

    describe! queries_execution {

        before_each {
            let mut executer = QueryExecuter::default();
        }

        it "creates single column table" {
            expect!(executer.execute("create table table_name (col int);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("'table_name' was created".to_owned()));
        }

        it "creates a table with list of columns" {
            expect!(executer.execute("create table table_name (col1 int, col2 int, col3 int);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("'table_name' was created".to_owned()));
        }

        it "inserts row in created table" {
            executer.execute("create table table_name (col int);".to_owned().tokenize().unwrap().parse().unwrap());

            expect!(executer.execute("insert into table_name values(1);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("row was inserted".to_owned()));
        }

        it "inserts row in table with many columns" {
            executer.execute("create table table_name (col1 int, col2 int);".to_owned().tokenize().unwrap().parse().unwrap());

            expect!(executer.execute("insert into table_name values(1, 2);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("row was inserted".to_owned()));
        }
    }
}
<commit_msg>add missing test<commit_after>pub use expectest::prelude::{be_ok, be_err};

pub use sql::lexer::Tokenizer;
pub use sql::parser::Parser;
pub use sql::query_executer::QueryExecuter;

describe! create_table_queries {

    describe! queries_execution {

        before_each {
            let mut executer = QueryExecuter::default();
        }

        it "creates single column table" {
            expect!(executer.execute("create table table_name (col int);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("'table_name' was created".to_owned()));
        }

        it "creates a table with list of columns" {
            expect!(executer.execute("create table table_name (col1 int, col2 int, col3 int);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("'table_name' was created".to_owned()));
        }

        it "inserts row in created table" {
            executer.execute("create table table_name (col int);".to_owned().tokenize().unwrap().parse().unwrap());

            expect!(executer.execute("insert into table_name values(1);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("row was inserted".to_owned()));
        }

        it "inserts row in table with many columns" {
            executer.execute("create table table_name (col1 int, col2 int);".to_owned().tokenize().unwrap().parse().unwrap());

            expect!(executer.execute("insert into table_name values(1, 2);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_ok().value("row was inserted".to_owned()));
        }

        it "does not insert into table that does not exist" {
            expect!(executer.execute("insert into table_name values(1);".to_owned().tokenize().unwrap().parse().unwrap()))
                .to(be_err().value("[ERR 100] table 'table_name' does not exist".to_owned()));
        }
    }
}
<|endoftext|>