<commit_before>macro_rules! native_ref(
    (&$name:ident = $alias:ty) => (
        impl Eq for $name {}
        impl PartialEq<$name> for $name {
            fn eq(&self, other: &$name) -> bool {
                use std::mem;
                unsafe { mem::transmute::<_, isize>(self) == mem::transmute(other) }
            }
        }
        impl<'a> PartialEq<$name> for &'a $name {
            fn eq(&self, other: &$name) -> bool {
                use std::mem;
                unsafe { mem::transmute::<_, isize>(self) == mem::transmute(other) }
            }
        }
        impl<'a> From<&'a $name> for $alias {
            fn from(ty: &'a $name) -> $alias {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
        impl<'a> From<&'a mut $name> for $alias {
            fn from(ty: &'a mut $name) -> $alias {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
        impl<'a> From<$alias> for &'a $name {
            fn from(ty: $alias) -> &'a $name {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
        impl<'a> From<$alias> for &'a mut $name {
            fn from(ty: $alias) -> &'a mut $name {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
    );
    ($name:ident, $field:ident: $pointer_ty:ty) => (
        impl<'a> From<&'a mut $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<&'a $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$pointer_ty> for $name {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name {
                $name {
                    $field: ptr
                }
            }
        }
    );
    ($name:ident, $field:ident: $pointer_ty:ty, $($ofield:ident = $expr:expr),*) => (
        impl<'a> From<&'a mut $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<&'a $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$pointer_ty> for $name {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name {
                $name {
                    $field: ptr,
                    $($ofield: $expr),*
                }
            }
        }
    );
    ($name:ident<$ty:ident>, $field:ident: $pointer_ty:ty, $($ofield:ident = $expr:expr),*) => (
        impl<'a, $ty> From<&'a mut $name<$ty>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name<$ty>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a, $ty> From<&'a $name<$ty>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name<$ty>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<$ty> From<$name<$ty>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name<$ty>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<$ty> From<$pointer_ty> for $name<$ty> {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name<$ty> {
                $name {
                    $field: ptr,
                    $($ofield: $expr),*
                }
            }
        }
    );
    (contra $name:ident, $field:ident: $pointer_ty:ty) => (
        impl<'a, 'b> From<&'a mut $name<'b>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name<'b>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a, 'b> From<&'a $name<'b>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name<'b>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<$name<'a>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name<'a>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<$pointer_ty> for $name<'a> {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name<'a> {
                $name {
                    $field: ptr,
                    marker: PhantomData
                }
            }
        }
    )
);
macro_rules! to_str(
    ($ty:ty, $func:ident) => (
        impl fmt::Debug for $ty {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                fmt.write_str(unsafe {
                    let c_str = core::$func(self.into());
                    util::to_str(c_str)
                })
            }
        }
    );
);
macro_rules! get_context(
    ($ty:ty, $func:ident) => (
        impl GetContext for $ty {
            fn get_context(&self) -> &Context {
                unsafe { core::$func(self.into()) }.into()
            }
        }
    );
);
macro_rules! deref(
    ($ty:ty, $to:ty) => (
        impl Deref for $ty {
            type Target = $to;
            fn deref(&self) -> &$to {
                unsafe { mem::transmute(self) }
            }
        }
    );
);
macro_rules! dispose(
    ($ty:ty, $ref_ty:ty, $func:expr) => (
        impl ::cbox::DisposeRef for $ty {
            type RefTo = $ref_ty;
            #[inline(always)]
            unsafe fn dispose(ptr: *mut $ref_ty) {
                $func(ptr)
            }
        }
    );
);
<commit_msg>Fix permissions on macros.rs<commit_after>macro_rules! native_ref(
    (&$name:ident = $alias:ty) => (
        impl Eq for $name {}
        impl PartialEq<$name> for $name {
            fn eq(&self, other: &$name) -> bool {
                use std::mem;
                unsafe { mem::transmute::<_, isize>(self) == mem::transmute(other) }
            }
        }
        impl<'a> PartialEq<$name> for &'a $name {
            fn eq(&self, other: &$name) -> bool {
                use std::mem;
                unsafe { mem::transmute::<_, isize>(self) == mem::transmute(other) }
            }
        }
        impl<'a> From<&'a $name> for $alias {
            fn from(ty: &'a $name) -> $alias {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
        impl<'a> From<&'a mut $name> for $alias {
            fn from(ty: &'a mut $name) -> $alias {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
        impl<'a> From<$alias> for &'a $name {
            fn from(ty: $alias) -> &'a $name {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
        impl<'a> From<$alias> for &'a mut $name {
            fn from(ty: $alias) -> &'a mut $name {
                use std::mem;
                unsafe { mem::transmute(ty) }
            }
        }
    );
    ($name:ident, $field:ident: $pointer_ty:ty) => (
        impl<'a> From<&'a mut $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<&'a $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$pointer_ty> for $name {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name {
                $name {
                    $field: ptr
                }
            }
        }
    );
    ($name:ident, $field:ident: $pointer_ty:ty, $($ofield:ident = $expr:expr),*) => (
        impl<'a> From<&'a mut $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<&'a $name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$name> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name) -> $pointer_ty {
                thing.$field
            }
        }
        impl From<$pointer_ty> for $name {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name {
                $name {
                    $field: ptr,
                    $($ofield: $expr),*
                }
            }
        }
    );
    ($name:ident<$ty:ident>, $field:ident: $pointer_ty:ty, $($ofield:ident = $expr:expr),*) => (
        impl<'a, $ty> From<&'a mut $name<$ty>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name<$ty>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a, $ty> From<&'a $name<$ty>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name<$ty>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<$ty> From<$name<$ty>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name<$ty>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<$ty> From<$pointer_ty> for $name<$ty> {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name<$ty> {
                $name {
                    $field: ptr,
                    $($ofield: $expr),*
                }
            }
        }
    );
    (contra $name:ident, $field:ident: $pointer_ty:ty) => (
        impl<'a, 'b> From<&'a mut $name<'b>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a mut $name<'b>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a, 'b> From<&'a $name<'b>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: &'a $name<'b>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<$name<'a>> for $pointer_ty {
            /// Convert into a native pointer
            fn from(thing: $name<'a>) -> $pointer_ty {
                thing.$field
            }
        }
        impl<'a> From<$pointer_ty> for $name<'a> {
            /// Convert from a native pointer
            fn from(ptr: $pointer_ty) -> $name<'a> {
                $name {
                    $field: ptr,
                    marker: PhantomData
                }
            }
        }
    )
);
macro_rules! to_str(
    ($ty:ty, $func:ident) => (
        impl fmt::Debug for $ty {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                fmt.write_str(unsafe {
                    let c_str = core::$func(self.into());
                    util::to_str(c_str)
                })
            }
        }
    );
);
macro_rules! get_context(
    ($ty:ty, $func:ident) => (
        impl GetContext for $ty {
            fn get_context(&self) -> &Context {
                unsafe { core::$func(self.into()) }.into()
            }
        }
    );
);
macro_rules! deref(
    ($ty:ty, $to:ty) => (
        impl Deref for $ty {
            type Target = $to;
            fn deref(&self) -> &$to {
                unsafe { mem::transmute(self) }
            }
        }
    );
);
macro_rules! dispose(
    ($ty:ty, $ref_ty:ty, $func:expr) => (
        impl ::cbox::DisposeRef for $ty {
            type RefTo = $ref_ty;
            #[inline(always)]
            unsafe fn dispose(ptr: *mut $ref_ty) {
                $func(ptr)
            }
        }
    );
);
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, NativeEndian, ReadBytesExt, WriteBytesExt};
use std::collections::{btree_map, BTreeMap, HashMap};
use std::collections::Bound::{Included, Excluded};
use std::mem;
use std::ptr;

use error::{EvalError, EvalResult};
use primval::PrimVal;

