<commit_before>use errors::Error;
//use factory::FactoryBase;
use container::{ReadGuard, WriteGuard, Container};
use reflect;

use downcast::Downcast;

use std::marker::PhantomData;
use std::any::Any;

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub trait Method<'a, Key, SvcBase: ?Sized>: Any
    where Key: reflect::Key, SvcBase: Any
{
    type Ret: 'a;
    fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>>;
    fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>>;
}

// ++++++++++++++++++++ dummy ++++++++++++++++++++

impl<'a, Key, SvcBase: ?Sized> Method<'a, Key, SvcBase> for ()
    where Key: reflect::Key, SvcBase: Any
{
    type Ret = ();

    fn resolve_unprotected(_: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        Ok(())
    }
    fn try_resolve_unprotected(_: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        Ok(())
    }
}

// ++++++++++++++++++++ Read ++++++++++++++++++++

pub struct Read<Svc>(PhantomData<fn(Svc)>);

impl<'a, Key, SvcBase: ?Sized, Svc> Method<'a, Key, SvcBase> for Read<Svc>
where
    Key: reflect::Key,
    Svc: reflect::Service<Key = Key>,
    SvcBase: Downcast<Svc>,
{
    type Ret = ReadGuard<'a, Svc, SvcBase>;
    fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.read::<Svc>()
    }
    fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.try_read::<Svc>()
    }
}

macro_rules! multi_read {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Key, SvcBase: ?Sized, $($params),+> Method<'a, Key, SvcBase> for Read<($($params,)+)>
        where
            Key: reflect::Key,
            $($params: reflect::Service<Key = Key>),+,
            $(SvcBase: Downcast<$params>),+
        {
            type Ret = ($(<Read<$params> as Method<'a, Key, SvcBase>>::Ret,)+);
            fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.read::<$params>()},)+
                ))
            }
            fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.try_read::<$params>()},)+
                ))
            }
        }
    )+}
}

multi_read!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    //{A B C D E F G H J K L M N O P}
    //{A B C D E F G H J K L M N O P Q}
}

// ++++++++++++++++++++ Write ++++++++++++++++++++

pub struct Write<Svc>(PhantomData<fn(Svc)>);

impl<'a, Key, SvcBase: ?Sized, Svc> Method<'a, Key, SvcBase> for Write<Svc>
where
    Key: reflect::Key,
    Svc: reflect::Service<Key = Key>,
    SvcBase: Downcast<Svc>,
{
    type Ret = WriteGuard<'a, Svc, SvcBase>;
    fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.write::<Svc>()
    }
    fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.try_write::<Svc>()
    }
}

macro_rules! multi_write {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Key, SvcBase: ?Sized, $($params),+> Method<'a, Key, SvcBase> for Write<($($params,)+)>
        where
            Key: reflect::Key,
            $($params: reflect::Service<Key = Key>),+,
            $(SvcBase: Downcast<$params>),+
        {
            type Ret = ($(<Write<$params> as Method<'a, Key, SvcBase>>::Ret,)+);
            fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.write::<$params>()},)+
                ))
            }
            fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.try_write::<$params>()},)+
                ))
            }
        }
    )+}
}

multi_write!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    {A B C D E F G H J K L M N O P}
    {A B C D E F G H J K L M N O P Q}
}

/*
// ++++++++++++++++++++ Create ++++++++++++++++++++

pub struct Create<Obj>(fn(Obj));

impl<'a, Cont, Obj> Method<'a, Cont> for Create<Obj>
where
    Obj: reflect::FactoryObject<Key = Cont::Key>,
    Obj::Factory: FactoryBase<'a, Cont, Obj>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Obj::Factory>,
{
    type Ret = Obj;
    fn resolve_unprotected(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.create::<Obj>()
    }
}

macro_rules! multi_create {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Cont, $($params),+> Method<'a, Cont> for Create<($($params,)+)>
        where
            $($params: reflect::FactoryObject<Key = Cont::Key>),+,
            $($params::Factory: FactoryBase<'a, Cont, $params>),+,
            Cont: Container<'a>,
            $(Cont::ServiceBase: Downcast<$params::Factory>),+
        {
            type Ret = ($(<Create<$params> as Method<'a, Cont>>::Ret,)+);
            fn resolve_unprotected(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok((
                    $(try!{ioc.create::<$params>()},)+
                ))
            }
        }
    )+}
}
*/
// ++++++++++++++++++++ multi-method ++++++++++++++++++++

macro_rules! e {
    ($e:expr) => { $e }
}

macro_rules! multi_methods {
    ($({$($idx:tt,$params:ident)+})+) => {$(

        impl<'a, Key, SvcBase: ?Sized, $($params),+> Method<'a, Key, SvcBase> for ($($params,)+)
        where
            Key: reflect::Key,
            $($params: Method<'a, Key, SvcBase> + 'a),+,
            SvcBase: Any,
        {
            type Ret = ($($params::Ret,)+);
            fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{e![$params::resolve_unprotected(ioc)]},)+
                ))
            }
            fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{e![$params::try_resolve_unprotected(ioc)]},)+
                ))
            }
        }

    )+}
}

multi_methods!{
    {0,A}
    {0,A 1,B}
    {0,A 1,B 2,C}
    {0,A 1,B 2,C 3,D}
    {0,A 1,B 2,C 3,D 4,E}
    {0,A 1,B 2,C 3,D 4,E 5,F}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N 13,O}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N 13,O 14,P}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N 13,O 14,P 15,Q}
}

<commit_msg>add ContainerBuilder::register_default()<commit_after>use errors::Error;
//use factory::FactoryBase;
use container::{ReadGuard, WriteGuard, Container};
use reflect;

use downcast::Downcast;

use std::marker::PhantomData;
use std::any::Any;

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub trait Method<'a, Key, SvcBase: ?Sized>: Any
    where Key: reflect::Key, SvcBase: Any
{
    type Ret: 'a;
    fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>>;
    fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>>;
}

macro_rules! impl_nil {
    ($nil_ty:ty) => {
        impl<'a, Key, SvcBase: ?Sized> Method<'a, Key, SvcBase> for $nil_ty
            where Key: reflect::Key, SvcBase: Any
        {
            type Ret = ();

            fn resolve_unprotected(_: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok(())
            }
            fn try_resolve_unprotected(_: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok(())
            }
        }
    }
}

impl_nil!(());

// ++++++++++++++++++++ Read ++++++++++++++++++++

pub struct Read<Svc>(PhantomData<fn(Svc)>);

impl_nil!(Read<()>);

impl<'a, Key, SvcBase: ?Sized, Svc> Method<'a, Key, SvcBase> for Read<Svc>
where
    Key: reflect::Key,
    Svc: reflect::Service<Key = Key>,
    SvcBase: Downcast<Svc>,
{
    type Ret = ReadGuard<'a, Svc, SvcBase>;
    fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.read::<Svc>()
    }
    fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.try_read::<Svc>()
    }
}

macro_rules! multi_read {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Key, SvcBase: ?Sized, $($params),+> Method<'a, Key, SvcBase> for Read<($($params,)+)>
        where
            Key: reflect::Key,
            $($params: reflect::Service<Key = Key>),+,
            $(SvcBase: Downcast<$params>),+
        {
            type Ret = ($(<Read<$params> as Method<'a, Key, SvcBase>>::Ret,)+);
            fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.read::<$params>()},)+
                ))
            }
            fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.try_read::<$params>()},)+
                ))
            }
        }
    )+}
}

multi_read!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    //{A B C D E F G H J K L M N O P}
    //{A B C D E F G H J K L M N O P Q}
}

// ++++++++++++++++++++ Write ++++++++++++++++++++

pub struct Write<Svc>(PhantomData<fn(Svc)>);

impl_nil!(Write<()>);

impl<'a, Key, SvcBase: ?Sized, Svc> Method<'a, Key, SvcBase> for Write<Svc>
where
    Key: reflect::Key,
    Svc: reflect::Service<Key = Key>,
    SvcBase: Downcast<Svc>,
{
    type Ret = WriteGuard<'a, Svc, SvcBase>;
    fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.write::<Svc>()
    }
    fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
        ioc.try_write::<Svc>()
    }
}

macro_rules! multi_write {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Key, SvcBase: ?Sized, $($params),+> Method<'a, Key, SvcBase> for Write<($($params,)+)>
        where
            Key: reflect::Key,
            $($params: reflect::Service<Key = Key>),+,
            $(SvcBase: Downcast<$params>),+
        {
            type Ret = ($(<Write<$params> as Method<'a, Key, SvcBase>>::Ret,)+);
            fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.write::<$params>()},)+
                ))
            }
            fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{ioc.try_write::<$params>()},)+
                ))
            }
        }
    )+}
}

multi_write!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    {A B C D E F G H J K L M N O P}
    {A B C D E F G H J K L M N O P Q}
}

/*
// ++++++++++++++++++++ Create ++++++++++++++++++++

pub struct Create<Obj>(fn(Obj));

impl<'a, Cont, Obj> Method<'a, Cont> for Create<Obj>
where
    Obj: reflect::FactoryObject<Key = Cont::Key>,
    Obj::Factory: FactoryBase<'a, Cont, Obj>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Obj::Factory>,
{
    type Ret = Obj;
    fn resolve_unprotected(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.create::<Obj>()
    }
}

macro_rules! multi_create {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Cont, $($params),+> Method<'a, Cont> for Create<($($params,)+)>
        where
            $($params: reflect::FactoryObject<Key = Cont::Key>),+,
            $($params::Factory: FactoryBase<'a, Cont, $params>),+,
            Cont: Container<'a>,
            $(Cont::ServiceBase: Downcast<$params::Factory>),+
        {
            type Ret = ($(<Create<$params> as Method<'a, Cont>>::Ret,)+);
            fn resolve_unprotected(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok((
                    $(try!{ioc.create::<$params>()},)+
                ))
            }
        }
    )+}
}
*/
// ++++++++++++++++++++ multi-method ++++++++++++++++++++

macro_rules! e {
    ($e:expr) => { $e }
}

macro_rules! multi_methods {
    ($({$($idx:tt,$params:ident)+})+) => {$(

        impl<'a, Key, SvcBase: ?Sized, $($params),+> Method<'a, Key, SvcBase> for ($($params,)+)
        where
            Key: reflect::Key,
            $($params: Method<'a, Key, SvcBase> + 'a),+,
            SvcBase: Any,
        {
            type Ret = ($($params::Ret,)+);
            fn resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{e![$params::resolve_unprotected(ioc)]},)+
                ))
            }
            fn try_resolve_unprotected(ioc: &'a Container<Key, SvcBase>) -> Result<Self::Ret, Error<'a, Key>> {
                Ok((
                    $(try!{e![$params::try_resolve_unprotected(ioc)]},)+
                ))
            }
        }

    )+}
}

multi_methods!{
    {0,A}
    {0,A 1,B}
    {0,A 1,B 2,C}
    {0,A 1,B 2,C 3,D}
    {0,A 1,B 2,C 3,D 4,E}
    {0,A 1,B 2,C 3,D 4,E 5,F}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N 13,O}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N 13,O 14,P}
    {0,A 1,B 2,C 3,D 4,E 5,F 6,G 7,H 8,J 9,K 10,L 11,M 12,N 13,O 14,P 15,Q}
}

<|endoftext|>


<commit_before>pub mod gen;
pub mod dump;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::{Iter, IterMut};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use ast::{BinOp, UnOp};
use interner::Name;
use sym::BuiltinType;

pub struct Mir {
    blocks: Vec<Rc<RefCell<Block>>>,
    vars: Vec<VarDecl>,
    temps: Vec<TempDecl>,
}

impl Debug for Mir {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "mir.fct")
    }
}

impl Mir {
    pub fn new() -> Mir {
        Mir {
            blocks: Vec::new(),
            vars: Vec::new(),
            temps: Vec::new()
        }
    }

    pub fn block(&self, id: BlockId) -> Rc<RefCell<Block>> {
        self.blocks[id.0].clone()
    }

    pub fn increase_var(&mut self, id: VarId) -> u32 {
        let var = self.var_mut(id);
        var.next_ssa += 1;

        var.next_ssa
    }

    pub fn var_mut(&mut self, id: VarId) -> &mut VarDecl {
        &mut self.vars[id.0]
    }

    pub fn var(&self, id: VarId) -> &VarDecl {
        &self.vars[id.0]
    }

    pub fn add_block(&mut self) -> BlockId {
        let id = BlockId(self.blocks.len());
        self.blocks.push(Rc::new(RefCell::new(Block::new(id))));

        id
    }

    pub fn add_var(&mut self, name: Name, ty: BuiltinType) -> VarId {
        let id = VarId(self.vars.len());
        self.vars.push(VarDecl {
            name: name,
            ty: ty,
            cur_ssa: 0,
            next_ssa: 0
        });

        id
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct VarId(usize);

impl ToString for VarId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct VarDecl {
    name: Name,
    ty: BuiltinType,
    cur_ssa: u32,
    next_ssa: u32,
}

pub struct TempDecl {
    ty: BuiltinType
}

pub enum Lvalue {
    Var(u32),
    Temp(u32)
}

pub enum Rvalue {
    Use(Operand),
    Un(UnOp, Operand),
    Bin(BinOp, Operand, Operand),
}

pub enum Operand {
    Consume(Lvalue),
    Const(u32)
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct BlockId(usize);

impl ToString for BlockId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Block {
    id: BlockId,
    instructions: Vec<Instr>,
    predecessors: Vec<BlockId>,
}

impl Block {
    fn new(id: BlockId) -> Block {
        Block {
            id: id,
            instructions: Vec::new(),
            predecessors: Vec::new()
        }
    }

    fn add_instr(&mut self, instr: Instr) {
        self.instructions.push(instr);
    }

    fn last_instr(&self) -> Option<&Instr> {
        self.instructions.last()
    }

    fn add_predecessor(&mut self, id: BlockId) {
        self.predecessors.push(id);
    }

    fn find_phi_mut(&mut self, id: VarId) -> Option<&mut InstrPhiType> {
        for instr in &mut self.instructions {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                if phi.var_id == id {
                    return Some(phi);
                }

            } else {
                return None;
            }
        }

        None
    }

    fn add_phi(&mut self, phi: InstrPhiType) {
        let mut ind : usize = 0;

        for instr in &self.instructions {
            if let Instr::InstrPhi(ref instr_phi) = *instr {
                if instr_phi.var_id == phi.var_id {
                    panic!("phi-instruction for var {} already exists.",
                        phi.var_id.to_string());
                }

                ind += 1;
            } else {
                break;
            }
        }

        self.instructions.insert(ind, Instr::InstrPhi(phi));
    }

    fn phi_iter(&self) -> PhiIter {
        PhiIter {
            iter: self.instructions.iter()
        }
    }

    fn phi_iter_mut(&mut self) -> PhiIterMut {
        PhiIterMut {
            iter: self.instructions.iter_mut()
        }
    }
}

struct PhiIter<'a> {
    iter: Iter<'a, Instr>
}

impl<'a> Iterator for PhiIter<'a> {
    type Item = &'a InstrPhiType;

    fn next(&mut self) -> Option<&'a InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct PhiIterMut<'a> {
    iter: IterMut<'a, Instr>
}

impl<'a> Iterator for PhiIterMut<'a> {
    type Item = &'a mut InstrPhiType;

    fn next(&mut self) -> Option<&'a mut InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

pub enum Terminator {
    Ret,

    If {
        cond: Operand,
        targets: (BlockId, BlockId)
    },

    Goto {
        target: BlockId
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Instr {
    InstrRet(Option<Opnd>),
    InstrTest(InstrTestType),
    InstrBin(InstrBinType),
    InstrUn(InstrUnType),
    InstrAssign(InstrAssignType),
    InstrPhi(InstrPhiType),
    InstrCall(InstrCallType),
    InstrStr(InstrStrType),
    InstrGoto(BlockId),
}

impl Instr {
    fn ret() -> Instr {
        Instr::InstrRet(None)
    }

    fn ret_value(opnd: Opnd) -> Instr {
        Instr::InstrRet(Some(opnd))
    }

    fn test(opnd: Opnd, true_block: BlockId, false_block: BlockId) -> Instr {
        Instr::InstrTest(InstrTestType {
            opnd: opnd,
            true_block: true_block,
            false_block: false_block,
        })
    }

    fn bin(dest: Opnd, lhs: Opnd, op: BinOp, rhs: Opnd) -> Instr {
        Instr::InstrBin(InstrBinType {
            dest: dest,
            lhs: lhs,
            op: op,
            rhs: rhs,
        })
    }

    fn un(dest: Opnd, op: UnOp, src: Opnd) -> Instr {
        Instr::InstrUn(InstrUnType {
            dest: dest,
            op: op,
            src: src,
        })
    }

    fn assign(dest: Opnd, src: Opnd) -> Instr {
        Instr::InstrAssign(InstrAssignType {
            dest: dest,
            src: src,
        })
    }

    fn call(dest: Opnd, name: String, args: Vec<Opnd>) -> Instr {
        Instr::InstrCall(InstrCallType {
            dest: dest,
            name: name,
            args: args,
        })
    }

    fn str(dest: Opnd, value: String) -> Instr {
        Instr::InstrStr(InstrStrType {
            dest: dest,
            value: value,
        })
    }

    fn goto(target: BlockId) -> Instr {
        Instr::InstrGoto(target)
    }

    fn phi(var_id: VarId, dest: u32, opnds: Vec<u32>, backup: u32) -> Instr {
        Instr::InstrPhi(InstrPhiType {
            var_id: var_id,
            dest: dest,
            opnds: opnds,
            backup: backup,
        })
    }
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrTestType {
    pub opnd: Opnd,
    pub true_block: BlockId,
    pub false_block: BlockId,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrBinType {
    pub dest: Opnd,
    pub lhs: Opnd,
    pub op: BinOp,
    pub rhs: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrUnType {
    pub dest: Opnd,
    pub op: UnOp,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrAssignType {
    pub dest: Opnd,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrCallType {
    pub dest: Opnd,
    pub name: String,
    pub args: Vec<Opnd>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrPhiType {
    pub var_id: VarId,
    pub dest: u32,
    pub opnds: Vec<u32>,
    pub backup: u32,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrStrType {
    pub dest: Opnd,
    pub value: String,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Opnd {
    OpndReg(u32),
    OpndVar(VarId, u32),
    OpndInt(i32),
    OpndBool(bool),
}

#[cfg(test)]
mod tests {
    use interner::Name;
    use mir::*;
    use mir::Instr::*;
    use sym::BuiltinType;

    #[test]
    fn find_phi_fails() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.find_phi_mut(VarId(0)));
    }

    #[test]
    fn find_phi_succeeds() {
        let mut block = Block::new(BlockId(0));
        let phi = Instr::phi(VarId(0), 0, Vec::new(), 0);
        block.add_instr(phi);

        assert!(block.find_phi_mut(VarId(0)).is_some());
        assert_eq!(None, block.find_phi_mut(VarId(1)));
    }

    #[test]
    fn increase_var() {
        let mut fct = Mir::new();
        let var_id = fct.add_var(Name(0), BuiltinType::Int);

        assert_eq!(1, fct.increase_var(var_id));
    }

    #[test]
    #[should_panic]
    fn add_phi_panics() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(0));
        block.add_phi(phi(0));
    }

    #[test]
    fn add_phi() {
        let mut block = Block::new(BlockId(0));

        block.add_instr(Instr::ret());
        block.add_phi(phi(0));
        block.add_phi(phi(1));
        block.add_phi(phi(2));

        let instrs = &block.instructions;

        assert_eq!(phi_instr(0), instrs[0]);
        assert_eq!(phi_instr(1), instrs[1]);
        assert_eq!(phi_instr(2), instrs[2]);
        assert_eq!(Instr::ret(), instrs[3]);
    }

    #[test]
    fn phi_iterator_empty() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.phi_iter().next());
    }

    #[test]
    fn phi_iterator_single() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(3));
        block.add_instr(Instr::ret());

        let mut iter = block.phi_iter();
        assert_eq!(Some(&phi(3)), iter.next());
        assert_eq!(None, iter.next());
    }

    fn phi_instr(var: usize) -> Instr {
        InstrPhi(phi(var))
    }

    fn phi(var: usize) -> InstrPhiType {
        InstrPhiType {
            var_id: VarId(var),
            dest: 0,
            opnds: Vec::new(),
            backup: 0
        }
    }
}
<commit_msg>MIR: added enum for constants<commit_after>pub mod gen;
pub mod dump;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::{Iter, IterMut};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use ast::{BinOp, UnOp};
use interner::Name;
use sym::BuiltinType;

pub struct Mir {
    blocks: Vec<Rc<RefCell<Block>>>,
    vars: Vec<VarDecl>,
    temps: Vec<TempDecl>,
}

impl Debug for Mir {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "mir.fct")
    }
}

impl Mir {
    pub fn new() -> Mir {
        Mir {
            blocks: Vec::new(),
            vars: Vec::new(),
            temps: Vec::new()
        }
    }