pub struct Memory {
    alloc_map: HashMap<u64, Allocation>,
    next_id: u64,
    pub pointer_size: usize,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AllocId(u64);

#[derive(Debug)]
pub struct Allocation {
    pub bytes: Box<[u8]>,
    pub relocations: BTreeMap<usize, AllocId>,
    // TODO(tsion): undef mask
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Pointer {
    pub alloc_id: AllocId,
    pub offset: usize,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FieldRepr {
    pub offset: usize,
    pub size: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Repr {
    /// Representation for a non-aggregate type such as a boolean, integer, character or pointer.
    Primitive {
        size: usize
    },

    /// The representation for aggregate types including structs, enums, and tuples.
    Aggregate {
        /// The size of the discriminant (an integer). Should be between 0 and 8. Always 0 for
        /// structs and tuples.
        discr_size: usize,

        /// The size of the entire aggregate, including the discriminant.
        size: usize,

        /// The representations of the contents of each variant.
        variants: Vec<Vec<FieldRepr>>,
    },

    Array {
        elem_size: usize,

        /// Number of elements.
        length: usize,
    },
}

impl Memory {
    pub fn new() -> Self {
        Memory {
            alloc_map: HashMap::new(),
            next_id: 0,

            // TODO(tsion): Should this be host's or target's usize?
            pointer_size: mem::size_of::<usize>(),
        }
    }

    pub fn allocate(&mut self, size: usize) -> Pointer {
        let id = AllocId(self.next_id);
        let alloc = Allocation {
            bytes: vec![0; size].into_boxed_slice(),
            relocations: BTreeMap::new(),
        };
        self.alloc_map.insert(self.next_id, alloc);
        self.next_id += 1;
        Pointer {
            alloc_id: id,
            offset: 0,
        }
    }

    pub fn get(&self, id: AllocId) -> EvalResult<&Allocation> {
        self.alloc_map.get(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    pub fn get_mut(&mut self, id: AllocId) -> EvalResult<&mut Allocation> {
        self.alloc_map.get_mut(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        let alloc = try!(self.get(ptr.alloc_id));
        if ptr.offset + size > alloc.bytes.len() {
            return Err(EvalError::PointerOutOfBounds);
        }
        Ok(&alloc.bytes[ptr.offset..ptr.offset + size])
    }

    fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        let alloc = try!(self.get_mut(ptr.alloc_id));
        if ptr.offset + size > alloc.bytes.len() {
            return Err(EvalError::PointerOutOfBounds);
        }
        Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
    }

    fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        if try!(self.relocations(ptr, size)).count() != 0 {
            return Err(EvalError::ReadPointerAsBytes);
        }
        // TODO(tsion): Track and check for undef bytes.
        self.get_bytes_unchecked(ptr, size)
    }

    fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        try!(self.clear_relocations(ptr, size));
        self.get_bytes_unchecked_mut(ptr, size)
    }

    fn relocations(&self, ptr: Pointer, size: usize)
        -> EvalResult<btree_map::Range<usize, AllocId>>
    {
        let start = ptr.offset.saturating_sub(self.pointer_size - 1);
        let end = start + size;
        Ok(try!(self.get(ptr.alloc_id)).relocations.range(Included(&start), Excluded(&end)))
    }

    fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let keys: Vec<_> = try!(self.relocations(ptr, size)).map(|(&k, _)| k).collect();
        let alloc = try!(self.get_mut(ptr.alloc_id));
        for k in keys {
            alloc.relocations.remove(&k);
        }
        Ok(())
    }

    fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let overlapping_start = try!(self.relocations(ptr, 0)).count();
        let overlapping_end = try!(self.relocations(ptr.offset(size as isize), 0)).count();
        if overlapping_start + overlapping_end != 0 {
            return Err(EvalError::ReadPointerAsBytes);
        }
        Ok(())
    }

    fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        let relocations: Vec<_> = try!(self.relocations(src, size))
            .map(|(&offset, &alloc_id)| {
                // Update relocation offsets for the new positions in the destination allocation.
                (offset + dest.offset - src.offset, alloc_id)
            })
            .collect();
        try!(self.get_mut(dest.alloc_id)).relocations.extend(relocations);
        Ok(())
    }

    pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        // TODO(tsion): Track and check for undef bytes.
        try!(self.check_relocation_edges(src, size));

        let src_bytes = try!(self.get_bytes_unchecked_mut(src, size)).as_mut_ptr();
        let dest_bytes = try!(self.get_bytes_mut(dest, size)).as_mut_ptr();

        // SAFE: The above indexing would have panicked if there weren't at least `size` bytes
        // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
        // `dest` could possibly overlap.
        unsafe {
            if src.alloc_id == dest.alloc_id {
                ptr::copy(src_bytes, dest_bytes, size);
            } else {
                ptr::copy_nonoverlapping(src_bytes, dest_bytes, size);
            }
        }

        self.copy_relocations(src, dest, size)
    }

    pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<()> {
        self.get_bytes_mut(ptr, src.len()).map(|dest| dest.clone_from_slice(src))
    }

    pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<Pointer> {
        let size = self.pointer_size;
        let offset = try!(self.get_bytes_unchecked(ptr, size))
            .read_uint::<NativeEndian>(size).unwrap() as usize;
        let alloc = try!(self.get(ptr.alloc_id));
        match alloc.relocations.get(&ptr.offset) {
            Some(&alloc_id) => Ok(Pointer { alloc_id: alloc_id, offset: offset }),
            None => Err(EvalError::ReadBytesAsPointer),
        }
    }

    pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<()> {
        {
            let size = self.pointer_size;
            let mut bytes = try!(self.get_bytes_mut(dest, size));
            bytes.write_uint::<NativeEndian>(ptr.offset as u64, size).unwrap();
        }
        try!(self.get_mut(dest.alloc_id)).relocations.insert(dest.offset, ptr.alloc_id);
        Ok(())
    }

    pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> {
        let pointer_size = self.pointer_size;
        match val {
            PrimVal::Bool(b) => self.write_bool(ptr, b),
            PrimVal::I8(n)   => self.write_int(ptr, n as i64, 1),
            PrimVal::I16(n)  => self.write_int(ptr, n as i64, 2),
            PrimVal::I32(n)  => self.write_int(ptr, n as i64, 4),
            PrimVal::I64(n)  => self.write_int(ptr, n as i64, 8),
            PrimVal::U8(n)   => self.write_uint(ptr, n as u64, 1),
            PrimVal::U16(n)  => self.write_uint(ptr, n as u64, 2),
            PrimVal::U32(n)  => self.write_uint(ptr, n as u64, 4),
            PrimVal::U64(n)  => self.write_uint(ptr, n as u64, 8),
            PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
            PrimVal::AbstractPtr(_p) => unimplemented!(),
        }
    }

    pub fn read_bool(&self, ptr: Pointer) -> EvalResult<bool> {
        let bytes = try!(self.get_bytes(ptr, 1));
        match bytes[0] {
            0 => Ok(false),
            1 => Ok(true),
            _ => Err(EvalError::InvalidBool),
        }
    }

    pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<()> {
        self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8)
    }

    pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<i64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_int::<NativeEndian>(size).unwrap())
    }

    pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_int::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<u64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_uint::<NativeEndian>(size).unwrap())
    }

    pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_uint::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_isize(&self, ptr: Pointer) -> EvalResult<i64> {
        self.read_int(ptr, self.pointer_size)
    }

    pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_int(ptr, n, size)
    }

    pub fn read_usize(&self, ptr: Pointer) -> EvalResult<u64> {
        self.read_uint(ptr, self.pointer_size)
    }

    pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_uint(ptr, n, size)
    }
}

impl Pointer {
    pub fn offset(self, i: isize) -> Self {
        Pointer { offset: (self.offset as isize + i) as usize, ..self }
    }
}

impl Repr {
    pub fn size(&self) -> usize {
        match *self {
            Repr::Primitive { size } => size,
            Repr::Aggregate { size, .. } => size,
            Repr::Array { elem_size, length } => elem_size * length,
        }
    }
}
<commit_msg>Reorganize memory methods.<commit_after>use byteorder::{ByteOrder, NativeEndian, ReadBytesExt, WriteBytesExt};
use std::collections::{btree_map, BTreeMap, HashMap};
use std::collections::Bound::{Included, Excluded};
use std::mem;
use std::ptr;

use error::{EvalError, EvalResult};
use primval::PrimVal;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AllocId(u64);