    pub fn block(&self, id: BlockId) -> Rc<RefCell<Block>> {
        self.blocks[id.0].clone()
    }

    pub fn increase_var(&mut self, id: VarId) -> u32 {
        let var = self.var_mut(id);
        var.next_ssa += 1;

        var.next_ssa
    }

    pub fn var_mut(&mut self, id: VarId) -> &mut VarDecl {
        &mut self.vars[id.0]
    }

    pub fn var(&self, id: VarId) -> &VarDecl {
        &self.vars[id.0]
    }

    pub fn add_block(&mut self) -> BlockId {
        let id = BlockId(self.blocks.len());
        self.blocks.push(Rc::new(RefCell::new(Block::new(id))));

        id
    }

    pub fn add_var(&mut self, name: Name, ty: BuiltinType) -> VarId {
        let id = VarId(self.vars.len());
        self.vars.push(VarDecl {
            name: name,
            ty: ty,
            cur_ssa: 0,
            next_ssa: 0
        });

        id
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct VarId(usize);

impl ToString for VarId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct VarDecl {
    name: Name,
    ty: BuiltinType,
    cur_ssa: u32,
    next_ssa: u32,
}

pub struct TempDecl {
    ty: BuiltinType
}

pub enum Lvalue {
    Var(u32),
    Temp(u32)
}

pub enum Rvalue {
    Use(Operand),
    Un(UnOp, Operand),
    Bin(BinOp, Operand, Operand),
}

pub enum Operand {
    Consume(Lvalue),
    Const(Const)
}

pub enum Const {
    Str(String),
    Bool(bool),
    Int(u32)
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct BlockId(usize);

impl ToString for BlockId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Block {
    id: BlockId,
    instructions: Vec<Instr>,
    predecessors: Vec<BlockId>,
}

impl Block {
    fn new(id: BlockId) -> Block {
        Block {
            id: id,
            instructions: Vec::new(),
            predecessors: Vec::new()
        }
    }

    fn add_instr(&mut self, instr: Instr) {
        self.instructions.push(instr);
    }

    fn last_instr(&self) -> Option<&Instr> {
        self.instructions.last()
    }

    fn add_predecessor(&mut self, id: BlockId) {
        self.predecessors.push(id);
    }

    fn find_phi_mut(&mut self, id: VarId) -> Option<&mut InstrPhiType> {
        for instr in &mut self.instructions {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                if phi.var_id == id {
                    return Some(phi);
                }

            } else {
                return None;
            }
        }

        None
    }

    fn add_phi(&mut self, phi: InstrPhiType) {
        let mut ind : usize = 0;

        for instr in &self.instructions {
            if let Instr::InstrPhi(ref instr_phi) = *instr {
                if instr_phi.var_id == phi.var_id {
                    panic!("phi-instruction for var {} already exists.",
                        phi.var_id.to_string());
                }

                ind += 1;
            } else {
                break;
            }
        }

        self.instructions.insert(ind, Instr::InstrPhi(phi));
    }

    fn phi_iter(&self) -> PhiIter {
        PhiIter {
            iter: self.instructions.iter()
        }
    }

    fn phi_iter_mut(&mut self) -> PhiIterMut {
        PhiIterMut {
            iter: self.instructions.iter_mut()
        }
    }
}

struct PhiIter<'a> {
    iter: Iter<'a, Instr>
}

impl<'a> Iterator for PhiIter<'a> {
    type Item = &'a InstrPhiType;

    fn next(&mut self) -> Option<&'a InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct PhiIterMut<'a> {
    iter: IterMut<'a, Instr>
}

impl<'a> Iterator for PhiIterMut<'a> {
    type Item = &'a mut InstrPhiType;

    fn next(&mut self) -> Option<&'a mut InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

pub enum Terminator {
    Ret,

    If {
        cond: Operand,
        targets: (BlockId, BlockId)
    },

    Goto {
        target: BlockId
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Instr {
    InstrRet(Option<Opnd>),
    InstrTest(InstrTestType),
    InstrBin(InstrBinType),
    InstrUn(InstrUnType),
    InstrAssign(InstrAssignType),
    InstrPhi(InstrPhiType),
    InstrCall(InstrCallType),
    InstrStr(InstrStrType),
    InstrGoto(BlockId),
}

impl Instr {
    fn ret() -> Instr {
        Instr::InstrRet(None)
    }

    fn ret_value(opnd: Opnd) -> Instr {
        Instr::InstrRet(Some(opnd))
    }

    fn test(opnd: Opnd, true_block: BlockId, false_block: BlockId) -> Instr {
        Instr::InstrTest(InstrTestType {
            opnd: opnd,
            true_block: true_block,
            false_block: false_block,
        })
    }

    fn bin(dest: Opnd, lhs: Opnd, op: BinOp, rhs: Opnd) -> Instr {
        Instr::InstrBin(InstrBinType {
            dest: dest,
            lhs: lhs,
            op: op,
            rhs: rhs,
        })
    }

    fn un(dest: Opnd, op: UnOp, src: Opnd) -> Instr {
        Instr::InstrUn(InstrUnType {
            dest: dest,
            op: op,
            src: src,
        })
    }

    fn assign(dest: Opnd, src: Opnd) -> Instr {
        Instr::InstrAssign(InstrAssignType {
            dest: dest,
            src: src,
        })
    }

    fn call(dest: Opnd, name: String, args: Vec<Opnd>) -> Instr {
        Instr::InstrCall(InstrCallType {
            dest: dest,
            name: name,
            args: args,
        })
    }

    fn str(dest: Opnd, value: String) -> Instr {
        Instr::InstrStr(InstrStrType {
            dest: dest,
            value: value,
        })
    }

    fn goto(target: BlockId) -> Instr {
        Instr::InstrGoto(target)
    }

    fn phi(var_id: VarId, dest: u32, opnds: Vec<u32>, backup: u32) -> Instr {
        Instr::InstrPhi(InstrPhiType {
            var_id: var_id,
            dest: dest,
            opnds: opnds,
            backup: backup,
        })
    }
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrTestType {
    pub opnd: Opnd,
    pub true_block: BlockId,
    pub false_block: BlockId,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrBinType {
    pub dest: Opnd,
    pub lhs: Opnd,
    pub op: BinOp,
    pub rhs: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrUnType {
    pub dest: Opnd,
    pub op: UnOp,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrAssignType {
    pub dest: Opnd,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrCallType {
    pub dest: Opnd,
    pub name: String,
    pub args: Vec<Opnd>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrPhiType {
    pub var_id: VarId,
    pub dest: u32,
    pub opnds: Vec<u32>,
    pub backup: u32,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrStrType {
    pub dest: Opnd,
    pub value: String,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Opnd {
    OpndReg(u32),
    OpndVar(VarId, u32),
    OpndInt(i32),
    OpndBool(bool),
}

#[cfg(test)]
mod tests {
    use interner::Name;
    use mir::*;
    use mir::Instr::*;
    use sym::BuiltinType;

    #[test]
    fn find_phi_fails() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.find_phi_mut(VarId(0)));
    }

    #[test]
    fn find_phi_succeeds() {
        let mut block = Block::new(BlockId(0));
        let phi = Instr::phi(VarId(0), 0, Vec::new(), 0);
        block.add_instr(phi);

        assert!(block.find_phi_mut(VarId(0)).is_some());
        assert_eq!(None, block.find_phi_mut(VarId(1)));
    }

    #[test]
    fn increase_var() {
        let mut fct = Mir::new();
        let var_id = fct.add_var(Name(0), BuiltinType::Int);

        assert_eq!(1, fct.increase_var(var_id));
    }

    #[test]
    #[should_panic]
    fn add_phi_panics() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(0));
        block.add_phi(phi(0));
    }

    #[test]
    fn add_phi() {
        let mut block = Block::new(BlockId(0));

        block.add_instr(Instr::ret());
        block.add_phi(phi(0));
        block.add_phi(phi(1));
        block.add_phi(phi(2));

        let instrs = &block.instructions;

        assert_eq!(phi_instr(0), instrs[0]);
        assert_eq!(phi_instr(1), instrs[1]);
        assert_eq!(phi_instr(2), instrs[2]);
        assert_eq!(Instr::ret(), instrs[3]);
    }

    #[test]
    fn phi_iterator_empty() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.phi_iter().next());
    }

    #[test]
    fn phi_iterator_single() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(3));
        block.add_instr(Instr::ret());

        let mut iter = block.phi_iter();
        assert_eq!(Some(&phi(3)), iter.next());
        assert_eq!(None, iter.next());
    }

    fn phi_instr(var: usize) -> Instr {
        InstrPhi(phi(var))
    }

    fn phi(var: usize) -> InstrPhiType {
        InstrPhiType {
            var_id: VarId(var),
            dest: 0,
            opnds: Vec::new(),
            backup: 0
        }
    }
}
<|endoftext|>


<commit_before>
use token::{Token, TokenKind};
use error::{NcclError, ErrorKind};

use std::error::Error;

// ranked worst to best
enum Indent {
    Neither,
    Tabs,
    Spaces(u8),
}

pub struct Scanner {
    source: Vec<u8>,
    tokens: Vec<Token>,
    start: usize,
    current: usize,
    line: u64,
    indent: Indent,
}

impl Scanner {
    pub fn new(source: String) -> Self {
        Scanner {
            source: source.into_bytes(),
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
            indent: Indent::Neither,
        }
    }

    pub fn scan_tokens(&mut self) -> Result<Vec<Token>, Vec<Box<Error>>> {
        let mut err: Vec<Box<Error>> = vec![];

        while !self.is_at_end() {
            self.start = self.current;
            let e = self.scan_token();
            if e.is_err() {
                err.push(Box::new(e.err().unwrap()));
            }
        }

        self.tokens.push(Token::new(TokenKind::EOF, "".into(), self.line));

        if !err.is_empty() {
            Err(err)
        } else {
            Ok(self.tokens.clone())
        }
    }

    fn scan_token(&mut self) -> Result<(), NcclError> {
        let mut error = Ok(());
        match self.advance() {
            b'#' => {
                while self.peek() != b'\n' && !self.is_at_end() {
                    self.advance();
                }
            },

            b' ' => {
                match self.indent {
                    Indent::Neither => {
                        let mut spaces = 0;
                        while self.peek() == b' ' && !self.is_at_end() {
                            self.advance();
                            spaces += 1;
                        }
                        if self.is_at_end() {
                            error = Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line));
                        }
                        self.indent = Indent::Spaces(spaces);
                        self.add_token(TokenKind::Indent);
                    }
                    Indent::Spaces(s) => {
                        let mut spaces = 0;
                        while spaces < s  && !self.is_at_end() {
                            if self.peek() != b' ' {
                                error = Err(NcclError::new(ErrorKind::IndentationError, &format!("Incorrect number of spaces: found {}, expected {}", spaces, s), self.line));
                            }
                            self.advance();
                            spaces += 1;
                        }
                        if self.is_at_end() {
                            error = Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line));
                        }
                        self.add_token(TokenKind::Indent);
                    },
                    Indent::Tabs => { error = Err(NcclError::new(ErrorKind::IndentationError, "Expected tabs, found spaces", self.line)); }
                }
            },

            b'\t' => {
                match self.indent {
                    Indent::Neither => {
                        self.add_token(TokenKind::Indent);
                        self.indent = Indent::Tabs;
                    },
                    Indent::Tabs => {
                        self.add_token(TokenKind::Indent);
                    },
                    Indent::Spaces(_) => { error = Err(NcclError::new(ErrorKind::IndentationError, "Expected spaces, found tabs", self.line)); }
                }
            },

            b'\n' => {
                self.add_token(TokenKind::Newline);
                self.line += 1;
                if self.peek() != b' ' && self.peek() != b'\t' && self.peek() != b'#' {
                    self.indent = Indent::Neither;
                }
            },

            b'\r' => {},

            b'"' => if let Err(e) = self.string() { error = Err(e); },

            _ => if let Err(e) = self.identifier() { error = Err(e); },
        }

        error
    }

    fn identifier(&mut self) -> Result<(), NcclError> {
        while self.peek() != b'\n' && self.peek() != b'\r' && !self.is_at_end() {
            self.advance();
        }

        let value = String::from_utf8(self.source[self.start..self.current].to_vec()).unwrap();
        self.add_token_string(TokenKind::Value, value);

        Ok(())
    }

    fn string(&mut self) -> Result<(), NcclError> {
        let mut value = String::new();
        while self.peek() != b'"' && !self.is_at_end() {
            if self.peek() == b'\n' {
                self.line += 1;
            }

            if self.peek() == b'\\' {
                self.advance();
                match self.peek() {
                    b'n' => {
                        value.push('\n');
                    },
                    b'r' => {
                        value.push('\r');
                    }
                    b'\\' => {
                        value.push('\\');
                    },
                    b'"' => {
                        value.push('"');
                    },
                    b'\n' => {
                        self.advance();
                        println!("newline");
                        while self.peek() == b' ' || self.peek() == b'\t' {
                            println!("advance");
                            self.advance();
                        }
                        self.reverse();
                    },
                    _ => return Err(NcclError::new(ErrorKind::ParseError, &format!("Unknown format code: {}", self.peek()), self.line))
                }
            } else {
                value.push(self.source[self.current] as char);
            }

            self.advance();
        }

        if self.is_at_end() {
            return Err(NcclError::new(ErrorKind::ParseError, "Unterminated string", self.line));
        }

        self.advance();

        self.add_token_string(TokenKind::Value, value);

        Ok(())
    }

    fn add_token(&mut self, kind: TokenKind) {
        let text = String::from_utf8(self.source[self.start..self.current].to_vec()).unwrap();
        self.tokens.push(Token::new(kind, text, self.line));
    }

    fn add_token_string(&mut self, kind: TokenKind, value: String) {
        self.tokens.push(Token::new(kind, value, self.line));
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn advance(&mut self) -> u8 {
        self.current += 1;
        self.source[self.current - 1]
    }

    fn reverse(&mut self) -> u8 {
        self.current -= 1;
        self.source[self.current]
    }

    fn peek(&mut self) -> u8 {
        if self.current >= self.source.len() {
            b'\0'
        } else {
            self.source[self.current]
        }
    }
}

<commit_msg>remove debug printlns<commit_after>
use token::{Token, TokenKind};
use error::{NcclError, ErrorKind};

use std::error::Error;

// ranked worst to best
enum Indent {
    Neither,
    Tabs,
    Spaces(u8),
}

pub struct Scanner {
    source: Vec<u8>,
    tokens: Vec<Token>,
    start: usize,
    current: usize,
    line: u64,
    indent: Indent,
}

impl Scanner {
    pub fn new(source: String) -> Self {
        Scanner {
            source: source.into_bytes(),
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
            indent: Indent::Neither,
        }
    }

    pub fn scan_tokens(&mut self) -> Result<Vec<Token>, Vec<Box<Error>>> {
        let mut err: Vec<Box<Error>> = vec![];

        while !self.is_at_end() {
            self.start = self.current;
            let e = self.scan_token();
            if e.is_err() {
                err.push(Box::new(e.err().unwrap()));
            }
        }

        self.tokens.push(Token::new(TokenKind::EOF, "".into(), self.line));

        if !err.is_empty() {
            Err(err)
        } else {
            Ok(self.tokens.clone())
        }
    }

    fn scan_token(&mut self) -> Result<(), NcclError> {
        let mut error = Ok(());
        match self.advance() {
            b'#' => {
                while self.peek() != b'\n' && !self.is_at_end() {
                    self.advance();
                }
            },

            b' ' => {
                match self.indent {
                    Indent::Neither => {
                        let mut spaces = 0;
                        while self.peek() == b' ' && !self.is_at_end() {
                            self.advance();
                            spaces += 1;
                        }
                        if self.is_at_end() {
                            error = Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line));
                        }
                        self.indent = Indent::Spaces(spaces);
                        self.add_token(TokenKind::Indent);
                    }
                    Indent::Spaces(s) => {
                        let mut spaces = 0;
                        while spaces < s  && !self.is_at_end() {
                            if self.peek() != b' ' {
                                error = Err(NcclError::new(ErrorKind::IndentationError, &format!("Incorrect number of spaces: found {}, expected {}", spaces, s), self.line));
                            }
                            self.advance();
                            spaces += 1;
                        }
                        if self.is_at_end() {
                            error = Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line));
                        }
                        self.add_token(TokenKind::Indent);
                    },
                    Indent::Tabs => { error = Err(NcclError::new(ErrorKind::IndentationError, "Expected tabs, found spaces", self.line)); }
                }
            },

            b'\t' => {
                match self.indent {
                    Indent::Neither => {
                        self.add_token(TokenKind::Indent);
                        self.indent = Indent::Tabs;
                    },
                    Indent::Tabs => {
                        self.add_token(TokenKind::Indent);
                    },
                    Indent::Spaces(_) => { error = Err(NcclError::new(ErrorKind::IndentationError, "Expected spaces, found tabs", self.line)); }
                }
            },

            b'\n' => {
                self.add_token(TokenKind::Newline);
                self.line += 1;
                if self.peek() != b' ' && self.peek() != b'\t' && self.peek() != b'#' {
                    self.indent = Indent::Neither;
                }
            },

            b'\r' => {},

            b'"' => if let Err(e) = self.string() { error = Err(e); },

            _ => if let Err(e) = self.identifier() { error = Err(e); },
        }

        error
    }

    fn identifier(&mut self) -> Result<(), NcclError> {
        while self.peek() != b'\n' && self.peek() != b'\r' && !self.is_at_end() {
            self.advance();
        }

        let value = String::from_utf8(self.source[self.start..self.current].to_vec()).unwrap();
        self.add_token_string(TokenKind::Value, value);

        Ok(())
    }

    fn string(&mut self) -> Result<(), NcclError> {
        let mut value = String::new();
        while self.peek() != b'"' && !self.is_at_end() {
            if self.peek() == b'\n' {
                self.line += 1;
            }

            if self.peek() == b'\\' {
                self.advance();
                match self.peek() {
                    b'n' => {
                        value.push('\n');
                    },
                    b'r' => {
                        value.push('\r');
                    }
                    b'\\' => {
                        value.push('\\');
                    },
                    b'"' => {
                        value.push('"');
                    },
                    b'\n' => {
                        self.advance();
                        while self.peek() == b' ' || self.peek() == b'\t' {
                            self.advance();
                        }
                        self.reverse();
                    },
                    _ => return Err(NcclError::new(ErrorKind::ParseError, &format!("Unknown format code: {}", self.peek()), self.line))
                }
            } else {
                value.push(self.source[self.current] as char);
            }

            self.advance();
        }

        if self.is_at_end() {
            return Err(NcclError::new(ErrorKind::ParseError, "Unterminated string", self.line));
        }

        self.advance();

        self.add_token_string(TokenKind::Value, value);

        Ok(())
    }

    fn add_token(&mut self, kind: TokenKind) {
        let text = String::from_utf8(self.source[self.start..self.current].to_vec()).unwrap();
        self.tokens.push(Token::new(kind, text, self.line));
    }