#[derive(Debug)]
pub struct Allocation {
    pub bytes: Box<[u8]>,
    pub relocations: BTreeMap<usize, AllocId>,
    // TODO(tsion): undef mask
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Pointer {
    pub alloc_id: AllocId,
    pub offset: usize,
}

impl Pointer {
    pub fn offset(self, i: isize) -> Self {
        Pointer { offset: (self.offset as isize + i) as usize, ..self }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FieldRepr {
    pub offset: usize,
    pub size: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Repr {
    /// Representation for a non-aggregate type such as a boolean, integer, character or pointer.
    Primitive {
        size: usize
    },

    /// The representation for aggregate types including structs, enums, and tuples.
    Aggregate {
        /// The size of the discriminant (an integer). Should be between 0 and 8. Always 0 for
        /// structs and tuples.
        discr_size: usize,

        /// The size of the entire aggregate, including the discriminant.
        size: usize,

        /// The representations of the contents of each variant.
        variants: Vec<Vec<FieldRepr>>,
    },

    Array {
        elem_size: usize,

        /// Number of elements.
        length: usize,
    },
}

impl Repr {
    pub fn size(&self) -> usize {
        match *self {
            Repr::Primitive { size } => size,
            Repr::Aggregate { size, .. } => size,
            Repr::Array { elem_size, length } => elem_size * length,
        }
    }
}

pub struct Memory {
    alloc_map: HashMap<u64, Allocation>,
    next_id: u64,
    pub pointer_size: usize,
}

impl Memory {
    pub fn new() -> Self {
        Memory {
            alloc_map: HashMap::new(),
            next_id: 0,

            // TODO(tsion): Should this be host's or target's usize?
            pointer_size: mem::size_of::<usize>(),
        }
    }

    pub fn allocate(&mut self, size: usize) -> Pointer {
        let id = AllocId(self.next_id);
        let alloc = Allocation {
            bytes: vec![0; size].into_boxed_slice(),
            relocations: BTreeMap::new(),
        };
        self.alloc_map.insert(self.next_id, alloc);
        self.next_id += 1;
        Pointer {
            alloc_id: id,
            offset: 0,
        }
    }

    ////////////////////////////////////////////////////////////////////////////////
    // Allocation accessors
    ////////////////////////////////////////////////////////////////////////////////

    pub fn get(&self, id: AllocId) -> EvalResult<&Allocation> {
        self.alloc_map.get(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    pub fn get_mut(&mut self, id: AllocId) -> EvalResult<&mut Allocation> {
        self.alloc_map.get_mut(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    ////////////////////////////////////////////////////////////////////////////////
    // Byte accessors
    ////////////////////////////////////////////////////////////////////////////////

    fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        let alloc = try!(self.get(ptr.alloc_id));
        if ptr.offset + size > alloc.bytes.len() {
            return Err(EvalError::PointerOutOfBounds);
        }
        Ok(&alloc.bytes[ptr.offset..ptr.offset + size])
    }

    fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        let alloc = try!(self.get_mut(ptr.alloc_id));
        if ptr.offset + size > alloc.bytes.len() {
            return Err(EvalError::PointerOutOfBounds);
        }
        Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
    }

    fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        if try!(self.relocations(ptr, size)).count() != 0 {
            return Err(EvalError::ReadPointerAsBytes);
        }
        // TODO(tsion): Track and check for undef bytes.
        self.get_bytes_unchecked(ptr, size)
    }

    fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        try!(self.clear_relocations(ptr, size));
        self.get_bytes_unchecked_mut(ptr, size)
    }

    ////////////////////////////////////////////////////////////////////////////////
    // Reading and writing
    ////////////////////////////////////////////////////////////////////////////////

    pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        // TODO(tsion): Track and check for undef bytes.
        try!(self.check_relocation_edges(src, size));

        let src_bytes = try!(self.get_bytes_unchecked_mut(src, size)).as_mut_ptr();
        let dest_bytes = try!(self.get_bytes_mut(dest, size)).as_mut_ptr();

        // SAFE: The above indexing would have panicked if there weren't at least `size` bytes
        // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
        // `dest` could possibly overlap.
        unsafe {
            if src.alloc_id == dest.alloc_id {
                ptr::copy(src_bytes, dest_bytes, size);
            } else {
                ptr::copy_nonoverlapping(src_bytes, dest_bytes, size);
            }
        }

        self.copy_relocations(src, dest, size)
    }

    pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<()> {
        self.get_bytes_mut(ptr, src.len()).map(|dest| dest.clone_from_slice(src))
    }

    pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<Pointer> {
        let size = self.pointer_size;
        let offset = try!(self.get_bytes_unchecked(ptr, size))
            .read_uint::<NativeEndian>(size).unwrap() as usize;
        let alloc = try!(self.get(ptr.alloc_id));
        match alloc.relocations.get(&ptr.offset) {
            Some(&alloc_id) => Ok(Pointer { alloc_id: alloc_id, offset: offset }),
            None => Err(EvalError::ReadBytesAsPointer),
        }
    }

    pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<()> {
        {
            let size = self.pointer_size;
            let mut bytes = try!(self.get_bytes_mut(dest, size));
            bytes.write_uint::<NativeEndian>(ptr.offset as u64, size).unwrap();
        }
        try!(self.get_mut(dest.alloc_id)).relocations.insert(dest.offset, ptr.alloc_id);
        Ok(())
    }

    pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> {
        let pointer_size = self.pointer_size;
        match val {
            PrimVal::Bool(b) => self.write_bool(ptr, b),
            PrimVal::I8(n)   => self.write_int(ptr, n as i64, 1),
            PrimVal::I16(n)  => self.write_int(ptr, n as i64, 2),
            PrimVal::I32(n)  => self.write_int(ptr, n as i64, 4),
            PrimVal::I64(n)  => self.write_int(ptr, n as i64, 8),
            PrimVal::U8(n)   => self.write_uint(ptr, n as u64, 1),
            PrimVal::U16(n)  => self.write_uint(ptr, n as u64, 2),
            PrimVal::U32(n)  => self.write_uint(ptr, n as u64, 4),
            PrimVal::U64(n)  => self.write_uint(ptr, n as u64, 8),
            PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
            PrimVal::AbstractPtr(_p) => unimplemented!(),
        }
    }

    pub fn read_bool(&self, ptr: Pointer) -> EvalResult<bool> {
        let bytes = try!(self.get_bytes(ptr, 1));
        match bytes[0] {
            0 => Ok(false),
            1 => Ok(true),
            _ => Err(EvalError::InvalidBool),
        }
    }

    pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<()> {
        self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8)
    }

    pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<i64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_int::<NativeEndian>(size).unwrap())
    }

    pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_int::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<u64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_uint::<NativeEndian>(size).unwrap())
    }

    pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_uint::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_isize(&self, ptr: Pointer) -> EvalResult<i64> {
        self.read_int(ptr, self.pointer_size)
    }

    pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_int(ptr, n, size)
    }

    pub fn read_usize(&self, ptr: Pointer) -> EvalResult<u64> {
        self.read_uint(ptr, self.pointer_size)
    }

    pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_uint(ptr, n, size)
    }

    ////////////////////////////////////////////////////////////////////////////////
    // Relocations
    ////////////////////////////////////////////////////////////////////////////////

    fn relocations(&self, ptr: Pointer, size: usize)
        -> EvalResult<btree_map::Range<usize, AllocId>>
    {
        let start = ptr.offset.saturating_sub(self.pointer_size - 1);
        let end = start + size;
        Ok(try!(self.get(ptr.alloc_id)).relocations.range(Included(&start), Excluded(&end)))
    }

    fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let keys: Vec<_> = try!(self.relocations(ptr, size)).map(|(&k, _)| k).collect();
        let alloc = try!(self.get_mut(ptr.alloc_id));
        for k in keys {
            alloc.relocations.remove(&k);
        }
        Ok(())
    }

    fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let overlapping_start = try!(self.relocations(ptr, 0)).count();
        let overlapping_end = try!(self.relocations(ptr.offset(size as isize), 0)).count();
        if overlapping_start + overlapping_end != 0 {
            return Err(EvalError::ReadPointerAsBytes);
        }
        Ok(())
    }

    fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        let relocations: Vec<_> = try!(self.relocations(src, size))
            .map(|(&offset, &alloc_id)| {
                // Update relocation offsets for the new positions in the destination allocation.
                (offset + dest.offset - src.offset, alloc_id)
            })
            .collect();
        try!(self.get_mut(dest.alloc_id)).relocations.extend(relocations);
        Ok(())
    }
}
<|endoftext|>