    fn add_token_string(&mut self, kind: TokenKind, value: String) {
        self.tokens.push(Token::new(kind, value, self.line));
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn advance(&mut self) -> u8 {
        self.current += 1;
        self.source[self.current - 1]
    }

    fn reverse(&mut self) -> u8 {
        self.current -= 1;
        self.source[self.current]
    }

    fn peek(&mut self) -> u8 {
        if self.current >= self.source.len() {
            b'\0'
        } else {
            self.source[self.current]
        }
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 Walter Kuppens.
//
// 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 nes::instruction::Instruction;
use nes::memory::Memory;
use std::fmt;

// Flag constants that allow easy bitwise getting and setting of flag values.
pub const CARRY_FLAG       : u8 = 0x1;
pub const ZERO_FLAG        : u8 = 0x2;
pub const INTERRUPT_DISABLE: u8 = 0x4;
pub const DECIMAL_MODE     : u8 = 0x8;
pub const BREAK_COMMAND    : u8 = 0x10;
pub const OVERFLOW_FLAG    : u8 = 0x40;
pub const NEGATIVE_FLAG    : u8 = 0x80;

/// This is an implementation of 2A03 processor used in the NES. The 2A03 is
/// based off the 6502 processor with some minor changes such as having no
/// binary-coded decimal mode. Currently only the NTSC variant of the chip is
/// planned to be implemented.
///
/// Much of the information and comments are due credit to www.obelisk.me.uk,
/// which has really good information about the 6502 processor. If you're
/// interested in diving further, I recommend you give that site a visit.
#[derive(Debug)]
pub struct CPU {
    // The program counter is a 16-bit register which points to the next
    // instruction to be executed. The value of program counter is modified
    // automatically as instructions are executed.
    //
    // The value of the program counter can be modified by executing a jump, a
    // relative branch, a subroutine call to another memory address, by
    // returning from a subroutine, or by an interrupt.
    pub pc: u16,

    // The processor supports a 256 byte stack located between $0100 and $01FF.
    // The stack pointer is an 8-bit register and holds the next free location
    // on the stack. The location of the stack is fixed and cannot be moved and
    // grows downwards.
    pub sp: u8,

    // The 8-bit accumulator is used all arithmetic and logical operations (with
    // the exception of increments and decrements). The contents of the
    // accumulator can be stored and retrieved either from memory or the stack.
    pub a: u8,

    // The 8-bit X register can be used to control information, compare values
    // in memory, and be incremented or decremented. The X register is special
    // as it can be used to get a copy of the stack pointer or change its value.
    pub x: u8,

    // The 8-bit Y register like X, can be used to manage information and be
    // incremented or decremented; however it doesn't have any special functions
    // like the X register does.
    pub y: u8,

    // The Processor Status register contains a list of flags that are set and
    // cleared by instructions to record the results of operations. Each flag
    // has a special bit within the register (8 bits).  Instructions exist to
    // set, clear, and read the various flags. One even allows pushing or
    // pulling the flags to the stack.
    //
    // Carry Flag:
    //
    // The carry flag is set if the last operation caused an overflow from bit 7
    // of the result or an underflow from bit 0. This condition is set during
    // arithmetic, comparison and during logical shifts. It can be explicitly
    // set using the 'Set Carry Flag' (SEC) instruction and cleared with 'Clear
    // Carry Flag' (CLC).
    //
    // Zero Flag:
    //
    // The zero flag is set if the result of the last operation as was zero.
    //
    // Interrupt Disable:
    //
    // The interrupt disable flag is set if the program has executed a 'Set
    // Interrupt Disable' (SEI) instruction. While this flag is set the
    // processor will not respond to interrupts from devices until it is cleared
    // by a 'Clear Interrupt Disable' (CLI) instruction.
    //
    // Decimal Mode: (UNUSED in 2A03)
    //
    // While the decimal mode flag is set the processor will obey the rules of
    // Binary Coded Decimal (BCD) arithmetic during addition and subtraction.
    // The flag can be explicitly set using 'Set Decimal Flag' (SED) and cleared
    // with 'Clear Decimal Flag' (CLD).
    //
    // Break Command:
    //
    // The break command bit is set when a BRK instruction has been executed and
    // an interrupt has been generated to process it.
    //
    // Overflow Flag:
    //
    // The overflow flag is set during arithmetic operations if the result has
    // yielded an invalid 2's complement result (e.g. adding to positive numbers
    // and ending up with a negative result: 64 + 64 => -128). It is determined
    // by looking at the carry between bits 6 and 7 and between bit 7 and the
    // carry flag.
    //
    // Negative Flag:
    //
    // The negative flag is set if the result of the last operation had bit 7
    // set to a one.
    pub p: u8,

    // The amount of cycles currently accumulated. A cycle represents a unit of
    // time (the time it takes for the CPU clock to fire). Different
    // instructions take a different amount of cycles to complete depending on
    // their complexity.
    pub cycles: u16
}

impl CPU {
    pub fn new() -> CPU {
        CPU {
            pc: 0xC000,
            sp: 0xFD,
            a: 0,
            x: 0,
            y: 0,
            p: 0x24,
            cycles: 0
        }
    }

    /// Sets the carry flag in the status register.
    #[inline(always)]
    pub fn set_carry_flag(&mut self) {
        self.p |= CARRY_FLAG;
    }

    /// Sets the zero flag in the status register.
    #[inline(always)]
    pub fn set_zero_flag(&mut self) {
        self.p |= ZERO_FLAG;
    }

    /// Sets the interrupt disable flag in the status register.
    #[inline(always)]
    pub fn set_interrupt_disable(&mut self) {
        self.p |= INTERRUPT_DISABLE;
    }

    /// Sets the decimal mode flag in the status register.
    /// NOTE: This flag is disabled in the 2A03 variation of the 6502.
    #[inline(always)]
    pub fn set_decimal_mode(&mut self) {
        self.p |= DECIMAL_MODE;
    }

    /// Sets the break command flag in the status register.
    #[inline(always)]
    pub fn set_break_command(&mut self) {
        self.p |= BREAK_COMMAND;
    }

    /// Sets the overflow flag in the status register.
    #[inline(always)]
    pub fn set_overflow_flag(&mut self) {
        self.p |= OVERFLOW_FLAG;
    }

    /// Sets the negative flag in the status register.
    #[inline(always)]
    pub fn set_negative_flag(&mut self) {
        self.p |= NEGATIVE_FLAG;
    }

    /// Unsets the carry flag in the status register.
    #[inline(always)]
    pub fn unset_carry_flag(&mut self) {
        self.p &= ~CARRY_FLAG;
    }

    /// Unsets the zero flag in the status register.
    #[inline(always)]
    pub fn unset_zero_flag(&mut self) {
        self.p &= ~ZERO_FLAG;
    }

    /// Unsets the interrupt disable flag in the status register.
    #[inline(always)]
    pub fn unset_interrupt_disable(&mut self) {
        self.p &= ~INTERRUPT_DISABLE;
    }

    /// Unsets the decimal mode flag in the status register.
    /// NOTE: This flag is disabled in the 2A03 variation of the 6502.
    #[inline(always)]
    pub fn unset_decimal_mode(&mut self) {
        self.p &= ~DECIMAL_MODE;
    }

    /// Unsets the break command flag in the status register.
    #[inline(always)]
    pub fn unset_break_command(&mut self) {
        self.p &= ~BREAK_COMMAND;
    }

    /// Unsets the overflow flag in the status register.
    #[inline(always)]
    pub fn unset_overflow_flag(&mut self) {
        self.p &= ~OVERFLOW_FLAG;
    }

    /// Unsets the negative flag in the status register.
    #[inline(always)]
    pub fn unset_negative_flag(&mut self) {
        self.p &= ~NEGATIVE_FLAG;
    }

    /// Sets the carry flag in the status register.
    #[inline(always)]
    pub fn carry_flag_set(&self) -> bool {
        self.p & CARRY_FLAG == CARRY_FLAG
    }

    /// Sets the zero flag in the status register.
    #[inline(always)]
    pub fn zero_flag_set(&self) -> bool {
        self.p & ZERO_FLAG == ZERO_FLAG
    }

    /// Sets the interrupt disable flag in the status register.
    #[inline(always)]
    pub fn interrupt_disable_set(&self) -> bool {
        self.p & INTERRUPT_DISABLE == INTERRUPT_DISABLE
    }

    /// Sets the decimal mode flag in the status register.
    /// NOTE: This flag is disabled in the 2A03 variation of the 6502.
    #[inline(always)]
    pub fn decimal_mode_set(&self) -> bool {
        self.p & DECIMAL_MODE == DECIMAL_MODE
    }

    /// Sets the break command flag in the status register.
    #[inline(always)]
    pub fn break_command_set(&self) -> bool {
        self.p & BREAK_COMMAND == BREAK_COMMAND
    }

    /// Sets the overflow flag in the status register.
    #[inline(always)]
    pub fn overflow_flag_set(&self) -> bool {
        self.p & OVERFLOW_FLAG == OVERFLOW_FLAG
    }

    /// Sets the negative flag in the status register.
    #[inline(always)]
    pub fn negative_flag_set(&self) -> bool {
        self.p & NEGATIVE_FLAG == NEGATIVE_FLAG
    }

    /// Parse an instruction from memory at the address the program counter
    /// currently points execute it. All instruction logic is in instruction.rs.
    pub fn execute(&mut self, memory: &mut Memory) {
        // NOTE: At this time, some parsing logic is done twice for the sake of
        // code simplicity. In the future I may rework the function arguments to
        // reuse as much data as possible since this is high-performance code.
        let instr = Instruction::parse(self.pc as usize, memory);
        instr.log(self);
        instr.execute(self, memory);
    }

    fn fmt_flag(&self, flag: bool) -> &'static str {
        if flag { "SET" } else { "UNSET" }
    }
}

impl fmt::Display for CPU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "\nCPU Crash State:").unwrap();
        writeln!(f, "    Program Counter: {:#X}", self.pc).unwrap();
        writeln!(f, "    Stack Pointer:   {:#X}", self.sp).unwrap();
        writeln!(f, "    Accumulator:     {:#X}", self.a).unwrap();
        writeln!(f, "    X Register:      {:#X}", self.x).unwrap();
        writeln!(f, "    Y Register:      {:#X}", self.y).unwrap();
        writeln!(f, "").unwrap();
        writeln!(f, "Status Register: {:#X}", self.p).unwrap();
        writeln!(f, "    Carry Flag:        {}", self.fmt_flag(self.carry_flag_set())).unwrap();
        writeln!(f, "    Zero Flag:         {}", self.fmt_flag(self.zero_flag_set())).unwrap();
        writeln!(f, "    Interrupt Disable: {}", self.fmt_flag(self.interrupt_disable_set())).unwrap();
        writeln!(f, "    Decimal Mode:      {}", self.fmt_flag(self.decimal_mode_set())).unwrap();
        writeln!(f, "    Break Command:     {}", self.fmt_flag(self.break_command_set())).unwrap();
        writeln!(f, "    Overflow Flag:     {}", self.fmt_flag(self.overflow_flag_set())).unwrap();
        writeln!(f, "    Negative Flag:     {}", self.fmt_flag(self.negative_flag_set()))
    }
}
<commit_msg>Whoops, Rust uses different bitwise syntax than C<commit_after>// Copyright 2016 Walter Kuppens.
//
// 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 nes::instruction::Instruction;
use nes::memory::Memory;
use std::fmt;

// Flag constants that allow easy bitwise getting and setting of flag values.
pub const CARRY_FLAG       : u8 = 0x1;
pub const ZERO_FLAG        : u8 = 0x2;
pub const INTERRUPT_DISABLE: u8 = 0x4;
pub const DECIMAL_MODE     : u8 = 0x8;
pub const BREAK_COMMAND    : u8 = 0x10;
pub const OVERFLOW_FLAG    : u8 = 0x40;
pub const NEGATIVE_FLAG    : u8 = 0x80;

/// This is an implementation of 2A03 processor used in the NES. The 2A03 is
/// based off the 6502 processor with some minor changes such as having no
/// binary-coded decimal mode. Currently only the NTSC variant of the chip is
/// planned to be implemented.
///
/// Much of the information and comments are due credit to www.obelisk.me.uk,
/// which has really good information about the 6502 processor. If you're
/// interested in diving further, I recommend you give that site a visit.
#[derive(Debug)]
pub struct CPU {
    // The program counter is a 16-bit register which points to the next
    // instruction to be executed. The value of program counter is modified
    // automatically as instructions are executed.
    //
    // The value of the program counter can be modified by executing a jump, a
    // relative branch, a subroutine call to another memory address, by
    // returning from a subroutine, or by an interrupt.
    pub pc: u16,