<commit_before>use ast::*;
use scanner::{Token, TokenWithContext};
use std::iter::Peekable;

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Option<Expr>, String> {
    let mut iter = tokens.iter().peekable();
    // TODO: add recovery
    parse_expression(&mut iter)
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<Operator>,
                       parse_subexpression: &Fn(&mut Peekable<I>) -> Result<Option<Expr>, String>)
                       -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        if let Some(e) = try!(parse_subexpression(tokens)) {
            expr = e;
        } else {
            return Ok(None);
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        {
            // Just advance, we know all we need from the peeked value
            let _ = tokens.next();
        }
        let right;
        {
            if let Some(e) = try!(parse_subexpression(tokens)) {
                right = e
            } else {
                // TODO add context
                return Err("Expected subexpression".into());
            }
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Ok(Some(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::BangEqual => Some(Operator::NotEqual),
            &Token::EqualEqual => Some(Operator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Greater => Some(Operator::Greater),
            &Token::GreaterEqual => Some(Operator::GreaterEqual),
            &Token::Less => Some(Operator::Less),
            &Token::LessEqual => Some(Operator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Plus => Some(Operator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Slash => Some(Operator::Slash),
            &Token::Star => Some(Operator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Bang => Some(Operator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().cloned().map(|pt| map_operator(&pt.token)) {
        {
            // Just advance, we know all we need from the peeked value
            let _ = tokens.next();
        }
        let right;
        {
            if let Some(e) = try!(parse_unary(tokens)) {
                right = e;
            } else {
                // TODO: add context
                return Err("Expected right side of unary".into());
            }
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Ok(Some(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr;
                {
                    if let Some(e) = try!(parse_expression(tokens)) {
                        expr = e;
                    } else {
                        // TODO add context
                        return Err("Unfinished grouping expression".into());
                    }
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::LeftParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Ok(Some(Expr::Grouping(Box::new(grouping_expression))));
                        }
                    }
                    // TODO: fill with context
                    return Err("Missing )".into());
                }
            }
            _ => {
                // TODO: fill with context
                return Err("Unexpected token".into());
            }
        };
        Ok(Some(parsed_expression))
    } else {
        Ok(None)
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let tokens = scan(&"123".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("123", &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let tokens = scan(&"123+456".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let tokens = scan(&"123+456*789".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

        #[test]
    fn precedence_mul_add() {
        let tokens = scan(&"123*456+789".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }
}
<commit_msg>Test for unary operation<commit_after>use ast::*;
use scanner::{Token, TokenWithContext};
use std::iter::Peekable;

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Option<Expr>, String> {
    let mut iter = tokens.iter().peekable();
    // TODO: add recovery
    parse_expression(&mut iter)
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<Operator>,
                       parse_subexpression: &Fn(&mut Peekable<I>) -> Result<Option<Expr>, String>)
                       -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        if let Some(e) = try!(parse_subexpression(tokens)) {
            expr = e;
        } else {
            return Ok(None);
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        {
            // Just advance, we know all we need from the peeked value
            let _ = tokens.next();
        }
        let right;
        {
            if let Some(e) = try!(parse_subexpression(tokens)) {
                right = e
            } else {
                // TODO add context
                return Err("Expected subexpression".into());
            }
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Ok(Some(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::BangEqual => Some(Operator::NotEqual),
            &Token::EqualEqual => Some(Operator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Greater => Some(Operator::Greater),
            &Token::GreaterEqual => Some(Operator::GreaterEqual),
            &Token::Less => Some(Operator::Less),
            &Token::LessEqual => Some(Operator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Plus => Some(Operator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Slash => Some(Operator::Slash),
            &Token::Star => Some(Operator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Bang => Some(Operator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().cloned().map(|pt| map_operator(&pt.token)) {
        {
            // Just advance, we know all we need from the peeked value
            let _ = tokens.next();
        }
        let right;
        {
            if let Some(e) = try!(parse_unary(tokens)) {
                right = e;
            } else {
                // TODO: add context
                return Err("Expected right side of unary".into());
            }
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Ok(Some(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Result<Option<Expr>, String>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr;
                {
                    if let Some(e) = try!(parse_expression(tokens)) {
                        expr = e;
                    } else {
                        // TODO add context
                        return Err("Unfinished grouping expression".into());
                    }
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::LeftParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Ok(Some(Expr::Grouping(Box::new(grouping_expression))));
                        }
                    }
                    // TODO: fill with context
                    return Err("Missing )".into());
                }
            }
            _ => {
                // TODO: fill with context
                return Err("Unexpected token".into());
            }
        };
        Ok(Some(parsed_expression))
    } else {
        Ok(None)
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let tokens = scan(&"123".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("123", &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let tokens = scan(&"123+456".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let tokens = scan(&"123+456*789".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let tokens = scan(&"123*456+789".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let tokens = scan(&"-123*456+789".into()).unwrap();
        let expr = parse(tokens).unwrap().unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }
}
<|endoftext|>


<commit_before>use std::str;
use std::fmt::Write;
use std::iter::Iterator;
use std::collections::HashMap;
use std::string::String;

use regex::Regex;

use types::*;

lazy_static!{
    pub static ref FMT_PAT: Regex = Regex::new(
//          1-ident    2-fill 3-align 4-sign  5-width   6-precision    7-type
        r"^([\w\d-_]+)(?::(.)?([<>^])?([+-])?([([\d]+)?(?:\.([\d]+))?([sbcdoxXneEfFgG%])?)?\z")
        .unwrap();
//          1-ident    2-fill 3-align 4-width  5-precision
    // r"^([\w\d-_]+)(?::(.)?([<>^])?([\d]+)?(?:\.([\d]+))?)?\z").unwrap();
// if align doesn't exist, width == fill + width
}

fn write_char(s: &mut String, c: char, n: usize) {
    for _ in 0..n {
        s.push(c);
    }
}

#[test]
fn test_write_char() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_char(&mut s, 'f', 3);
    assert!(s == "h fff");
}

fn write_from<'a, I>(s: &mut String, f: I, n: usize) -> usize
    where I: Iterator<Item = char>
{
    // eexaust f or run out of n, return chars written
    if n == 0 {
        return 0;
    }
    let mut n_written: usize = 0;
    for c in f {
        s.push(c);
        n_written += 1;
        if n_written == n {
            return n_written;
        }
    }
    n_written
}

#[test]
fn test_write_from() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_from(&mut s, "fff".chars(), 5);
    assert!(s == "h fff");
    write_from(&mut s, "xxxx".chars(), 2);
    assert!(s == "h fffxx");
    write_from(&mut s, "333".chars(), 3);
    assert!(s == "h fffxx333");
}

fn is_alignment_token(c: char) -> bool {
    match c {
        '=' | '<' | '^' | '>' => true,
        _ => false,
    }
}

fn is_sign_element(c: char) -> bool {
    match c {
        ' ' | '-' | '+' => true,
        _ => false,
    }
}

fn is_type_element(c: char) -> bool {
    match c {
        'b' | 'c' | 'd' | 'o' | 'x' | 'X' | 'n' |
        'e' | 'E' | 'f' | 'F' | 'g' | 'G' | '%' |
        's' | '?' => true,
        _ => false,
    }
}

// get an integer from pos, returning the number of bytes
// consumed and the integer
fn get_integer(s: &[u8], pos: usize) -> (usize, Option<i64>) {
    let (_, rest) = s.split_at(pos);
    let mut consumed: usize = 0;
    for b in rest {
        match *b as char {
            '0'...'9' => {},
            _ => break,
        };
        consumed += 1;
    }
    if consumed == 0 {
        (0, None)
    } else {
        let (intstr, _) = rest.split_at(consumed);
        let val = unsafe { // I think I can be reasonably sure that 0-9 chars are utf8 :)
            match str::from_utf8_unchecked(intstr).parse::<i64>() {
                Ok(v) => Some(v),
                Err(_) => None,
            }
        };
        (consumed, val)
    }
}

#[derive(Debug)]
/// The format struct as it is defined in the python source
struct FmtPy {
    pub fill: char,
    pub align: char,
    pub alternate: bool,
    pub sign: char,
    pub width: i64,
    pub thousands: bool,
    pub precision: i64,
    pub ty: char,
}

fn parse_like_python(rest: &str) -> Result<FmtPy> {
    /* The rest of this was pretty much strait up copied from python's format parser
        All credit goes to python source file: formatter_unicode.c
    */

    let mut format = FmtPy {
        fill: ' ',
        align: '>',
        alternate: false,
        sign: '\0',
        width: -1,
        thousands: false,
        precision: -1,
        ty: ' ',
    };
    let mut chars = rest.chars();
    let fake_fill = match chars.next() {
        Some(c) => c,
        None => return Ok(format),
    };
    let (_, rest) = rest.split_at(fake_fill.len_utf8());
    // from now on all format characters MUST be valid
    // ASCII characters (fill and identifier were the
    // only ones that weren't.
    // Therefore we can use bytes for the rest
    let mut align_specified = false;
    let mut fill_specified = false;

    let rest = rest.as_bytes();
    let end: usize = rest.len();
    let mut pos: usize = 0;

    /* If the second char is an alignment token,
        then parse the fill char */
    if end-pos >= 1 && is_alignment_token(rest[0] as char) {
        format.align = rest[0] as char;
        format.fill = fake_fill;
        fill_specified = true;
        align_specified = true;
        pos += 2;
    } else if end-pos == 0 && is_alignment_token(fake_fill) {
        format.align = fake_fill;
        pos+=1;
    }

    /* Parse the various sign options */
    if end-pos >= 1 && is_sign_element(rest[pos] as char) {
        format.sign = rest[pos] as char;
        pos+=1;
    }

    /* If the next character is #, we're in alternate mode.  This only
        applies to integers. */
    if end-pos >= 1 && rest[pos] as char == '#' {
        format.alternate = true;
        pos+=1;
    }

    /* The special case for 0-padding (backwards compat) */
    if !fill_specified && end-pos >= 1 && rest[pos] == '0' as u8 {
        format.fill = '0';
        if (!align_specified) {
            format.align = '=';
        }
        pos+=1;
    }

    // check to make sure that val is good
    let (consumed, val) = get_integer(rest, pos);
    pos += consumed;
    if consumed != 0 {
        match val {
            None => return Err(FmtError::Invalid("overflow error when parsing width".to_string())),
            Some(v) => {
                format.width = v;
            }
        }
    }

    /* Comma signifies add thousands separators */
    if end-pos > 0 && rest[pos] as char == ',' {
        format.thousands = true;
        pos+=1;
    }

    /* Parse field precision */
    if end-pos > 0 && rest[pos] as char == '.' {
        pos+=1;

        let (consumed, val) = get_integer(rest, pos);
        if consumed != 0 {
            match val {
                None => return Err(FmtError::Invalid("overflow error when parsing precision"
                                            .to_string())),
                Some(v) => {
                    format.precision = v;
                }
            }
        } else {
            /* Not having a precision after a dot is an error. */
            if (consumed == 0) {
                return Err(FmtError::Invalid("Format specifier missing precision".to_string()));
            }
        }

    }

    /* Finally, parse the type field. */
    if end-pos > 1 {
        /* More than one char remain, invalid format specifier. */
        return Err(FmtError::Invalid("Invalid format specifier".to_string()));
    }

    if end-pos == 1 {
        format.ty = rest[pos] as char;
        if !is_type_element(format.ty) {
            let mut msg = String::new();
            write!(msg, "Invalid type specifier: {:?}", format.ty).unwrap();
            return Err(FmtError::Invalid(msg));
        }
        pos+=1;
    }

    /* Do as much validating as we can, just by looking at the format
        specifier.  Do not take into account what type of formatting
        we're doing (int, float, string). */
    if format.thousands {
        match format.ty {
            'd' | 'e' | 'f' | 'g' | 'E' | 'G' |
            '%' | 'F' | '\0' => {}, /* These are allowed. See PEP 378.*/

            _ => {
                let mut msg = String::new();
                write!(msg, "Invalid comma type: {}", format.ty);
                return Err(FmtError::Invalid(msg));
            }
        }
    }
    Ok(format)
}

impl<'a> FmtChunk<'a> {
    /// create FmtChunk from format string
    pub fn from_str(s: &'a str) -> Result<FmtChunk> {
        let mut done = false;
        let mut chars = s.chars();
        let mut c = match chars.next() {
            Some(':') | None => return Err(
                FmtError::Invalid("must specify identifier".to_string())),
            Some(c) => c,
        };
        let mut consumed = 0;
        // find the identifier
        loop {
            consumed += c.len_utf8();
            if c == ':' {
                break;
            }
            c = match chars.next() {
                Some(c) => c,
                None => {
                    done = true;
                    break;
                }
            };
        }
        let (identifier, rest) = s.split_at(consumed);
        let (identifier, _) = identifier.split_at(identifier.len() - 1); // get rid of ':'

        let format = try!(parse_like_python(rest));

        Ok(FmtChunk{
            identifier: identifier,
            fill: format.fill,
            align: match format.align {
                '<' => Align::Left,
                '^' => Align::Center,
                '>' => Align::Right,
                '=' => Align::Equal,
                _ => unreachable!(),
            },
            alternate: format.alternate,
            width: match format.width {
                -1 => None,
                _ => Some(format.width as usize),
            },
            thousands: format.thousands,
            precision: match format.precision {
                -1 => None,
                _ => Some(format.precision as usize),
            },
            ty: match format.ty {
                ' ' => None,
                _ => Some(format.ty),
            },
        })
    }

    /// write the formatted string to `s` and return true. If there is an error: clear `s`,
    /// write the error and return false
    pub fn write(&self, s: &mut String, vars: &'a HashMap<String, String>) -> Result<()> {
        let ref value = match vars.get(self.identifier) {
            Some(v) => v,
            None => {
                return Err(FmtError::KeyError(self.identifier.to_string()));
            }
        };
        let len = match self.precision {
            None => value.len(),
            Some(p) => {
                if p < value.len() {
                    p
                } else {
                    value.len()
                }
            }
        };
        let mut value = value.chars();
        let mut pad: usize = 0;

        match self.width {
            Some(mut width) => {
                if width > len {
                    match self.align {
                        Align::Left => pad = width - len,
                        Align::Center => {
                            width = width - len;
                            pad = width / 2;
                            write_char(s, self.fill, pad);
                            pad += width % 2;
                        }
                        Align::Right => {
                            write_char(s, self.fill, width - len);
                        }
                        Align::Equal => panic!("not yet supported"), // TODO
                    }
                }
            }
            None => {}
        }
        if self.precision.is_none() {
            s.extend(value);
        } else {
            write_from(s, &mut value, self.precision.unwrap());
        }
        write_char(s, self.fill, pad);
        Ok(())
    }
}

/// UNSTABLE: rust-style format a string given a HashMap of the variables and additional options
/// variables:
///   ignore_missing: if true, ignore missing variables
pub fn strfmt_options(fmtstr: &str, vars: &HashMap<String, String>, ignore_missing: bool) -> Result<String> {
    let mut out = String::with_capacity(fmtstr.len() * 2);
    let mut bytes_read: usize = 0;
    let mut opening_brace: usize = 0;
    let mut closing_brace: bool = false;
    let mut reading_fmt = false;
    let mut remaining = fmtstr;
    for c in fmtstr.chars() {
        bytes_read += c.len_utf8();
        if c == '{' {
            if reading_fmt && opening_brace == bytes_read - 2 {
                // found {{
                out.push(c);
                reading_fmt = false;
            } else if !reading_fmt {
                // found a first {
                reading_fmt = true;
                opening_brace = bytes_read - 1;
            } else {
                // found a { after finding an opening brace, error!
                out.clear();
                out.write_str("extra { found").unwrap();
                return Err(FmtError::Invalid(out));
            }
        } else if c == '}' {
            if !reading_fmt && !closing_brace {
                // found a '}' that isn't after a '{'
                closing_brace = true;
            } else if closing_brace {
                // found "}}"
                out.push(c);
                closing_brace = false;
            } else {
                // found a format string
                // discard before opening brace
                let (_, r) = remaining.split_at(opening_brace);

                // get the fmt pattern and remaining
                let (fmt_pattern, r) = r.split_at(bytes_read - opening_brace);
                remaining = r;

                // discard the braces
                let (_, fmt_pattern) = fmt_pattern.split_at(1);
                let (fmt_pattern, _) = fmt_pattern.split_at(fmt_pattern.len() - 1);
                // use the FmtChunk object to write the formatted string
                let fmt = try!(FmtChunk::from_str(fmt_pattern));
                match fmt.write(&mut out, vars) {
                    Ok(_) => {},
                    Err(err) => match ignore_missing {
                        true => write!(out, "{{{}}}", fmt_pattern).unwrap(),
                        false => return Err(err),
                    }
                }
                reading_fmt = false;
                bytes_read = 0;
            }
        } else if closing_brace {
            return Err(FmtError::Invalid("Single '}' encountered in format string".to_string()));
        } else if !reading_fmt {
            out.push(c)
        } // else we are currently reading a format string, so don't push
    }
    if closing_brace {
        return Err(FmtError::Invalid("Single '}' encountered in format string".to_string()));
    } else if reading_fmt {
        return Err(FmtError::Invalid("Expected '}' before end of string".to_string()));
    }
    out.shrink_to_fit();
    Ok(out)
}
<commit_msg>fixed identifier<commit_after>use std::str;
use std::fmt::Write;
use std::iter::Iterator;
use std::collections::HashMap;
use std::string::String;

use regex::Regex;

use types::*;

lazy_static!{
    pub static ref FMT_PAT: Regex = Regex::new(
//          1-ident    2-fill 3-align 4-sign  5-width   6-precision    7-type
        r"^([\w\d-_]+)(?::(.)?([<>^])?([+-])?([([\d]+)?(?:\.([\d]+))?([sbcdoxXneEfFgG%])?)?\z")
        .unwrap();
//          1-ident    2-fill 3-align 4-width  5-precision
    // r"^([\w\d-_]+)(?::(.)?([<>^])?([\d]+)?(?:\.([\d]+))?)?\z").unwrap();
// if align doesn't exist, width == fill + width
}

fn write_char(s: &mut String, c: char, n: usize) {
    for _ in 0..n {
        s.push(c);
    }
}

#[test]
fn test_write_char() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_char(&mut s, 'f', 3);
    assert!(s == "h fff");
}

fn write_from<'a, I>(s: &mut String, f: I, n: usize) -> usize
    where I: Iterator<Item = char>
{
    // eexaust f or run out of n, return chars written
    if n == 0 {
        return 0;
    }
    let mut n_written: usize = 0;
    for c in f {
        s.push(c);
        n_written += 1;
        if n_written == n {
            return n_written;
        }
    }
    n_written
}

#[test]
fn test_write_from() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_from(&mut s, "fff".chars(), 5);
    assert!(s == "h fff");
    write_from(&mut s, "xxxx".chars(), 2);
    assert!(s == "h fffxx");
    write_from(&mut s, "333".chars(), 3);
    assert!(s == "h fffxx333");
}

fn is_alignment_token(c: char) -> bool {
    match c {
        '=' | '<' | '^' | '>' => true,
        _ => false,
    }
}

fn is_sign_element(c: char) -> bool {
    match c {
        ' ' | '-' | '+' => true,
        _ => false,
    }
}

fn is_type_element(c: char) -> bool {
    match c {
        'b' | 'c' | 'd' | 'o' | 'x' | 'X' | 'n' |
        'e' | 'E' | 'f' | 'F' | 'g' | 'G' | '%' |
        's' | '?' => true,
        _ => false,
    }
}

// get an integer from pos, returning the number of bytes
// consumed and the integer
fn get_integer(s: &[u8], pos: usize) -> (usize, Option<i64>) {
    let (_, rest) = s.split_at(pos);
    let mut consumed: usize = 0;
    for b in rest {
        match *b as char {
            '0'...'9' => {},
            _ => break,
        };
        consumed += 1;
    }
    if consumed == 0 {
        (0, None)
    } else {
        let (intstr, _) = rest.split_at(consumed);
        let val = unsafe { // I think I can be reasonably sure that 0-9 chars are utf8 :)
            match str::from_utf8_unchecked(intstr).parse::<i64>() {
                Ok(v) => Some(v),
                Err(_) => None,
            }
        };
        (consumed, val)
    }
}

#[derive(Debug)]
/// The format struct as it is defined in the python source
struct FmtPy {
    pub fill: char,
    pub align: char,
    pub alternate: bool,
    pub sign: char,
    pub width: i64,
    pub thousands: bool,
    pub precision: i64,
    pub ty: char,
}

fn parse_like_python(rest: &str) -> Result<FmtPy> {
    /* The rest of this was pretty much strait up copied from python's format parser
        All credit goes to python source file: formatter_unicode.c
    */

    let mut format = FmtPy {
        fill: ' ',
        align: '>',
        alternate: false,
        sign: '\0',
        width: -1,
        thousands: false,
        precision: -1,
        ty: ' ',
    };
    let mut chars = rest.chars();
    let fake_fill = match chars.next() {
        Some(c) => c,
        None => return Ok(format),
    };
    let (_, rest) = rest.split_at(fake_fill.len_utf8());
    // from now on all format characters MUST be valid
    // ASCII characters (fill and identifier were the
    // only ones that weren't.
    // Therefore we can use bytes for the rest
    let mut align_specified = false;
    let mut fill_specified = false;

    let rest = rest.as_bytes();
    let end: usize = rest.len();
    let mut pos: usize = 0;

    /* If the second char is an alignment token,
        then parse the fill char */
    if end-pos >= 1 && is_alignment_token(rest[0] as char) {
        format.align = rest[0] as char;
        format.fill = fake_fill;
        fill_specified = true;
        align_specified = true;
        pos += 2;
    } else if end-pos == 0 && is_alignment_token(fake_fill) {
        format.align = fake_fill;
        pos+=1;
    }

    /* Parse the various sign options */
    if end-pos >= 1 && is_sign_element(rest[pos] as char) {
        format.sign = rest[pos] as char;
        pos+=1;
    }

    /* If the next character is #, we're in alternate mode.  This only
        applies to integers. */
    if end-pos >= 1 && rest[pos] as char == '#' {
        format.alternate = true;
        pos+=1;
    }

    /* The special case for 0-padding (backwards compat) */
    if !fill_specified && end-pos >= 1 && rest[pos] == '0' as u8 {
        format.fill = '0';
        if (!align_specified) {
            format.align = '=';
        }
        pos+=1;
    }

    // check to make sure that val is good
    let (consumed, val) = get_integer(rest, pos);
    pos += consumed;
    if consumed != 0 {
        match val {
            None => return Err(FmtError::Invalid("overflow error when parsing width".to_string())),
            Some(v) => {
                format.width = v;
            }
        }
    }

    /* Comma signifies add thousands separators */
    if end-pos > 0 && rest[pos] as char == ',' {
        format.thousands = true;
        pos+=1;
    }

    /* Parse field precision */
    if end-pos > 0 && rest[pos] as char == '.' {
        pos+=1;

        let (consumed, val) = get_integer(rest, pos);
        if consumed != 0 {
            match val {
                None => return Err(FmtError::Invalid("overflow error when parsing precision"
                                            .to_string())),
                Some(v) => {
                    format.precision = v;
                }
            }
        } else {
            /* Not having a precision after a dot is an error. */
            if (consumed == 0) {
                return Err(FmtError::Invalid("Format specifier missing precision".to_string()));
            }
        }

    }

    /* Finally, parse the type field. */
    if end-pos > 1 {
        /* More than one char remain, invalid format specifier. */
        return Err(FmtError::Invalid("Invalid format specifier".to_string()));
    }

    if end-pos == 1 {
        format.ty = rest[pos] as char;
        if !is_type_element(format.ty) {
            let mut msg = String::new();
            write!(msg, "Invalid type specifier: {:?}", format.ty).unwrap();
            return Err(FmtError::Invalid(msg));
        }
        pos+=1;
    }

    /* Do as much validating as we can, just by looking at the format
        specifier.  Do not take into account what type of formatting
        we're doing (int, float, string). */
    if format.thousands {
        match format.ty {
            'd' | 'e' | 'f' | 'g' | 'E' | 'G' |
            '%' | 'F' | '\0' => {}, /* These are allowed. See PEP 378.*/

            _ => {
                let mut msg = String::new();
                write!(msg, "Invalid comma type: {}", format.ty);
                return Err(FmtError::Invalid(msg));
            }
        }
    }
    Ok(format)
}

impl<'a> FmtChunk<'a> {
    /// create FmtChunk from format string
    pub fn from_str(s: &'a str) -> Result<FmtChunk> {
        let mut found_colon = false;
        let mut chars = s.chars();
        let mut c = match chars.next() {
            Some(':') | None => return Err(
                FmtError::Invalid("must specify identifier".to_string())),
            Some(c) => c,
        };
        let mut consumed = 0;
        // find the identifier
        loop {
            consumed += c.len_utf8();
            if c == ':' {
                found_colon = true;
                break;
            }
            c = match chars.next() {
                Some(c) => c,
                None => {
                    break;
                }
            };
        }
        let (identifier, rest) = s.split_at(consumed);
        println!("iden: {:?} rest: {:?}", identifier, rest);
        let identifier = if found_colon {
            let (i, _) = identifier.split_at(identifier.len() - 1); // get rid of ':'
            i
        } else {
            identifier
        };

        let format = try!(parse_like_python(rest));

        Ok(FmtChunk{
            identifier: identifier,
            fill: format.fill,
            align: match format.align {
                '<' => Align::Left,
                '^' => Align::Center,
                '>' => Align::Right,
                '=' => Align::Equal,
                _ => unreachable!(),
            },
            alternate: format.alternate,
            width: match format.width {
                -1 => None,
                _ => Some(format.width as usize),
            },
            thousands: format.thousands,
            precision: match format.precision {
                -1 => None,
                _ => Some(format.precision as usize),
            },
            ty: match format.ty {
                ' ' => None,
                _ => Some(format.ty),
            },
        })
    }

    /// write the formatted string to `s` and return true. If there is an error: clear `s`,
    /// write the error and return false
    pub fn write(&self, s: &mut String, vars: &'a HashMap<String, String>) -> Result<()> {
        let ref value = match vars.get(self.identifier) {
            Some(v) => v,
            None => {
                return Err(FmtError::KeyError(self.identifier.to_string()));
            }
        };
        let len = match self.precision {
            None => value.len(),
            Some(p) => {
                if p < value.len() {
                    p
                } else {
                    value.len()
                }
            }
        };
        let mut value = value.chars();
        let mut pad: usize = 0;

        match self.width {
            Some(mut width) => {
                if width > len {
                    match self.align {
                        Align::Left => pad = width - len,
                        Align::Center => {
                            width = width - len;
                            pad = width / 2;
                            write_char(s, self.fill, pad);
                            pad += width % 2;
                        }
                        Align::Right => {
                            write_char(s, self.fill, width - len);
                        }
                        Align::Equal => panic!("not yet supported"), // TODO
                    }
                }
            }
            None => {}
        }
        if self.precision.is_none() {
            s.extend(value);
        } else {
            write_from(s, &mut value, self.precision.unwrap());
        }
        write_char(s, self.fill, pad);
        Ok(())
    }
}

/// UNSTABLE: rust-style format a string given a HashMap of the variables and additional options
/// variables:
///   ignore_missing: if true, ignore missing variables
pub fn strfmt_options(fmtstr: &str, vars: &HashMap<String, String>, ignore_missing: bool) -> Result<String> {
    let mut out = String::with_capacity(fmtstr.len() * 2);
    let mut bytes_read: usize = 0;
    let mut opening_brace: usize = 0;
    let mut closing_brace: bool = false;
    let mut reading_fmt = false;
    let mut remaining = fmtstr;
    for c in fmtstr.chars() {
        bytes_read += c.len_utf8();
        if c == '{' {
            if reading_fmt && opening_brace == bytes_read - 2 {
                // found {{
                out.push(c);
                reading_fmt = false;
            } else if !reading_fmt {
                // found a first {
                reading_fmt = true;
                opening_brace = bytes_read - 1;
            } else {
                // found a { after finding an opening brace, error!
                out.clear();
                out.write_str("extra { found").unwrap();
                return Err(FmtError::Invalid(out));
            }
        } else if c == '}' {
            if !reading_fmt && !closing_brace {
                // found a '}' that isn't after a '{'
                closing_brace = true;
            } else if closing_brace {
                // found "}}"
                out.push(c);
                closing_brace = false;
            } else {
                // found a format string
                // discard before opening brace
                let (_, r) = remaining.split_at(opening_brace);

                // get the fmt pattern and remaining
                let (fmt_pattern, r) = r.split_at(bytes_read - opening_brace);
                remaining = r;

                // discard the braces
                let (_, fmt_pattern) = fmt_pattern.split_at(1);
                let (fmt_pattern, _) = fmt_pattern.split_at(fmt_pattern.len() - 1);
                // use the FmtChunk object to write the formatted string
                let fmt = try!(FmtChunk::from_str(fmt_pattern));
                match fmt.write(&mut out, vars) {
                    Ok(_) => {},
                    Err(err) => match ignore_missing {
                        true => write!(out, "{{{}}}", fmt_pattern).unwrap(),
                        false => return Err(err),
                    }
                }
                reading_fmt = false;
                bytes_read = 0;
            }
        } else if closing_brace {
            return Err(FmtError::Invalid("Single '}' encountered in format string".to_string()));
        } else if !reading_fmt {
            out.push(c)
        } // else we are currently reading a format string, so don't push
    }
    if closing_brace {
        return Err(FmtError::Invalid("Single '}' encountered in format string".to_string()));
    } else if reading_fmt {
        return Err(FmtError::Invalid("Expected '}' before end of string".to_string()));
    }
    out.shrink_to_fit();
    Ok(out)
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8),
        /* TODO: ustar */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    None
            }
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<commit_msg>parse ustart header<commit_after>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    map_res!(take!(6),   from_utf8) ~
        version:  map_res!(take!(2),   from_utf8) ~
        uname:    map_res!(take!(32),  from_utf8) ~
        gname:    map_res!(take!(32),  from_utf8) ~
        devmajor: map_res!(take!(8),   from_utf8) ~
        devminor: map_res!(take!(8),   from_utf8) ~
        prefix:   map_res!(take!(155), from_utf8),
        ||{
            match magic {
                "ustar" => Some(UStarHeader{
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8) ~
        ustar:    parse_ustar,
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<|endoftext|>


<commit_before>
#![allow(dead_code)]

bitflags! {
    flags KeyState: u8 {
        const LEFT = 0b1,
        const RIGHT = 0b10,
        const UP = 0b100,
        const DOWN = 0b1000,
    }
}

pub enum State {
    Bitten(f64),
    Normal,
}

pub struct Player {
    pub pos: [f64, ..2],
    pub vel: [f64, ..2],
    pub key_state: KeyState,
    pub time_since_last_frame_update: f64,
    pub frame: uint,
    pub state: State,
}

impl Player {
    pub fn new(pos: [f64, ..2]) -> Player {
        Player {
            pos: pos,
            vel: [0.0, 0.0],
            key_state: KeyState::empty(),
            time_since_last_frame_update: 0.0,
            frame: 0,
            state: State::Normal,
        }
    }
}

pub fn update_player(dt: f64) {
    use current_stream;
    use current_player;
    use current_rocks;
    use piston::vecmath::vec2_add as add;
    use piston::vecmath::vec2_scale as scale;
    use piston::vecmath::vec2_sub as sub;
    use piston::vecmath::vec2_len as len;
    use piston::vecmath::vec2_square_len as square_len;
    use settings::WATER_FRICTION;
    use settings::player::{ ACC, FRAME_INTERVAL, FRAMES, SPEEDUP };
    use std::num::Float;

    let dt = dt * SPEEDUP;

    let stream = &mut *current_stream();
    let player = &mut *current_player();
    let rocks = &mut *current_rocks();
    let friction = WATER_FRICTION;

    player.time_since_last_frame_update += dt;
    if player.time_since_last_frame_update > FRAME_INTERVAL {
        if player.key_state.contains(UP) {
            player.frame = (player.frame + FRAMES.len() - 1) % FRAMES.len();
        } else {
            player.frame = (player.frame + 1) % FRAMES.len();
        }
        player.time_since_last_frame_update -= FRAME_INTERVAL;
    }
    player.state = match player.state {
            State::Normal => State::Normal,
            State::Bitten(sec) => {
                let new_sec = sec - dt;
                if new_sec < 0.0 {
                    State::Normal
                } else {
                    State::Bitten(new_sec)
                }
            }
        };

    let mut acc: [f64, ..2] = [0.0, 0.0];
    if player.key_state.contains(LEFT) {
        acc[0] -= ACC;
    }
    if player.key_state.contains(RIGHT) {
        acc[0] += ACC;
    }
    if player.key_state.contains(DOWN) {
        acc[1] += ACC;
    }
    if player.key_state.contains(UP) {
        acc[1] -= ACC;
    }

    let next_vel = add(player.vel, scale(acc, dt));
    let next_vel_square_len = square_len(next_vel);
    let drag = 1.0 / (next_vel_square_len * friction).exp();
    let next_vel = scale(next_vel, drag);

    let avg_vel = scale(add(player.vel, next_vel), 0.5);
    let dir = stream.at(player.pos);
    let next_pos = add(player.pos, add(scale(dir, dt), scale(avg_vel, dt)));

    let mut hits_rock = false;
    let rock_radius = ::settings::rocks::RADIUS;
    for rock in rocks.rocks.iter() {
        let diff = sub(rock.pos, next_pos);
        if len(diff) < rock_radius {
            hits_rock = true;
            break;
        }
    }

    if !hits_rock {
        player.pos = next_pos;
    }
}
<commit_msg>Created `acceleration` method<commit_after>
#![allow(dead_code)]

bitflags! {
    flags KeyState: u8 {
        const LEFT = 0b1,
        const RIGHT = 0b10,
        const UP = 0b100,
        const DOWN = 0b1000,
    }
}

impl KeyState {
    pub fn acceleration(&self, d: f64) -> [f64, ..2] {
        let mut acc = [0.0, ..2];
        if self.contains(LEFT) {
            acc[0] -= d;
        }
        if self.contains(RIGHT) {
            acc[0] += d;
        }
        if self.contains(DOWN) {
            acc[1] += d;
        }
        if self.contains(UP) {
            acc[1] -= d;
        }
        acc
    }
}

pub enum State {
    Bitten(f64),
    Normal,
}

pub struct Player {
    pub pos: [f64, ..2],
    pub vel: [f64, ..2],
    pub key_state: KeyState,
    pub time_since_last_frame_update: f64,
    pub frame: uint,
    pub state: State,
}

impl Player {
    pub fn new(pos: [f64, ..2]) -> Player {
        Player {
            pos: pos,
            vel: [0.0, 0.0],
            key_state: KeyState::empty(),
            time_since_last_frame_update: 0.0,
            frame: 0,
            state: State::Normal,
        }
    }
}

pub fn update_player(dt: f64) {
    use current_stream;
    use current_player;
    use current_rocks;
    use piston::vecmath::vec2_add as add;
    use piston::vecmath::vec2_scale as scale;
    use piston::vecmath::vec2_sub as sub;
    use piston::vecmath::vec2_len as len;
    use piston::vecmath::vec2_square_len as square_len;
    use settings::WATER_FRICTION;
    use settings::player::{ ACC, FRAME_INTERVAL, FRAMES, SPEEDUP };
    use std::num::Float;

    let dt = dt * SPEEDUP;

    let stream = &mut *current_stream();
    let player = &mut *current_player();
    let rocks = &mut *current_rocks();
    let friction = WATER_FRICTION;

    player.time_since_last_frame_update += dt;
    if player.time_since_last_frame_update > FRAME_INTERVAL {
        if player.key_state.contains(UP) {
            player.frame = (player.frame + FRAMES.len() - 1) % FRAMES.len();
        } else {
            player.frame = (player.frame + 1) % FRAMES.len();
        }
        player.time_since_last_frame_update -= FRAME_INTERVAL;
    }
    player.state = match player.state {
            State::Normal => State::Normal,
            State::Bitten(sec) => {
                let new_sec = sec - dt;
                if new_sec < 0.0 {
                    State::Normal
                } else {
                    State::Bitten(new_sec)
                }
            }
        };

    let acc = player.key_state.acceleration(ACC);

    let next_vel = add(player.vel, scale(acc, dt));
    let next_vel_square_len = square_len(next_vel);
    let drag = 1.0 / (next_vel_square_len * friction).exp();
    let next_vel = scale(next_vel, drag);

    let avg_vel = scale(add(player.vel, next_vel), 0.5);
    let dir = stream.at(player.pos);
    let next_pos = add(player.pos, add(scale(dir, dt), scale(avg_vel, dt)));

    let mut hits_rock = false;
    let rock_radius = ::settings::rocks::RADIUS;
    for rock in rocks.rocks.iter() {
        let diff = sub(rock.pos, next_pos);
        if len(diff) < rock_radius {
            hits_rock = true;
            break;
        }
    }

    if !hits_rock {
        player.pos = next_pos;
    }
}
<|endoftext|>


<commit_before>use syntax::ast::consts::*;
use syntax::ast::op::*;
use syntax::core::tokens::Token;

pub trait CodeGen {
	// Not sure if this should return anything
	fn gen_code(&self);
}

#[derive(Debug, PartialEq)]
pub struct ExprWrapper {
	expr: Box<Expr>,
	start_line: usize,
	start_column: usize,
	end_line: usize,
	end_column: usize
}

impl CodeGen for ExprWrapper {
	fn gen_code(&self) {
		self.expr.gen_code();
	}
}

impl ExprWrapper {
	// Create an associated expression with start and end positions
	pub fn new(expr: Box<Expr>, startl: usize, startc: usize, endl: usize, endc: usize) -> ExprWrapper {
		ExprWrapper {
			expr: expr,
			start_line: startl,
			start_column: startc,
			end_line: endl,
			end_column: endc
		}
	}

	pub fn default(expr: Box<Expr>) -> ExprWrapper {
		ExprWrapper {
			expr: expr,
			start_line: 0,
			start_column: 0,
			end_line: 0,
			end_column: 0,
        }
    }

	pub fn get_expr(&self) -> &Expr {
		&self.expr
	}
}

#[derive(Debug, PartialEq)]
pub enum Expr {
	// Operations between two expressions
	NumOp(InfixOp, ExprWrapper, ExprWrapper),
	// Operation on a single expression
	UnaryOp(UnaryOp, ExprWrapper),
	// Constants such as numbers and strings
	Const(Const),
	// Run expression while conditional is true
	WhileLoop(ExprWrapper, ExprWrapper),
	// Run expression if condition true, optional elif, else
	If(ExprWrapper, ExprWrapper, Option<ExprWrapper>),
	// Assign a value to an expression
	Assign(ExprWrapper, ExprWrapper),
	// Fn call with args.
	// ToDo: Vec<Option<ExprWrapper>> for optional args?
	FnCall(ExprWrapper, Vec<ExprWrapper>),
	// Declare a function with a name, args(name, type | ident), return (type | ident), and expr
	// ToDo: Optional args
	FnDecl(String, Vec<(String, Token)>, Token, ExprWrapper),
	// Run consecutive expressions
	Block(Vec<ExprWrapper>),
	// Variable name and expression.
	// ToDo: Does this need a variable type here?
	// ToDo: A bool for whether it is const(def) or not(var)?
	VarDecl(Vec<(String, ExprWrapper)>),
	// Reference to a value in an identifier
	Ident(String),
	// Return an expression from a function
	Return(Option<ExprWrapper>),
	// A lot more to come
    NoOp,
}

impl CodeGen for Expr {
	fn gen_code(&self) {
		match *self {
			Expr::Block(ref vec) => {
				for expr in vec {
					expr.gen_code();
				}
			},
			// Codegen for others:
			_ => ()
		}
	}
}
<commit_msg>Changed tabs to spaces in expr.rs<commit_after>use syntax::ast::consts::*;
use syntax::ast::op::*;
use syntax::core::tokens::Token;

pub trait CodeGen {
    // Not sure if this should return anything
    fn gen_code(&self);
}

#[derive(Debug, PartialEq)]
pub struct ExprWrapper {
    expr: Box<Expr>,
    start_line: usize,
    start_column: usize,
    end_line: usize,
    end_column: usize
}

impl CodeGen for ExprWrapper {
    fn gen_code(&self) {
        self.expr.gen_code();
    }
}

impl ExprWrapper {
    // Create an associated expression with start and end positions
    pub fn new(expr: Box<Expr>, startl: usize, startc: usize, endl: usize, endc: usize) -> ExprWrapper {
        ExprWrapper {
            expr: expr,
            start_line: startl,
            start_column: startc,
            end_line: endl,
            end_column: endc
        }
    }

    pub fn default(expr: Box<Expr>) -> ExprWrapper {
        ExprWrapper {
            expr: expr,
            start_line: 0,
            start_column: 0,
            end_line: 0,
            end_column: 0,
        }
    }

    pub fn get_expr(&self) -> &Expr {
        &self.expr
    }
}

#[derive(Debug, PartialEq)]
pub enum Expr {
    // Operations between two expressions
    NumOp(InfixOp, ExprWrapper, ExprWrapper),
    // Operation on a single expression
    UnaryOp(UnaryOp, ExprWrapper),
    // Constants such as numbers and strings
    Const(Const),
    // Run expression while conditional is true
    WhileLoop(ExprWrapper, ExprWrapper),
    // Run expression if condition true, optional elif, else
    If(ExprWrapper, ExprWrapper, Option<ExprWrapper>),
    // Assign a value to an expression
    Assign(ExprWrapper, ExprWrapper),
    // Fn call with args.
    // ToDo: Vec<Option<ExprWrapper>> for optional args?
    FnCall(ExprWrapper, Vec<ExprWrapper>),
    // Declare a function with a name, args(name, type | ident), return (type | ident), and expr
    // ToDo: Optional args
    FnDecl(String, Vec<(String, Token)>, Token, ExprWrapper),
    // Run consecutive expressions
    Block(Vec<ExprWrapper>),
    // Variable name and expression.
    // ToDo: Does this need a variable type here?
    // ToDo: A bool for whether it is const(def) or not(var)?
    VarDecl(Vec<(String, ExprWrapper)>),
    // Reference to a value in an identifier
    Ident(String),
    // Return an expression from a function
    Return(Option<ExprWrapper>),
    // A lot more to come
    NoOp,
}

impl CodeGen for Expr {
    fn gen_code(&self) {
        match *self {
            Expr::Block(ref vec) => {
                for expr in vec {
                    expr.gen_code();
                }
            },
            // Codegen for others:
            _ => ()
        }
    }
}
<|endoftext|>