    // The processor supports a 256 byte stack located between $0100 and $01FF.
    // The stack pointer is an 8-bit register and holds the next free location
    // on the stack. The location of the stack is fixed and cannot be moved and
    // grows downwards.
    pub sp: u8,

    // The 8-bit accumulator is used all arithmetic and logical operations (with
    // the exception of increments and decrements). The contents of the
    // accumulator can be stored and retrieved either from memory or the stack.
    pub a: u8,

    // The 8-bit X register can be used to control information, compare values
    // in memory, and be incremented or decremented. The X register is special
    // as it can be used to get a copy of the stack pointer or change its value.
    pub x: u8,

    // The 8-bit Y register like X, can be used to manage information and be
    // incremented or decremented; however it doesn't have any special functions
    // like the X register does.
    pub y: u8,

    // The Processor Status register contains a list of flags that are set and
    // cleared by instructions to record the results of operations. Each flag
    // has a special bit within the register (8 bits).  Instructions exist to
    // set, clear, and read the various flags. One even allows pushing or
    // pulling the flags to the stack.
    //
    // Carry Flag:
    //
    // The carry flag is set if the last operation caused an overflow from bit 7
    // of the result or an underflow from bit 0. This condition is set during
    // arithmetic, comparison and during logical shifts. It can be explicitly
    // set using the 'Set Carry Flag' (SEC) instruction and cleared with 'Clear
    // Carry Flag' (CLC).
    //
    // Zero Flag:
    //
    // The zero flag is set if the result of the last operation as was zero.
    //
    // Interrupt Disable:
    //
    // The interrupt disable flag is set if the program has executed a 'Set
    // Interrupt Disable' (SEI) instruction. While this flag is set the
    // processor will not respond to interrupts from devices until it is cleared
    // by a 'Clear Interrupt Disable' (CLI) instruction.
    //
    // Decimal Mode: (UNUSED in 2A03)
    //
    // While the decimal mode flag is set the processor will obey the rules of
    // Binary Coded Decimal (BCD) arithmetic during addition and subtraction.
    // The flag can be explicitly set using 'Set Decimal Flag' (SED) and cleared
    // with 'Clear Decimal Flag' (CLD).
    //
    // Break Command:
    //
    // The break command bit is set when a BRK instruction has been executed and
    // an interrupt has been generated to process it.
    //
    // Overflow Flag:
    //
    // The overflow flag is set during arithmetic operations if the result has
    // yielded an invalid 2's complement result (e.g. adding to positive numbers
    // and ending up with a negative result: 64 + 64 => -128). It is determined
    // by looking at the carry between bits 6 and 7 and between bit 7 and the
    // carry flag.
    //
    // Negative Flag:
    //
    // The negative flag is set if the result of the last operation had bit 7
    // set to a one.
    pub p: u8,

    // The amount of cycles currently accumulated. A cycle represents a unit of
    // time (the time it takes for the CPU clock to fire). Different
    // instructions take a different amount of cycles to complete depending on
    // their complexity.
    pub cycles: u16
}

impl CPU {
    pub fn new() -> CPU {
        CPU {
            pc: 0xC000,
            sp: 0xFD,
            a: 0,
            x: 0,
            y: 0,
            p: 0x24,
            cycles: 0
        }
    }

    /// Sets the carry flag in the status register.
    #[inline(always)]
    pub fn set_carry_flag(&mut self) {
        self.p |= CARRY_FLAG;
    }

    /// Sets the zero flag in the status register.
    #[inline(always)]
    pub fn set_zero_flag(&mut self) {
        self.p |= ZERO_FLAG;
    }

    /// Sets the interrupt disable flag in the status register.
    #[inline(always)]
    pub fn set_interrupt_disable(&mut self) {
        self.p |= INTERRUPT_DISABLE;
    }

    /// Sets the decimal mode flag in the status register.
    /// NOTE: This flag is disabled in the 2A03 variation of the 6502.
    #[inline(always)]
    pub fn set_decimal_mode(&mut self) {
        self.p |= DECIMAL_MODE;
    }

    /// Sets the break command flag in the status register.
    #[inline(always)]
    pub fn set_break_command(&mut self) {
        self.p |= BREAK_COMMAND;
    }

    /// Sets the overflow flag in the status register.
    #[inline(always)]
    pub fn set_overflow_flag(&mut self) {
        self.p |= OVERFLOW_FLAG;
    }

    /// Sets the negative flag in the status register.
    #[inline(always)]
    pub fn set_negative_flag(&mut self) {
        self.p |= NEGATIVE_FLAG;
    }

    /// Unsets the carry flag in the status register.
    #[inline(always)]
    pub fn unset_carry_flag(&mut self) {
        self.p &= !CARRY_FLAG;
    }

    /// Unsets the zero flag in the status register.
    #[inline(always)]
    pub fn unset_zero_flag(&mut self) {
        self.p &= !ZERO_FLAG;
    }

    /// Unsets the interrupt disable flag in the status register.
    #[inline(always)]
    pub fn unset_interrupt_disable(&mut self) {
        self.p &= !INTERRUPT_DISABLE;
    }

    /// Unsets the decimal mode flag in the status register.
    /// NOTE: This flag is disabled in the 2A03 variation of the 6502.
    #[inline(always)]
    pub fn unset_decimal_mode(&mut self) {
        self.p &= !DECIMAL_MODE;
    }

    /// Unsets the break command flag in the status register.
    #[inline(always)]
    pub fn unset_break_command(&mut self) {
        self.p &= !BREAK_COMMAND;
    }

    /// Unsets the overflow flag in the status register.
    #[inline(always)]
    pub fn unset_overflow_flag(&mut self) {
        self.p &= !OVERFLOW_FLAG;
    }

    /// Unsets the negative flag in the status register.
    #[inline(always)]
    pub fn unset_negative_flag(&mut self) {
        self.p &= !NEGATIVE_FLAG;
    }

    /// Sets the carry flag in the status register.
    #[inline(always)]
    pub fn carry_flag_set(&self) -> bool {
        self.p & CARRY_FLAG == CARRY_FLAG
    }

    /// Sets the zero flag in the status register.
    #[inline(always)]
    pub fn zero_flag_set(&self) -> bool {
        self.p & ZERO_FLAG == ZERO_FLAG
    }

    /// Sets the interrupt disable flag in the status register.
    #[inline(always)]
    pub fn interrupt_disable_set(&self) -> bool {
        self.p & INTERRUPT_DISABLE == INTERRUPT_DISABLE
    }

    /// Sets the decimal mode flag in the status register.
    /// NOTE: This flag is disabled in the 2A03 variation of the 6502.
    #[inline(always)]
    pub fn decimal_mode_set(&self) -> bool {
        self.p & DECIMAL_MODE == DECIMAL_MODE
    }

    /// Sets the break command flag in the status register.
    #[inline(always)]
    pub fn break_command_set(&self) -> bool {
        self.p & BREAK_COMMAND == BREAK_COMMAND
    }

    /// Sets the overflow flag in the status register.
    #[inline(always)]
    pub fn overflow_flag_set(&self) -> bool {
        self.p & OVERFLOW_FLAG == OVERFLOW_FLAG
    }

    /// Sets the negative flag in the status register.
    #[inline(always)]
    pub fn negative_flag_set(&self) -> bool {
        self.p & NEGATIVE_FLAG == NEGATIVE_FLAG
    }

    /// Parse an instruction from memory at the address the program counter
    /// currently points execute it. All instruction logic is in instruction.rs.
    pub fn execute(&mut self, memory: &mut Memory) {
        // NOTE: At this time, some parsing logic is done twice for the sake of
        // code simplicity. In the future I may rework the function arguments to
        // reuse as much data as possible since this is high-performance code.
        let instr = Instruction::parse(self.pc as usize, memory);
        instr.log(self);
        instr.execute(self, memory);
    }

    fn fmt_flag(&self, flag: bool) -> &'static str {
        if flag { "SET" } else { "UNSET" }
    }
}

impl fmt::Display for CPU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "\nCPU Crash State:").unwrap();
        writeln!(f, "    Program Counter: {:#X}", self.pc).unwrap();
        writeln!(f, "    Stack Pointer:   {:#X}", self.sp).unwrap();
        writeln!(f, "    Accumulator:     {:#X}", self.a).unwrap();
        writeln!(f, "    X Register:      {:#X}", self.x).unwrap();
        writeln!(f, "    Y Register:      {:#X}", self.y).unwrap();
        writeln!(f, "").unwrap();
        writeln!(f, "Status Register: {:#X}", self.p).unwrap();
        writeln!(f, "    Carry Flag:        {}", self.fmt_flag(self.carry_flag_set())).unwrap();
        writeln!(f, "    Zero Flag:         {}", self.fmt_flag(self.zero_flag_set())).unwrap();
        writeln!(f, "    Interrupt Disable: {}", self.fmt_flag(self.interrupt_disable_set())).unwrap();
        writeln!(f, "    Decimal Mode:      {}", self.fmt_flag(self.decimal_mode_set())).unwrap();
        writeln!(f, "    Break Command:     {}", self.fmt_flag(self.break_command_set())).unwrap();
        writeln!(f, "    Overflow Flag:     {}", self.fmt_flag(self.overflow_flag_set())).unwrap();
        writeln!(f, "    Negative Flag:     {}", self.fmt_flag(self.negative_flag_set()))
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use futures::{finished, Future};
use hyper::{self, Get as GetMethod, Post as PostMethod};
use hyper::server::{Service, Request, Response};
use route_recognizer::{Router as Recognizer};
use errors::*;
use super::{HttpFuture, Get, Post, Route};

type HttpRouter<T> = Recognizer<Box<T>>;

/// A `hyper` service that routes requests to child handlers.
///
/// This structure is relatively cheap to clone; it only needs to
/// increment a single [`Arc`]() pointer.
#[derive(Clone)]
pub struct Router {
    routers: Arc<Box<Routers>>,
}

struct Routers {
    get_router: HttpRouter<Get>,
    post_router: HttpRouter<Post>,
}

pub struct RouterBuilder {
    get_router: HttpRouter<Get>,
    post_router: HttpRouter<Post>,
}

impl RouterBuilder {
    /// Create a new router builder.
    pub fn new() -> Self {
        RouterBuilder {
            get_router: HttpRouter::new(),
            post_router: HttpRouter::new(),
        }
    }

    /// Add a new handler for a `GET` request.
    pub fn get<H>(mut self, handler: H) -> Self
        where H: Get + Route + 'static
    {
        self.get_router.add(H::ROUTE, Box::new(handler));

        self
    }

    /// Add a new handler for a `POST` request.
    pub fn post<H>(mut self, handler: H) -> Self
        where H: Post + Route + 'static
    {
        self.post_router.add(H::ROUTE, Box::new(handler));

        self
    }

    /// Build a `Router`.
    ///
    /// This function consumes the builder and returns a new
    /// immutable router with the given handlers.
    pub fn build(self) -> Router {
        Router {
            routers: Arc::new(Box::new(Routers {
                get_router: self.get_router,
                post_router: self.post_router,
            })),
        }
    }
}

impl Service for Router {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = HttpFuture;

    fn call(&self, req: Request) -> Self::Future {
        match *req.method() {
            GetMethod => self.get(req),
            PostMethod => self.post(req),
            _ => box finished(ErrorKind::MethodNotSupported.into()),
        }
    }
}

impl Router {
    fn get(&self, req: Request) -> <Self as Service>::Future {
        req.path()
            .ok_or({
                Error::from(ErrorKind::NoRouteSpecified)
            })
            .and_then(|path| {
                self.routers.get_router
                    .recognize(path)
                    .map_err(|_| ErrorKind::NoRouteMatch(path.to_owned()).into())
            })
            .map(|route| {
                let handler = route.handler;
                let params = route.params;

                handler.call(&params, req)
            })
            .unwrap_or_else(|e| {
                box finished(Response::from(e))
            })
    }

    fn post(&self, req: Request) -> <Self as Service>::Future {
        req.path()
            .ok_or({
                Error::from(ErrorKind::NoRouteSpecified)
            })
            .and_then(|path| {
                self.routers.post_router
                    .recognize(path)
                    .map_err(|_| ErrorKind::NoRouteMatch(path.to_owned()).into())
            })
            .map(|route| {
                let handler = route.handler;
                let params = route.params;

                handler.call(&params, req)
            })
            .unwrap_or_else(|e| {
                box finished(Response::from(e))
            })
    }
}

/// A conversion trait for handler futures.
///
/// This is a convenience trait for taking any future with a `Response`
/// or application `Error` and converting it into a future of a `Response`
/// or `hyper::Error`.
/// A failed future is converted into a successful one, but with an appropriate
/// HTTP status code derived from the error.
///
/// This particular trait is quite effective because it allows a wide range of
/// input values, and Rust's type inference will hide the details away for us.
/// It also helps avoid boxing response futures multiple times.
///
/// You can read the implementors section as _implement `IntoHttpFuture` for all
/// types `F`, where `F` is a `Future`, and `F`'s `Item` type can be converted into
/// a `Response`, and `F`'s `Error` type can be converted into an `Error`_.
pub trait IntoHttpFuture {
    fn into_http_future(self) -> HttpFuture;
}

impl<F> IntoHttpFuture for F
    where F: Future + 'static,
          F::Item: Into<Response>,
          F::Error: Into<Error>
{
    fn into_http_future(self) -> HttpFuture {
        box self.then(|response| {
            finished(match response {
                Ok(response) => response.into(),
                Err(e) => e.into().into(),
            })
        })
    }
}
<commit_msg>use the same combinator<commit_after>use std::sync::Arc;
use futures::{finished, Future};
use hyper::{self, Get as GetMethod, Post as PostMethod};
use hyper::server::{Service, Request, Response};
use route_recognizer::{Router as Recognizer};
use errors::*;
use super::{HttpFuture, Get, Post, Route};

type HttpRouter<T> = Recognizer<Box<T>>;

/// A `hyper` service that routes requests to child handlers.
///
/// This structure is relatively cheap to clone; it only needs to
/// increment a single [`Arc`]() pointer.
#[derive(Clone)]
pub struct Router {
    routers: Arc<Box<Routers>>,
}

struct Routers {
    get_router: HttpRouter<Get>,
    post_router: HttpRouter<Post>,
}

pub struct RouterBuilder {
    get_router: HttpRouter<Get>,
    post_router: HttpRouter<Post>,
}

impl RouterBuilder {
    /// Create a new router builder.
    pub fn new() -> Self {
        RouterBuilder {
            get_router: HttpRouter::new(),
            post_router: HttpRouter::new(),
        }
    }

    /// Add a new handler for a `GET` request.
    pub fn get<H>(mut self, handler: H) -> Self
        where H: Get + Route + 'static
    {
        self.get_router.add(H::ROUTE, Box::new(handler));

        self
    }

    /// Add a new handler for a `POST` request.
    pub fn post<H>(mut self, handler: H) -> Self
        where H: Post + Route + 'static
    {
        self.post_router.add(H::ROUTE, Box::new(handler));

        self
    }

    /// Build a `Router`.
    ///
    /// This function consumes the builder and returns a new
    /// immutable router with the given handlers.
    pub fn build(self) -> Router {
        Router {
            routers: Arc::new(Box::new(Routers {
                get_router: self.get_router,
                post_router: self.post_router,
            })),
        }
    }
}

impl Service for Router {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = HttpFuture;

    fn call(&self, req: Request) -> Self::Future {
        match *req.method() {
            GetMethod => self.get(req),
            PostMethod => self.post(req),
            _ => box finished(ErrorKind::MethodNotSupported.into()),
        }
    }
}

impl Router {
    fn get(&self, req: Request) -> <Self as Service>::Future {
        req.path()
            .ok_or({
                Error::from(ErrorKind::NoRouteSpecified)
            })
            .and_then(|path| {
                self.routers.get_router
                    .recognize(path)
                    .map_err(|_| ErrorKind::NoRouteMatch(path.to_owned()).into())
            })
            .and_then(|route| {
                let handler = route.handler;
                let params = route.params;

                Ok(handler.call(&params, req))
            })
            .unwrap_or_else(|e| {
                box finished(Response::from(e))
            })
    }

    fn post(&self, req: Request) -> <Self as Service>::Future {
        req.path()
            .ok_or({
                Error::from(ErrorKind::NoRouteSpecified)
            })
            .and_then(|path| {
                self.routers.post_router
                    .recognize(path)
                    .map_err(|_| ErrorKind::NoRouteMatch(path.to_owned()).into())
            })
            .and_then(|route| {
                let handler = route.handler;
                let params = route.params;

                Ok(handler.call(&params, req))
            })
            .unwrap_or_else(|e| {
                box finished(Response::from(e))
            })
    }
}

/// A conversion trait for handler futures.
///
/// This is a convenience trait for taking any future with a `Response`
/// or application `Error` and converting it into a future of a `Response`
/// or `hyper::Error`.
/// A failed future is converted into a successful one, but with an appropriate
/// HTTP status code derived from the error.
///
/// This particular trait is quite effective because it allows a wide range of
/// input values, and Rust's type inference will hide the details away for us.
/// It also helps avoid boxing response futures multiple times.
///
/// You can read the implementors section as _implement `IntoHttpFuture` for all
/// types `F`, where `F` is a `Future`, and `F`'s `Item` type can be converted into
/// a `Response`, and `F`'s `Error` type can be converted into an `Error`_.
pub trait IntoHttpFuture {
    fn into_http_future(self) -> HttpFuture;
}

impl<F> IntoHttpFuture for F
    where F: Future + 'static,
          F::Item: Into<Response>,
          F::Error: Into<Error>
{
    fn into_http_future(self) -> HttpFuture {
        box self.then(|response| {
            finished(match response {
                Ok(response) => response.into(),
                Err(e) => e.into().into(),
            })
        })
    }
}
<|endoftext|>


<commit_before>extern crate url;

use std::path::Path;
use std::env;
use self::url::Url;
use page::Page;

use util;

fn build_github_like_url(host: &str, user: &str, repo: &str, branch: &Option<String>, page: &Page) -> String {
    match page {
        &Page::Open => if let &Some(ref b) = branch {
            format!("https://{}/{}/{}/tree/{}", host, user, repo, b)
        } else {
            format!("https://{}/{}/{}", host, user, repo)
        },
        &Page::Diff {ref lhs, ref rhs} => format!("https://{}/{}/{}/compare/{}...{}", host, user, repo, lhs, rhs),
        &Page::Commit {ref hash} => format!("https://{}/{}/{}/commit/{}", host, user, repo, hash),
        &Page::FileOrDir {ref relative_path, ref hash, line: None} => format!("https://{}/{}/{}/blob/{}/{}", host, user, repo, hash, relative_path),
        &Page::FileOrDir {ref relative_path, ref hash, line: Some(line)} => format!("https://{}/{}/{}/blob/{}/{}#L{}", host, user, repo, hash, relative_path, line),
    }
}

fn build_custom_github_like_url(host: &str, user: &str, repo: &str, branch: &Option<String>, page: &Page, ssh_port_env: &str) -> String {
    if let Ok(v) = env::var(ssh_port_env) {
        if !v.is_empty() {
            return build_github_like_url(&format!("{}:{}", host, v).as_str(), user, repo, branch, page)
        }
    }
    build_github_like_url(host, user, repo, branch, page)
}

fn build_bitbucket_url(user: &str, repo: &str, branch: &Option<String>, page: &Page) -> util::Result<String> {
    match page {
        &Page::Open => if let &Some(ref b) = branch {
            Ok(format!("https://bitbucket.org/{}/{}/branch/{}", user, repo, b))
        } else {
            Ok(format!("https://bitbucket.org/{}/{}", user, repo))
        },
        &Page::Diff {..} => Err("BitBucket does not support diff between commits (see https://bitbucket.org/site/master/issues/4779/ability-to-diff-between-any-two-commits)".to_string()),
        &Page::Commit {ref hash} => Ok(format!("https://bitbucket.org/{}/{}/commits/{}", user, repo, hash)),
        &Page::FileOrDir {ref relative_path, ref hash, line: None} => Ok(format!("https://bitbucket.org/{}/{}/src/{}/{}", user, repo, hash, relative_path)),
        &Page::FileOrDir {ref relative_path, ref hash, line: Some(line)} => {
            let file = Path::new(relative_path)
                .file_name()
                .ok_or(format!("Cannot get file name from path: {}", relative_path))?
                .to_str()
                .ok_or(format!("Cannot convert path to UTF8 string: {}", relative_path))?;
            Ok(format!("https://bitbucket.org/{}/{}/src/{}/{}#{}-{}", user, repo, hash, relative_path, file, line))
        },
    }
}

// Note: Parse '/user/repo.git' or '/user/repo' or 'user/repo' into 'user' and 'repo'
fn user_and_repo_from_path<'a>(path: &'a str) -> util::Result<(&'a str, &'a str)> {
    let mut split = path.split('/').skip_while(|s| s.is_empty());
    let user = split.next().ok_or(format!("Can't detect user name from path {}", path))?;
    let mut repo = split.next().ok_or(format!("Can't detect repository name from path {}", path))?;
    if repo.ends_with(".git") {
        // Slice '.git' from 'repo.git'
        repo = &repo[0 .. repo.len() - 4];
    }
    Ok((user, repo))
}

// Known URL formats
//  1. https://hosting_service.com/user/repo.git
//  2. git@hosting_service.com:user/repo.git (-> ssh://git@hosting_service.com:22/user/repo.git)
pub fn parse_and_build_page_url(repo: &String, page: &Page, branch: &Option<String>) -> util::Result<String> {
    let url = Url::parse(repo).map_err(|e| format!("Failed to parse URL '{}': {}", repo, e))?;
    let path = url.path();
    let (user, repo_name) = user_and_repo_from_path(path)?;
    let host = url.host_str().ok_or(format!("Failed to parse host from {}", repo))?;
    match host {
        "github.com" | "gitlab.com" => Ok(build_github_like_url(host, user, repo_name, branch, page)),
        "bitbucket.org" => build_bitbucket_url(user, repo_name, branch, page),
        _ => if host.starts_with("github.") {
            Ok(build_custom_github_like_url(host, user, repo_name, branch, page, "GIT_BRWS_GHE_SSH_PORT"))
        } else if host.starts_with("gitlab.") {
            Ok(build_custom_github_like_url(host, user, repo_name, branch, page, "GIT_BRWS_GITLAB_SSH_PORT"))
        } else {
            if let Ok(v) = env::var("GIT_BRWS_GHE_URL_HOST") {
                if v == host {
                    return Ok(build_custom_github_like_url(host, user, repo_name, branch, page, "GIT_BRWS_GHE_SSH_PORT"))
                }
            }
            Err(format!("Unknown hosting service for URL {}. If you want to use custom URL for GitHub Enterprise, please set $GIT_BRWS_GHE_URL_HOST", repo))
        },
    }
}
<commit_msg>use 'slug'<commit_after>extern crate url;

use std::path::Path;
use std::env;
use self::url::Url;
use page::Page;

use util;

fn build_github_like_url(host: &str, user: &str, repo: &str, branch: &Option<String>, page: &Page) -> String {
    match page {
        &Page::Open => if let &Some(ref b) = branch {
            format!("https://{}/{}/{}/tree/{}", host, user, repo, b)
        } else {
            format!("https://{}/{}/{}", host, user, repo)
        },
        &Page::Diff {ref lhs, ref rhs} => format!("https://{}/{}/{}/compare/{}...{}", host, user, repo, lhs, rhs),
        &Page::Commit {ref hash} => format!("https://{}/{}/{}/commit/{}", host, user, repo, hash),
        &Page::FileOrDir {ref relative_path, ref hash, line: None} => format!("https://{}/{}/{}/blob/{}/{}", host, user, repo, hash, relative_path),
        &Page::FileOrDir {ref relative_path, ref hash, line: Some(line)} => format!("https://{}/{}/{}/blob/{}/{}#L{}", host, user, repo, hash, relative_path, line),
    }
}

fn build_custom_github_like_url(host: &str, user: &str, repo: &str, branch: &Option<String>, page: &Page, ssh_port_env: &str) -> String {
    if let Ok(v) = env::var(ssh_port_env) {
        if !v.is_empty() {
            return build_github_like_url(&format!("{}:{}", host, v).as_str(), user, repo, branch, page)
        }
    }
    build_github_like_url(host, user, repo, branch, page)
}

fn build_bitbucket_url(user: &str, repo: &str, branch: &Option<String>, page: &Page) -> util::Result<String> {
    match page {
        &Page::Open => if let &Some(ref b) = branch {
            Ok(format!("https://bitbucket.org/{}/{}/branch/{}", user, repo, b))
        } else {
            Ok(format!("https://bitbucket.org/{}/{}", user, repo))
        },
        &Page::Diff {..} => Err("BitBucket does not support diff between commits (see https://bitbucket.org/site/master/issues/4779/ability-to-diff-between-any-two-commits)".to_string()),
        &Page::Commit {ref hash} => Ok(format!("https://bitbucket.org/{}/{}/commits/{}", user, repo, hash)),
        &Page::FileOrDir {ref relative_path, ref hash, line: None} => Ok(format!("https://bitbucket.org/{}/{}/src/{}/{}", user, repo, hash, relative_path)),
        &Page::FileOrDir {ref relative_path, ref hash, line: Some(line)} => {
            let file = Path::new(relative_path)
                .file_name()
                .ok_or(format!("Cannot get file name from path: {}", relative_path))?
                .to_str()
                .ok_or(format!("Cannot convert path to UTF8 string: {}", relative_path))?;
            Ok(format!("https://bitbucket.org/{}/{}/src/{}/{}#{}-{}", user, repo, hash, relative_path, file, line))
        },
    }
}

// Note: Parse '/user/repo.git' or '/user/repo' or 'user/repo' into 'user' and 'repo'
fn slug_from_path<'a>(path: &'a str) -> util::Result<(&'a str, &'a str)> {
    let mut split = path.split('/').skip_while(|s| s.is_empty());
    let user = split.next().ok_or(format!("Can't detect user name from path {}", path))?;
    let mut repo = split.next().ok_or(format!("Can't detect repository name from path {}", path))?;
    if repo.ends_with(".git") {
        // Slice '.git' from 'repo.git'
        repo = &repo[0 .. repo.len() - 4];
    }
    Ok((user, repo))
}

// Known URL formats
//  1. https://hosting_service.com/user/repo.git
//  2. git@hosting_service.com:user/repo.git (-> ssh://git@hosting_service.com:22/user/repo.git)
pub fn parse_and_build_page_url(repo: &String, page: &Page, branch: &Option<String>) -> util::Result<String> {
    let url = Url::parse(repo).map_err(|e| format!("Failed to parse URL '{}': {}", repo, e))?;
    let path = url.path();
    let (user, repo_name) = slug_from_path(path)?;
    let host = url.host_str().ok_or(format!("Failed to parse host from {}", repo))?;
    match host {
        "github.com" | "gitlab.com" => Ok(build_github_like_url(host, user, repo_name, branch, page)),
        "bitbucket.org" => build_bitbucket_url(user, repo_name, branch, page),
        _ => if host.starts_with("github.") {
            Ok(build_custom_github_like_url(host, user, repo_name, branch, page, "GIT_BRWS_GHE_SSH_PORT"))
        } else if host.starts_with("gitlab.") {
            Ok(build_custom_github_like_url(host, user, repo_name, branch, page, "GIT_BRWS_GITLAB_SSH_PORT"))
        } else {
            if let Ok(v) = env::var("GIT_BRWS_GHE_URL_HOST") {
                if v == host {
                    return Ok(build_custom_github_like_url(host, user, repo_name, branch, page, "GIT_BRWS_GHE_SSH_PORT"))
                }
            }
            Err(format!("Unknown hosting service for URL {}. If you want to use custom URL for GitHub Enterprise, please set $GIT_BRWS_GHE_URL_HOST", repo))
        },
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#![feature(io, os, path)]

extern crate gl_generator;
extern crate khronos_api;

#[cfg(target_os = "windows")]
const GENERATOR: gl_generator::StructGenerator = gl_generator::StructGenerator;

#[cfg(not(target_os = "windows"))]
const GENERATOR: gl_generator::StaticStructGenerator = gl_generator::StaticStructGenerator;

fn main() {
    let dest = Path::new(std::os::getenv("OUT_DIR").unwrap());
    let mut file = std::old_io::File::create(&dest.join("gl_bindings.rs")).unwrap();
    gl_generator::generate_bindings(
        GENERATOR,
        gl_generator::registry::Ns::Gles2,
        khronos_api::GL_XML,
        vec![],
        "2.0",
        "core",
        &mut file,
    ).unwrap();
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>zoc_gl: Fixed warning<commit_after>// See LICENSE file for copyright and license details.

#![feature(io, path, env)]

extern crate gl_generator;
extern crate khronos_api;

#[cfg(target_os = "windows")]
const GENERATOR: gl_generator::StructGenerator = gl_generator::StructGenerator;

#[cfg(not(target_os = "windows"))]
const GENERATOR: gl_generator::StaticStructGenerator = gl_generator::StaticStructGenerator;

fn main() {
    let dest = Path::new(std::env::var_string("OUT_DIR").unwrap());
    let mut file = std::old_io::File::create(&dest.join("gl_bindings.rs")).unwrap();
    gl_generator::generate_bindings(
        GENERATOR,
        gl_generator::registry::Ns::Gles2,
        khronos_api::GL_XML,
        vec![],
        "2.0",
        "core",
        &mut file,
    ).unwrap();
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize,Ordering};

#[allow(non_camel_case_types)]
#[derive(Copy)]
enum Category
{ CATEGORY_TOKEN = 0,
  CATEGORY_RULE  = 1,
  CATEGORY_STATE = 2 }

pub struct Manager
{
    next_order: [AtomicUsize; 3]
}

impl Manager
{
    fn next_order(&self, c: Category) -> usize
    {
        self.next_order[c as usize].fetch_add(1, Ordering::SeqCst)
    }
}
<commit_msg>ordered: reimpl Manager to use a VecMap<commit_after>use std::fmt;
use std::collections::VecMap;
use std::collections::vec_map::Entry;
use std::sync::atomic::{AtomicUsize,Ordering};

#[allow(non_camel_case_types)]
#[derive(Copy)]
pub enum Category
{ TOKEN = 0,
  RULE  = 1,
  STATE = 2 }

pub trait Ordered {
    fn get_order(&self) -> usize;
}

pub struct Manager {
    next_order: VecMap<AtomicUsize>
}

impl Manager {
    pub fn new() -> Self {
        Manager{next_order: VecMap::with_capacity(3)}
    }
    pub fn next_order(&mut self, c: Category) -> usize
    {
        match self.next_order.entry(c as usize) {
            Entry::Vacant(entry) => { entry.insert(AtomicUsize::new(1));
                                      0 },
            Entry::Occupied(mut entry) => { let val = entry.get_mut();
                                            val.fetch_add(1, Ordering::SeqCst) }
        }
    }
}

impl fmt::Debug for Manager {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ordered::Manager{{}}")
    }
}
<|endoftext|>