<commit_before>use std::fs::File;
use std::io;
use std::io::Write;
#[cfg(windows)]
use std::io::{Seek, SeekFrom};
use std::path::Path;
#[cfg(unix)]
use std::os::unix::fs::FileExt;
#[cfg(windows)]
use std::os::windows::fs::FileExt;

use super::{ReadAt, WriteAt};

/// A wrapper for `File` that provides optimized random access through
/// `ReadAt` and `WriteAt`.
///
/// * On Unix the operating system is advised that reads will be in random
///   order (`FADV_RANDOM`).
/// * On Windows the implementation is orders of magnitude faster than `ReadAt`
///   directly on `File`.
///
/// # Examples
///
/// Read the fifth 512-byte sector of a file:
///
/// ```
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// use positioned_io::{RandomAccessFile, ReadAt};
///
/// // open a file (note: binding does not need to be mut)
/// let raf = RandomAccessFile::open("tests/pi.txt")?;
///
/// // read up to 512 bytes
/// let mut buf = [0; 512];
/// let bytes_read = raf.read_at(2048, &mut buf)?;
/// #     assert!(buf.starts_with(b"4"));
/// #     Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
#[derive(Debug)]
pub struct RandomAccessFile {
    file: File,
    #[cfg(not(unix))]
    pos: u64,
}

impl RandomAccessFile {
    /// [Opens](https://doc.rust-lang.org/std/fs/struct.File.html#method.open)
    /// a file for random access.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<RandomAccessFile> {
        RandomAccessFile::try_new(File::open(path)?)
    }

    /// Creates a `RandomAccessFile` wrapper around a `File`.
    pub fn try_new(file: File) -> io::Result<RandomAccessFile> {
        RandomAccessFile::try_new_impl(file)
    }

    #[cfg(unix)]
    fn try_new_impl(file: File) -> io::Result<RandomAccessFile> {
        unsafe {
            use std::os::unix::io::AsRawFd;
            libc::posix_fadvise(file.as_raw_fd(), 0, file.metadata()?.len() as i64, libc::POSIX_FADV_RANDOM);
        }

        Ok(RandomAccessFile { file })
    }

    #[cfg(not(unix))]
    fn try_new_impl(file: File) -> io::Result<RandomAccessFile> {
        Ok(RandomAccessFile {
            file,
            pos: file.seek(SeekFrom::Current(0))?,
        })
    }

    /// Tries to unwrap the inner `File`.
    pub fn try_into_inner(self) -> Result<File, (RandomAccessFile, io::Error)> {
        RandomAccessFile::try_into_inner_impl(self)
    }

    #[cfg(unix)]
    fn try_into_inner_impl(self) -> Result<File, (RandomAccessFile, io::Error)> {
        Ok(self.file)
    }

    #[cfg(not(unix))]
    fn try_into_inner_impl(self) -> Result<File, (RandomAccessFile, io::Error)> {
        match self.file.seek(SeekFrom::Start(self.pos)) {
            Ok(_) => Ok(self.file),
            Err(err) => Err((self, err)),
        }
    }
}

#[cfg(unix)]
impl ReadAt for RandomAccessFile {
    #[inline]
    fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
        FileExt::read_at(&self.file, buf, pos)
    }
}

#[cfg(unix)]
impl WriteAt for RandomAccessFile {
    fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
        FileExt::write_at(&self.file, buf, pos)
    }

    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut self.file)
    }
}

#[cfg(windows)]
impl ReadAt for RandomAccessFile {
    #[inline]
    fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
        FileExt::seek_read(&self.file, pos, buf)
    }
}

#[cfg(windows)]
impl WriteAt for RandomAccessFile {
    fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
        FileExt::seek_write(&self.file, buf, pos)
    }

    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut self.file)
    }
}
<commit_msg>another blind fix for windows<commit_after>use std::fs::File;
use std::io;
use std::io::Write;
#[cfg(windows)]
use std::io::{Seek, SeekFrom};
use std::path::Path;
#[cfg(unix)]
use std::os::unix::fs::FileExt;
#[cfg(windows)]
use std::os::windows::fs::FileExt;

use super::{ReadAt, WriteAt};

/// A wrapper for `File` that provides optimized random access through
/// `ReadAt` and `WriteAt`.
///
/// * On Unix the operating system is advised that reads will be in random
///   order (`FADV_RANDOM`).
/// * On Windows the implementation is orders of magnitude faster than `ReadAt`
///   directly on `File`.
///
/// # Examples
///
/// Read the fifth 512-byte sector of a file:
///
/// ```
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// use positioned_io::{RandomAccessFile, ReadAt};
///
/// // open a file (note: binding does not need to be mut)
/// let raf = RandomAccessFile::open("tests/pi.txt")?;
///
/// // read up to 512 bytes
/// let mut buf = [0; 512];
/// let bytes_read = raf.read_at(2048, &mut buf)?;
/// #     assert!(buf.starts_with(b"4"));
/// #     Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
#[derive(Debug)]
pub struct RandomAccessFile {
    file: File,
    #[cfg(not(unix))]
    pos: u64,
}

impl RandomAccessFile {
    /// [Opens](https://doc.rust-lang.org/std/fs/struct.File.html#method.open)
    /// a file for random access.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<RandomAccessFile> {
        RandomAccessFile::try_new(File::open(path)?)
    }

    /// Creates a `RandomAccessFile` wrapper around a `File`.
    pub fn try_new(file: File) -> io::Result<RandomAccessFile> {
        RandomAccessFile::try_new_impl(file)
    }

    #[cfg(unix)]
    fn try_new_impl(file: File) -> io::Result<RandomAccessFile> {
        unsafe {
            use std::os::unix::io::AsRawFd;
            libc::posix_fadvise(file.as_raw_fd(), 0, file.metadata()?.len() as i64, libc::POSIX_FADV_RANDOM);
        }

        Ok(RandomAccessFile { file })
    }

    #[cfg(not(unix))]
    fn try_new_impl(file: File) -> io::Result<RandomAccessFile> {
        Ok(RandomAccessFile {
            file,
            pos: file.seek(SeekFrom::Current(0))?,
        })
    }

    /// Tries to unwrap the inner `File`.
    pub fn try_into_inner(self) -> Result<File, (RandomAccessFile, io::Error)> {
        RandomAccessFile::try_into_inner_impl(self)
    }

    #[cfg(unix)]
    fn try_into_inner_impl(self) -> Result<File, (RandomAccessFile, io::Error)> {
        Ok(self.file)
    }

    #[cfg(not(unix))]
    fn try_into_inner_impl(self) -> Result<File, (RandomAccessFile, io::Error)> {
        match self.file.seek(SeekFrom::Start(self.pos)) {
            Ok(_) => Ok(self.file),
            Err(err) => Err((self, err)),
        }
    }
}

#[cfg(unix)]
impl ReadAt for RandomAccessFile {
    #[inline]
    fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
        FileExt::read_at(&self.file, buf, pos)
    }
}

#[cfg(unix)]
impl WriteAt for RandomAccessFile {
    fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
        FileExt::write_at(&self.file, buf, pos)
    }

    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut self.file)
    }
}

#[cfg(windows)]
impl ReadAt for RandomAccessFile {
    #[inline]
    fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
        FileExt::seek_read(&self.file, buf, pos)
    }
}

#[cfg(windows)]
impl WriteAt for RandomAccessFile {
    fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
        FileExt::seek_write(&self.file, buf, pos)
    }

    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut self.file)
    }
}
<|endoftext|>


<commit_before>//! ROM image loading code

use std::cmp;
use std::iter;
use std::str;

/// The (decoded) SNES header
pub struct RomHeader {
    /// ASCII title, filled with spaces to 21 Bytes
    title: [u8; 21],
    rom_size: u32,
    ram_size: u32,
    checksum: u16,
    rom_type: RomType,
}

#[derive(Debug)]
enum RomType {
    LoRom,
    HiRom,
}

impl RomHeader {
    /// Loads the ROM header from the given byte slice (must be exactly 64 bytes large).
    fn load(bytes: &[u8]) -> Result<RomHeader, ()> {
        // The header size must be correct (the ROM loader won't pass a wrong size)
        assert_eq!(bytes.len(), 64);

        debug!("raw rom header: {:?}", bytes);

        // First check: Is the title valid ASCII?
        let mut title = [0; 21];
        for (i, c) in bytes[0..21].iter().enumerate() {
            match *c {
                0x20 ... 0x7E => {
                    title[i] = *c;
                }
                _ => {
                    debug!("title contains non-ascii bytes");
                    return Err(())
                }
            }
        }

        info!("loading '{}'", str::from_utf8(&title).unwrap().trim_right());

        // 21) ROM makeup byte
        // `---smmmm`
        // * `s`: Speed (0: SlowROM, 1: FastROM)
        // * `m`: Map mode
        //  * `0000`: LoROM
        //  * `0001`: HiROM
        //  * `0010`: LoROM + S-DD1
        //  * `0011`: LoROM + SA-1
        //  * `0101`: ExHiROM
        //  * `1010`: HiROM + SPC7110
        if bytes[21] & 0x10 == 0x10 {
            error!("FastROM unsupported!");
            return Err(())
        }

        let rom_type = match bytes[21] & 0x0f {
            0 => RomType::LoRom,
            1 => RomType::HiRom,
            t => {
                error!("unknown / unimplemented ROM type {}", t);
                return Err(())
            }
        };

        info!("type: {:?}", rom_type);

        // bytes[22] is the chipset info. For now, we don't care about that.
        debug!("chipset: 0x{:02X}", bytes[22]);

        let rom_size = 0x400 << bytes[23] as u32;
        let ram_size = 0x400 << bytes[24] as u32;
        debug!("ROM/RAM size values: {:02X} {:02X}", bytes[23], bytes[24]);
        info!("{} bytes of ROM, {} bytes of RAM", rom_size, ram_size);

        // bytes[25-26] is a vendor code (doesn't matter)
        debug!("vendor code: 0x{:02X}{:02X}", bytes[25], bytes[26]);
        // 27 = version (also doesn't matter for us)
        debug!("version: 0x{:02X}", bytes[27]);

        // Now it's getting a bit more interesting: The next byte is the checksum's complement
        // followed by the checksum itself. The checksum is the sum of all bytes in the ROM
        // (truncated to 16 bits). It can be validated by the loader.
        // 16 bit, little-endian.
        let check_inv = (bytes[29] as u16) << 8 | bytes[28] as u16;
        let checksum = (bytes[31] as u16) << 8 | bytes[30] as u16;
        if check_inv != !checksum {
            error!("checksum invalid: stored complement is {:04X}, stored checksum is {:04X}",
                check_inv, checksum);
            return Err(())
        }

        Ok(RomHeader {
            title: title,
            rom_size: rom_size,
            ram_size: ram_size,
            checksum: checksum,
            rom_type: rom_type,
        })
    }
}

/// A ROM image
pub struct Rom {
    header: RomHeader,
    ram: Vec<u8>,
    rom: Vec<u8>,
}

impl Rom {
    /// Loads a ROM from raw data.
    pub fn from_bytes(mut bytes: &[u8]) -> Result<Rom, ()> {
        // FIXME Return a proper error!

        debug!("raw size: {} bytes ({:#X})", bytes.len(), bytes.len());

        // ROMs may begin with a 512 Bytes SMC header. It needs to go.
        match bytes.len() % 1024 {
            512 => {
                debug!("stripping SMC header");
                bytes = &bytes[512..];
            }
            0 => {},
            n => panic!("len() % 1024 == {} (expected 512 or 0)", n),
        }

        // Read the SNES header. It is located in a really stupid location which depends on whether
        // the ROM is HiROM or LoROM, so we must check both locations and pick the right one.
        // LoROM header is at 0x7FFF - 63, HiROM is at 0xFFFF - 63 (it is 64 Bytes large)

        // Test LoROM first (it's more common)
        let header = try!(RomHeader::load(&bytes[0x7FFF - 63..0x7FFF + 1])
            .or_else(|_| RomHeader::load(&bytes[0xFFFF - 63..0xFFFF + 1])));

        // Calculate the ROM's checksum
        let mut checksum: u16 = 0;
        for &byte in bytes {
            checksum = checksum.wrapping_add(byte as u16);
        }

        debug!("computed checksum: {:04X}", checksum);

        if header.checksum != checksum {
            warn!("incorrect checksum: computed ${:04X}, expected ${:04X}",
                checksum, header.checksum);
        }

        if bytes.len() != header.rom_size as usize {
            warn!("raw ROM is {} bytes, but header specifies {} bytes (we'll fill up with 0)",
                bytes.len(), header.rom_size);
        }

        // Create the right amount of RAM...
        let ram = vec![0; header.ram_size as usize];
        // ...and copy the ROM
        let rom = bytes.iter().cloned().chain(iter::repeat(0))
            .take(cmp::max(header.rom_size as usize, bytes.len())).collect();

        Ok(Rom {
            header: header,
            ram: ram,
            rom: rom,
        })
    }

    fn resolve_lorom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        // XXX I fear that this can cause the worst bugs, so make sure this is 100% correct!!!

        match addr {
            0x0000 ... 0x7fff => {
                // Cartridge RAM mapped to the low 8 pages
                // (there's other stuff here, but that's handled much earlier than we are called)
                match bank {
                    0x70 ... 0x7d => {
                        let a = (bank as u32 - 0x70) * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    0xfe ... 0xff => {
                        // last 64k of RAM
                        let start = self.ram.len() as u32 - 64 * 1024;
                        let a = start + (bank - 0xfe) as u32 * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    _ => {
                        // 0x40 ... 0x6f | 0x7e ... 0xfd
                        panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr);
                    }
                }
            },
            0x8000 ... 0xffff => match bank {
                // LoROM is mapped to the higher 8 pages
                0xfe => {
                    let a = 0x3f0000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0xff => {
                    let a = 0x3f8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0x80 ... 0xfd | 0x00 ... 0x7d => {
                    // `& !0x80` because 0x80-0xFD mirrors 0x00-0x7D
                    let a = (bank as u32 & !0x80) * 0x8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                _ => panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr)
            },
            _ => unreachable!()
        }
    }

    fn resolve_addr(&mut self, bank: u8, addr: u16) -> &mut u8 {
        match self.header.rom_type {
            RomType::LoRom => self.resolve_lorom(bank, addr),
            RomType::HiRom => unimplemented!(),
        }
    }
}

impl Rom {
    pub fn loadb(&mut self, bank: u8, addr: u16) -> u8 {
        *self.resolve_addr(bank, addr)
    }

    pub fn storeb(&mut self, bank: u8, addr: u16, value: u8) {
        if addr >= 0x8000 {
            panic!("attempted to write ${:02X} to ROM (${:02X}:{:04X})", value, bank, addr);
        }
        *self.resolve_addr(bank, addr) = value;
    }
}

fn out_of_ram_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("RAM access out of bounds at {:02X}:{:04X} -> {:04X}",
        bank, addr, abs)
}

fn out_of_rom_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("LoROM access out of bounds at {:02X}:{:04X} -> {:06X}",
        bank, addr, abs)
}
<commit_msg>HiROM support<commit_after>//! ROM image loading code

use std::cmp;
use std::iter;
use std::str;

/// The (decoded) SNES header
pub struct RomHeader {
    /// ASCII title, filled with spaces to 21 Bytes
    title: [u8; 21],
    rom_size: u32,
    ram_size: u32,
    checksum: u16,
    rom_type: RomType,
}

#[derive(Debug, PartialEq, Eq)]
enum RomType {
    LoRom,
    HiRom,
}

impl RomHeader {
    /// Loads the ROM header from the given byte slice (must be exactly 64 bytes large).
    /// `rom_type` is the expected type of the ROM header, based on its location. It will be
    /// used for the actual type if the type inside the header mismatches. This is apparently
    /// required for some broken ROMs.
    fn load(bytes: &[u8], rom_type: RomType) -> Result<RomHeader, ()> {
        // The header size must be correct (the ROM loader won't pass a wrong size)
        assert_eq!(bytes.len(), 64);

        debug!("raw rom header: {:?}", bytes);

        // First check: Is the title valid ASCII?
        let mut title = [0; 21];
        for (i, c) in bytes[0..21].iter().enumerate() {
            match *c {
                0x20 ... 0x7E => {
                    title[i] = *c;
                }
                _ => {
                    debug!("title contains non-ascii bytes");
                    return Err(())
                }
            }
        }

        info!("loading '{}'", str::from_utf8(&title).unwrap().trim_right());

        // 21) ROM makeup byte
        // `---smmmm`
        // * `s`: Speed (0: SlowROM, 1: FastROM)
        // * `m`: Map mode
        //  * `0000`: LoROM
        //  * `0001`: HiROM
        //  * `0010`: LoROM + S-DD1
        //  * `0011`: LoROM + SA-1
        //  * `0101`: ExHiROM
        //  * `1010`: HiROM + SPC7110
        if bytes[21] & 0x10 == 0x10 {
            warn!("FastROM not yet implemented!");
        }

        let header_rom_type = match bytes[21] & 0x0f {
            0 => RomType::LoRom,
            1 => RomType::HiRom,
            t => {
                error!("unknown / unimplemented ROM type {}", t);
                return Err(())
            }
        };

        if header_rom_type == rom_type {
            info!("type: {:?}", rom_type);
        } else {
            warn!("expected rom type {:?}, got {:?} (assuming {:?})", rom_type, header_rom_type,
                rom_type);
        }

        // bytes[22] is the chipset info. For now, we don't care about that.
        debug!("chipset: 0x{:02X}", bytes[22]);

        let rom_size = 0x400 << bytes[23] as u32;
        let ram_size = 0x400 << bytes[24] as u32;
        debug!("ROM/RAM size values: {:02X} {:02X}", bytes[23], bytes[24]);
        info!("{} KB of ROM, {} KB of RAM", rom_size / 1024, ram_size / 1024);

        // bytes[25-26] is a vendor code (doesn't matter)
        debug!("vendor code: 0x{:02X}{:02X}", bytes[25], bytes[26]);
        // 27 = version (also doesn't matter for us)
        debug!("version: 0x{:02X}", bytes[27]);

        // Now it's getting a bit more interesting: The next byte is the checksum's complement
        // followed by the checksum itself. The checksum is the sum of all bytes in the ROM
        // (truncated to 16 bits). It can be validated by the loader.
        // 16 bit, little-endian.
        let check_inv = (bytes[29] as u16) << 8 | bytes[28] as u16;
        let checksum = (bytes[31] as u16) << 8 | bytes[30] as u16;
        if check_inv != !checksum {
            error!("checksum invalid: stored complement is {:04X}, stored checksum is {:04X}",
                check_inv, checksum);
            return Err(())
        }

        Ok(RomHeader {
            title: title,
            rom_size: rom_size,
            ram_size: ram_size,
            checksum: checksum,
            rom_type: rom_type,
        })
    }
}

/// A ROM image
pub struct Rom {
    header: RomHeader,
    ram: Vec<u8>,
    rom: Vec<u8>,
}

impl Rom {
    /// Loads a ROM from raw data.
    pub fn from_bytes(mut bytes: &[u8]) -> Result<Rom, ()> {
        // FIXME Return a proper error!

        debug!("raw size: {} bytes ({:#X})", bytes.len(), bytes.len());

        // ROMs may begin with a 512 Bytes SMC header. It needs to go.
        match bytes.len() % 1024 {
            512 => {
                debug!("stripping SMC header");
                bytes = &bytes[512..];
            }
            0 => {},
            n => panic!("len() % 1024 == {} (expected 512 or 0)", n),
        }

        // Read the SNES header. It is located in a really stupid location which depends on whether
        // the ROM is HiROM or LoROM, so we must check both locations and pick the right one.
        // LoROM header is at 0x7FFF - 63, HiROM is at 0xFFFF - 63 (it is 64 Bytes large)

        // Test LoROM first (it's more common)
        let header = try!(RomHeader::load(&bytes[0x7FFF - 63..0x7FFF + 1], RomType::LoRom)
            .or_else(|_| RomHeader::load(&bytes[0xFFFF - 63..0xFFFF + 1], RomType::HiRom)));

        if bytes.len() != header.rom_size as usize {
            warn!("raw ROM is {} KB, but header specifies {} KB",
                bytes.len() / 1024, header.rom_size / 1024);
        }

        // Create the right amount of RAM...
        let ram = vec![0; header.ram_size as usize];
        // ...and copy the ROM
        let rom = bytes.iter().cloned().cycle()
            .take(cmp::max(header.rom_size as usize, bytes.len())).collect();

        // Calculate the ROM's checksum
        let mut checksum: u16 = 0;
        for &byte in &rom {
            checksum = checksum.wrapping_add(byte as u16);
        }

        debug!("computed checksum: ${:04X}", checksum);

        if header.checksum != checksum {
            warn!("incorrect checksum: computed ${:04X}, expected ${:04X}",
                checksum, header.checksum);
        }

        Ok(Rom {
            header: header,
            ram: ram,
            rom: rom,
        })
    }

    fn resolve_lorom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        // XXX I fear that this can cause the worst bugs, so make sure this is 100% correct!!!

        match addr {
            0x0000 ... 0x7fff => {
                // Cartridge RAM mapped to the low 32 KB
                // (there's other stuff here, but that's handled much earlier than we are called)
                match bank {
                    0x70 ... 0x7d => {
                        let a = (bank as u32 - 0x70) * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    0xfe ... 0xff => {
                        // last 64k of RAM
                        let start = self.ram.len() as u32 - 64 * 1024;
                        let a = start + (bank - 0xfe) as u32 * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    _ => {
                        // 0x40 ... 0x6f | 0x7e ... 0xfd
                        panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr);
                    }
                }
            },
            0x8000 ... 0xffff => match bank {
                // LoROM is mapped to the higher 8 pages
                0xfe => {
                    let a = 0x3f0000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0xff => {
                    let a = 0x3f8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0x80 ... 0xfd | 0x00 ... 0x7d => {
                    // `& !0x80` because 0x80-0xFD mirrors 0x00-0x7D
                    let a = (bank as u32 & !0x80) * 0x8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                _ => panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr)
            },
            _ => unreachable!()
        }
    }

    fn resolve_hirom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        let addr = addr as usize;
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf if addr >= 0x8000 => {
                &mut self.rom[(bank as usize & 0x3f) << 16 | addr]
            }
            0x20 ... 0x3f | 0xa0 ... 0xbf if addr >= 0x6000 && addr <= 0x7fff => {
                let a = ((bank as usize & 0x3f) - 0x20) * 0x2000 + (addr - 0x6000);
                &mut self.ram[a]
            }
            0x40 ... 0x7d | 0xc0 ... 0xfd => {
                &mut self.rom[((bank as usize & 0x7f) - 0x40) << 16 | addr]
            }
            0x7e ... 0x7f => unreachable!(),    // WRAM banks
            0xfe ... 0xff => {
                &mut self.rom[(bank as usize - 0xfe + 0x3e) << 16 | addr]
            }
            _ => panic!("attempted to access unmapped address: ${:02}:{:04X}", bank, addr),
        }
    }

    fn resolve_addr(&mut self, bank: u8, addr: u16) -> &mut u8 {
        match self.header.rom_type {
            RomType::LoRom => self.resolve_lorom(bank, addr),
            RomType::HiRom => self.resolve_hirom(bank, addr),
        }
    }
}

impl Rom {
    pub fn loadb(&mut self, bank: u8, addr: u16) -> u8 {
        *self.resolve_addr(bank, addr)
    }

    pub fn storeb(&mut self, bank: u8, addr: u16, value: u8) {
        if addr >= 0x8000 {
            panic!("attempted to write ${:02X} to ROM (${:02X}:{:04X})", value, bank, addr);
        }
        *self.resolve_addr(bank, addr) = value;
    }
}

fn out_of_ram_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("RAM access out of bounds at {:02X}:{:04X} -> {:04X}",
        bank, addr, abs)
}

fn out_of_rom_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("LoROM access out of bounds at {:02X}:{:04X} -> {:06X}",
        bank, addr, abs)
}
<|endoftext|>


<commit_before>use socket::Socket;

pub struct Data {
    socket: Socket,
}

impl Data {
    pub fn new(socket: Socket) -> Self {
        Data {
            socket: socket,
        }
    }

    pub fn get_write_pointer(&mut self) -> u32 {
        self.socket.send("ACQ:WPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn get_trigger_position(&mut self) -> u32 {
        self.socket.send("ACQ:TPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn set_units(&mut self, unit: &str) {
        self.socket.send(format!("ACQ:DATA:UNITS {}", unit));
    }

    pub fn set_format(&mut self, format: &str) {
        self.socket.send(format!("ACQ:DATA:FORMAT {}", format));
    }

    pub fn read_slice(&mut self, source: u8, start: u32, end: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:END? {},{}", source, start, end));

        self.socket.receive()
    }

    pub fn read(&mut self, source: u8, start: u32, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:N? {},{}", source, start, len));

        self.socket.receive()
    }

    pub fn read_all(&mut self, source: u8) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA?", source));

        self.socket.receive()
    }

    pub fn read_oldest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:OLD:N? {}", source, len));

        self.socket.receive()
    }

    pub fn read_latest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:LAT:N? {}", source, len));

        self.socket.receive()
    }

    pub fn buffer_size(&mut self) -> u32 {
        self.socket.send("ACQ:BUF:SIZE?");

        self.socket.receive()
            .parse()
            .unwrap()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_get_write_pointer() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_write_pointer(), 1024);
    }

    #[test]
    fn test_get_write_pointer_at_trigger() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_trigger_position(), 512);
    }

    #[test]
    fn test_set_units() {
        let (rx, mut data) = create_data();

        data.set_units("VOLTS");
        assert_eq!("ACQ:DATA:UNITS VOLTS\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_format() {
        let (rx, mut data) = create_data();

        data.set_format("FLOAT");
        assert_eq!("ACQ:DATA:FORMAT FLOAT\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_read_slice() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_slice(1, 10, 13), "{123,231,-231}");
    }

    #[test]
    fn test_read() {
        let (_, mut data) = create_data();

        assert_eq!(data.read(1, 10, 3), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_all() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_all(1), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_oldest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_oldest(1, 2), "{3.2,-1.2}");
    }

    #[test]
    fn test_read_latest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_latest(1, 2), "{1.2,3.2}");
    }

    #[test]
    fn test_buffer_size() {
        let (_, mut data) = create_data();

        assert_eq!(data.buffer_size(), 16384);
    }

    fn create_data() -> (::std::sync::mpsc::Receiver<String>, ::data::Data) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::data::Data::new(socket))
    }
}
<commit_msg>[data] Add data::Unit enum<commit_after>use socket::Socket;

pub enum Unit {
    RAW,
    VOLTS,
}

impl ::std::fmt::Display for Unit {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Unit::RAW => "RAW",
            &Unit::VOLTS => "VOLTS",
        };

        write!(f, "{}", display)
    }
}

pub struct Data {
    socket: Socket,
}

impl Data {
    pub fn new(socket: Socket) -> Self {
        Data {
            socket: socket,
        }
    }

    pub fn get_write_pointer(&mut self) -> u32 {
        self.socket.send("ACQ:WPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn get_trigger_position(&mut self) -> u32 {
        self.socket.send("ACQ:TPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn set_units(&mut self, unit: Unit) {
        self.socket.send(format!("ACQ:DATA:UNITS {}", unit));
    }

    pub fn set_format(&mut self, format: &str) {
        self.socket.send(format!("ACQ:DATA:FORMAT {}", format));
    }

    pub fn read_slice(&mut self, source: u8, start: u32, end: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:END? {},{}", source, start, end));

        self.socket.receive()
    }

    pub fn read(&mut self, source: u8, start: u32, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:N? {},{}", source, start, len));

        self.socket.receive()
    }

    pub fn read_all(&mut self, source: u8) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA?", source));

        self.socket.receive()
    }

    pub fn read_oldest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:OLD:N? {}", source, len));

        self.socket.receive()
    }

    pub fn read_latest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:LAT:N? {}", source, len));

        self.socket.receive()
    }

    pub fn buffer_size(&mut self) -> u32 {
        self.socket.send("ACQ:BUF:SIZE?");

        self.socket.receive()
            .parse()
            .unwrap()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_get_write_pointer() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_write_pointer(), 1024);
    }

    #[test]
    fn test_get_write_pointer_at_trigger() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_trigger_position(), 512);
    }

    #[test]
    fn test_set_units() {
        let (rx, mut data) = create_data();

        data.set_units(::data::Unit::VOLTS);
        assert_eq!("ACQ:DATA:UNITS VOLTS\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_format() {
        let (rx, mut data) = create_data();

        data.set_format("FLOAT");
        assert_eq!("ACQ:DATA:FORMAT FLOAT\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_read_slice() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_slice(1, 10, 13), "{123,231,-231}");
    }

    #[test]
    fn test_read() {
        let (_, mut data) = create_data();

        assert_eq!(data.read(1, 10, 3), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_all() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_all(1), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_oldest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_oldest(1, 2), "{3.2,-1.2}");
    }

    #[test]
    fn test_read_latest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_latest(1, 2), "{1.2,3.2}");
    }

    #[test]
    fn test_buffer_size() {
        let (_, mut data) = create_data();

        assert_eq!(data.buffer_size(), 16384);
    }

    fn create_data() -> (::std::sync::mpsc::Receiver<String>, ::data::Data) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::data::Data::new(socket))
    }
}
<|endoftext|>


<commit_before>use nom;
use nom::IResult::*;

use helper::*;
use super::{Date,Time,DateTime};

use macros::{take_2_digits,take_4_digits};

named!(sign, alt!(tag!("+") | tag!("-")));
named!(numeric_sign <&[u8], i32>, map!(sign, |s: &[u8]| {
    match s {
        b"-" => -1,
        _ => 1,
    }
}));

named!(positive_year  <&[u8], i32>, map!(call!(take_4_digits), buf_to_i32));
named!(pub year <&[u8], i32>, chain!(
        pref: opt!(numeric_sign) ~
        y: positive_year
        ,
        || {
            pref.unwrap_or(1) * y
        }));

named!(pub month <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub day   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub date <&[u8], Date>, chain!(
        y: year ~ tag!("-") ~ m: month ~ tag!("-") ~ d: day
        , || { Date{ year: y, month: m, day: d }
        }
        ));

named!(pub hour   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub minute <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub second <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(chain!(
                tag!(":") ~ s:second , || { s }))
        ,
        || { Time{ hour: h,
                   minute: m,
                   second: s.unwrap_or(0),
                   tz_offset: 0 }
           }
        ));

named!(timezone_hour <&[u8], i32>, chain!(
        s: numeric_sign ~
        h: hour ~
        m: empty_or!(
            chain!(
                tag!(":")? ~ m: minute , || { m }
            ))
        ,
        || { (s * (h as i32) * 3600) + (m.unwrap_or(0) * 60) as i32 }
        ));

named!(tag_z, tag!("Z"));
named!(timezone_utc <&[u8], i32>, map!(tag_z, |_| 0));
named!(timezone <&[u8], i32>, alt!(timezone_utc | timezone_hour));

named!(pub datetime <&[u8], DateTime>, chain!(
        d: date ~
        tag!("T") ~
        t: time ~
        tzo: empty_or!(call!(timezone))
        ,
        || {
            DateTime{
                date: d,
                time: t.set_tz(tzo.unwrap_or(0)),
            }
        }
        ));
<commit_msg>Directly map to value in alt parser<commit_after>use nom;
use nom::IResult::*;

use helper::*;
use super::{Date,Time,DateTime};

use macros::{take_2_digits,take_4_digits};

named!(sign <&[u8], i32>, alt!(
        tag!("-") => { |_| -1 } |
        tag!("+") => { |_| 1 }
        )
    );

named!(positive_year  <&[u8], i32>, map!(call!(take_4_digits), buf_to_i32));
named!(pub year <&[u8], i32>, chain!(
        pref: opt!(sign) ~
        y: positive_year
        ,
        || {
            pref.unwrap_or(1) * y
        }));

named!(pub month <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub day   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub date <&[u8], Date>, chain!(
        y: year ~ tag!("-") ~ m: month ~ tag!("-") ~ d: day
        , || { Date{ year: y, month: m, day: d }
        }
        ));

named!(pub hour   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub minute <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub second <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(chain!(
                tag!(":") ~ s:second , || { s }))
        ,
        || { Time{ hour: h,
                   minute: m,
                   second: s.unwrap_or(0),
                   tz_offset: 0 }
           }
        ));

named!(timezone_hour <&[u8], i32>, chain!(
        s: sign ~
        h: hour ~
        m: empty_or!(
            chain!(
                tag!(":")? ~ m: minute , || { m }
            ))
        ,
        || { (s * (h as i32) * 3600) + (m.unwrap_or(0) * 60) as i32 }
        ));

named!(tag_z, tag!("Z"));
named!(timezone_utc <&[u8], i32>, map!(tag_z, |_| 0));
named!(timezone <&[u8], i32>, alt!(timezone_utc | timezone_hour));

named!(pub datetime <&[u8], DateTime>, chain!(
        d: date ~
        tag!("T") ~
        t: time ~
        tzo: empty_or!(call!(timezone))
        ,
        || {
            DateTime{
                date: d,
                time: t.set_tz(tzo.unwrap_or(0)),
            }
        }
        ));
<|endoftext|>


<commit_before>use ast::{Ast, AstTrait};
use token::{TokenTrait, Type};

pub struct Eval {
    ast: Ast,
    stack: Vec<(Ast, usize)>,
    evaluated: bool
}

pub trait EvalTrait {
    fn eval(&mut self);
    fn is_evaluated(&self) -> bool;
}

pub trait PrettyPrint {
    fn pretty_print(&mut self) -> String;
    fn push_whitespace(&self, pretty: &mut String);
}

impl PrettyPrint for Eval {
    fn push_whitespace(&self, pretty: &mut String) {
        for _ in 0..self.stack.len() {
            pretty.push('\t');
        }
    }

    fn pretty_print(&mut self) -> String {
        let mut pretty = String::new();
        loop {
            match self.stack.pop() {
                Some(mut current) => {
                    match current.0.get_child(0) {
                        Some(mut child) => {
                            self.stack.push(current);
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => {
                            if current.0.node_val.is_some() {
                                let tok = current.0.node_val.unwrap();
                                self.push_whitespace(&mut pretty);
                                if tok.tok_type == Type::Oparen {
                                    pretty.push(')');
                                } else if tok.tok_type == Type::OpenList {
                                    pretty.push('>');
                                } else {
                                    pretty.push_str(&tok.get_lexed());
                                }
                            }
                            pretty.push('\n');
                        }
                    }
                },
                None => {
                    match self.ast.get_child(0) {
                        Some(mut child) => {
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => break
                    }
                }
            }
            if self.stack.is_empty() && self.ast.child_count() == 0 {
                break;
            }
        }
        pretty
    }
}

impl EvalTrait for Eval {
    fn eval(&mut self) {
        let mut scope = Scope::new_root();
        while !self.evaluated {
            scope = self.eval_node(scope);
        }
    }

    fn is_evaluated(&self) -> bool {
        self.evaluated
    }
}

impl Eval {
    pub fn new(ast: Ast) -> Self {
        Eval {
            ast: ast,
            stack: Vec::new(),
            evaluated: false
        }
    }

    pub fn new_option(ast: Option<Ast>) -> Self {
        match ast {
            Some(tree) => Eval {
                ast: tree,
                stack: Vec::new(),
                evaluated: false
            },
            None => panic!()
        }
    }

    fn eval_node(&mut self, mut scope: Scope) -> Scope {
        match self.stack.pop() {
            Some(mut current) => {
                match current.0.get_child(0) {
                    Some(mut child) => {
                        self.stack.push(current);

                        // if child.node_val.is_some() {
                        //     let tok = child.node_val.unwrap();
                        //     if tok.tok_type == Type::Oparen {
                        //         self.push_whitespace(&mut pretty);
                        //         pretty.push('(');
                        //         pretty.push('\n');
                        //     } else if tok.tok_type == Type::ListDelimiter {
                        //         self.push_whitespace(&mut pretty);
                        //         pretty.push('|');
                        //         pretty.push('\n');
                        //     }
                        //     child.node_val = Some(tok);
                        // }

                        self.stack.push((child, 0));
                    },
                    None => {
                        match self.stack.pop() {
                            Some(mut parent) => {
                                let new_index = current.1 + 1;
                                parent.0.insert_child(current.0, current.1);
                                match parent.0.child_count() > new_index {
                                    true => {
                                        let new_child = parent.0.get_child(new_index);
                                        self.stack.push(parent);
                                        self.stack.push((new_child.unwrap(), new_index));
                                    },
                                    false => {
                                        self.stack.push(parent);
                                        scope.evaluate_scope = true;
                                    }
                                }
                            },
                            None => self.evaluated = true
                        }
                    }
                }
            },
            None => {
                match self.ast.get_child(0) {
                    Some(mut child) => {
                        // if child.node_val.is_some() {
                        //     let tok = child.node_val.unwrap();
                        //     if tok.tok_type == Type::Oparen {
                        //         self.push_whitespace(&mut pretty);
                        //         pretty.push('(');
                        //         pretty.push('\n');
                        //     } else if tok.tok_type == Type::ListDelimiter {
                        //         self.push_whitespace(&mut pretty);
                        //         pretty.push('|');
                        //         pretty.push('\n');
                        //     }
                        //     child.node_val = Some(tok);
                        // }
                        self.stack.push((child, 0));
                    },
                    None => self.evaluated = true
                }
            }
        }
        if self.stack.is_empty() && self.ast.child_count() == 0 {
            self.evaluated = true;
        }
        scope
    }
}

struct Scope {
    pub parent: Option<Box<Scope>>,
    funcs: Vec<Ast>,
    in_builtin: bool,
    pub evaluate_scope: bool
}

impl Scope {
    pub fn new(parent: Scope) -> Self {
        Scope {
            parent: Some(Box::new(parent)),
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }

    pub fn new_root() -> Self {
        Scope {
            parent: None,
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }
}
<commit_msg>I believe that I am mostly done. I just need to write the scope functions and the function expansion and evaluation functions.<commit_after>use ast::{Ast, AstTrait};
use token::{TokenTrait, Type};

pub struct Eval {
    ast: Ast,
    stack: Vec<(Ast, usize)>,
    evaluated: bool
}

pub trait EvalTrait {
    fn eval(&mut self);
    fn is_evaluated(&self) -> bool;
}

pub trait PrettyPrint {
    fn pretty_print(&mut self) -> String;
    fn push_whitespace(&self, pretty: &mut String);
}

impl PrettyPrint for Eval {
    fn push_whitespace(&self, pretty: &mut String) {
        for _ in 0..self.stack.len() {
            pretty.push('\t');
        }
    }

    fn pretty_print(&mut self) -> String {
        let mut pretty = String::new();
        loop {
            match self.stack.pop() {
                Some(mut current) => {
                    match current.0.get_child(0) {
                        Some(mut child) => {
                            self.stack.push(current);
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => {
                            if current.0.node_val.is_some() {
                                let tok = current.0.node_val.unwrap();
                                self.push_whitespace(&mut pretty);
                                if tok.tok_type == Type::Oparen {
                                    pretty.push(')');
                                } else if tok.tok_type == Type::OpenList {
                                    pretty.push('>');
                                } else {
                                    pretty.push_str(&tok.get_lexed());
                                }
                            }
                            pretty.push('\n');
                        }
                    }
                },
                None => {
                    match self.ast.get_child(0) {
                        Some(mut child) => {
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => break
                    }
                }
            }
            if self.stack.is_empty() && self.ast.child_count() == 0 {
                break;
            }
        }
        pretty
    }
}

impl EvalTrait for Eval {
    fn eval(&mut self) {
        let mut scope = Scope::new_root();
        while !self.evaluated {
            scope = self.eval_node(scope); // If scope says evaluate, evaluate.
        }
    }

    fn is_evaluated(&self) -> bool {
        self.evaluated
    }
}

impl Eval {
    pub fn new(ast: Ast) -> Self {
        Eval {
            ast: ast,
            stack: Vec::new(),
            evaluated: false
        }
    }

    pub fn new_option(ast: Option<Ast>) -> Self {
        match ast {
            Some(tree) => Eval {
                ast: tree,
                stack: Vec::new(),
                evaluated: false
            },
            None => panic!()
        }
    }

    fn expand_function(&mut self, scope: &Scope) {

    }

    fn eval_node(&mut self, mut scope: Scope) -> Scope {
        match self.stack.pop() {
            Some(mut current) => {
                match current.0.get_child(0) {
                    Some(mut child) => {
                        self.stack.push(current);
                        if child.node_val.is_some() {
                            let tok = child.node_val.unwrap();
                            if tok.tok_type == Type::Func {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                                self.expand_function(&scope);
                            } else {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                            }
                        } else {
                            self.stack.push((child, 0));
                        }
                    },
                    None => {
                        match self.stack.pop() {
                            Some(mut parent) => {
                                let new_index = current.1 + 1;
                                parent.0.insert_child(current.0, current.1);
                                match parent.0.child_count() > new_index {
                                    true => {
                                        let new_child = parent.0.get_child(new_index);
                                        self.stack.push(parent);
                                        self.stack.push((new_child.unwrap(), new_index));
                                    },
                                    false => {
                                        self.stack.push(parent);
                                        scope.evaluate_scope = true;
                                    }
                                }
                            },
                            None => self.evaluated = true
                        }
                    }
                }
            },
            None => {
                match self.ast.get_child(0) {
                    Some(mut child) => {
                        if child.node_val.is_some() {
                            let tok = child.node_val.unwrap();
                            if tok.tok_type == Type::Func {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                                self.expand_function(&scope);
                            } else {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                            }
                        } else {
                            self.stack.push((child, 0));
                        }
                    },
                    None => self.evaluated = true
                }
            }
        }
        if self.stack.is_empty() && self.ast.child_count() == 0 {
            self.evaluated = true;
        }
        scope
    }
}

struct Scope {
    pub parent: Option<Box<Scope>>,
    funcs: Vec<Ast>,
    in_builtin: bool,
    pub evaluate_scope: bool
}

impl Scope {
    pub fn new(parent: Scope) -> Self {
        Scope {
            parent: Some(Box::new(parent)),
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }

    pub fn new_root() -> Self {
        Scope {
            parent: None,
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }
}
<|endoftext|>


<commit_before>use table::{TableRow, TableHeader, Table};
use definitions::{ResultColumn, RusqlStatement, InsertDef, SelectDef};
use definitions::{AlterTableDef, AlterTable, Expression, FromClause, JoinOperator};
use definitions::{DeleteDef, InsertDataSource, UpdateDef, Order, JoinConstraint};
use definitions::{BinaryOperator};
use expressions::{ExpressionResult, ExpressionEvaluator, expr_to_literal, result_to_literal};
use rusql::Rusql;

peg_file! parser("sql.rustpeg");

pub fn rusql_exec<F: FnMut(&TableRow, &TableHeader)>(db: &mut Rusql, sql_str: &str, mut callback: F) -> Option<Table> {
    match parser::rusql_parse(sql_str) {
        Ok(res) => {
            for stmt in res.into_iter() {
                match stmt {
                    RusqlStatement::AlterTable(alter_table_def) => alter_table(db, alter_table_def),
                    RusqlStatement::CreateTable(table_def) => db.create_table(table_def),
                    RusqlStatement::Delete(delete_def) => delete(db, delete_def),
                    RusqlStatement::DropTable(drop_table_def) => db.drop_table(&drop_table_def.name),
                    RusqlStatement::Insert(insert_def) => insert(db, insert_def),
                    RusqlStatement::Select(select_def) => return Some(select(db, select_def, callback)),
                    RusqlStatement::Update(update_def) => update(db, update_def),
                }
            }
        }
        Err(e) => println!("syntax error: {}", e),
    }
    None
}

fn alter_table(db: &mut Rusql, alter_table_def: AlterTableDef) {
    match alter_table_def.mode {
        AlterTable::RenameTo(new_name) => db.rename_table(&alter_table_def.name, new_name),
        AlterTable::AddColumn(column_def) => db.get_mut_table(&alter_table_def.name)
                                               .add_column(column_def),
    }
}

fn delete(db: &mut Rusql, delete_def: DeleteDef) {
    let table = db.get_mut_table(&delete_def.name);

    if let Some(ref expr) = delete_def.where_expr {
        // FIXME just making the borrow checker happy...
        let header = table.header.clone();
        table.delete_where(|row| ExpressionEvaluator::new(row, &header).eval_bool(expr));
    } else {
        table.clear();
    }
}

fn insert(db: &mut Rusql, insert_def: InsertDef) {
    match insert_def.data_source {
        InsertDataSource::Values(column_data) => {
            let mut table = db.get_mut_table(&insert_def.table_name);
            table.insert(column_data, &insert_def.column_names);
        }
        InsertDataSource::Select(select_def) => {
            let results_table = select(db, select_def, |_,_| {});
            let mut table = db.get_mut_table(&insert_def.table_name);

            for (_, row) in results_table.data.into_iter() {
                table.push_row(row);
            }
        }
        _ => {}
    }
}

fn update(db: &mut Rusql, update_def: UpdateDef) {
    let mut table = db.get_mut_table(&update_def.name);

    for (_, row) in table.data.iter_mut() {
        if let Some(ref expr) = update_def.where_expr {
            if !ExpressionEvaluator::new(row, &table.header).eval_bool(expr) {
                continue;
            }
        }

        for &(ref name, ref expr) in update_def.set.iter() {
            let x = table.header.iter().position(|ref cols| &cols.name == name).unwrap();

            row[x] = expr_to_literal(expr);
        }
    }
}

fn product(tables: Vec<&Table>, input_product: &mut Table, new_row_opt: Option<TableRow>) {
    let mut remaining = tables.clone();

    if remaining.len() == 0 {
        if let Some(new_row) = new_row_opt {
            input_product.push_row(new_row);
        }
    } else {
        let table = remaining.remove(0);
        for row in table.data.values() {
            let mut new_row: TableRow = if let Some(ref new_row) = new_row_opt {
                new_row.clone()
            } else {
                Vec::new()
            };

            new_row.push_all(&*row.clone());

            product(remaining.clone(), input_product, Some(new_row));
        }
    }
}

fn select<F: FnMut(&TableRow, &TableHeader)>(db: &mut Rusql, select_def: SelectDef, mut callback: F) -> Table {
    let mut input_tables: Vec<&Table> = Vec::new();
    let mut input_product = generate_inputs(db, &mut input_tables, &select_def);

    filter_inputs(&mut input_product, &input_tables, &select_def);

    let results_table = generate_result_set(input_product, &input_tables, &select_def);

    for row in results_table.data.values() {
        callback(row, &results_table.header);
    }

    results_table
}

fn natural_join(tables: &Vec<&Table>, constraints: &mut Vec<JoinConstraint>) {
    // FIXME ...
    let mut columns: Vec<(String, String, String)> = Vec::new();

    for table in tables.iter() {
        for other in tables.iter() {
            if table == other {
                continue;
            }

            for col in table.header.iter() {
                for other_col in other.header.iter() {
                    if col.name == other_col.name {
                        columns.push((table.name.clone(), other.name.clone(), other_col.name.clone()));
                    }
                }
            }
        }
    }

    for (table1, table2, column_name) in columns.into_iter() {
        constraints.push(JoinConstraint::On(
                Expression::BinaryOperator((BinaryOperator::Equals,
                    box Expression::TableName((table1, box Expression::ColumnName(column_name.clone()))),
                    box Expression::TableName((table2, box Expression::ColumnName(column_name)))))));
    }
}

fn generate_inputs<'a>(db: &'a Rusql, input_tables: &mut Vec<&'a Table>, select_def: &SelectDef) -> Table {
    // https://www.sqlite.org/lang_select.html#fromclause
    let mut input_header: TableHeader = Vec::new();

    if let Some(ref from_clause) = select_def.from_clause {
        // FIXME CLEANUP PLZ
        match from_clause {
            &FromClause::TableOrSubquery(ref table_or_subquery) => {
                for name in table_or_subquery.iter() {
                    let table = db.get_table(name);
                    input_tables.push(table);
                    input_header.push_all(&*table.header.clone());
                }

                let mut input_product = Table::new_result_table(input_header);

                product(input_tables.clone(), &mut input_product, None);

                input_product
            },
            &FromClause::JoinClause(ref name, ref join_clauses) => {
                let table = db.get_table(name);
                let mut constraints: Vec<JoinConstraint> = Vec::new();
                input_tables.push(table);
                input_header.push_all(&*table.header.clone());

                if let &Some(ref join_clauses) = join_clauses {
                    for &(ref join_operator, ref name, ref join_const) in join_clauses.iter() {
                        let table = db.get_table(name);
                        input_tables.push(table);
                        input_header.push_all(&*table.header.clone());

                        if let &Some(ref constraint) = join_const {
                            constraints.push(constraint.clone());
                        }

                        match join_operator {
                            &JoinOperator::Natural => natural_join(input_tables, &mut constraints),
                            _ => {}
                        }
                    }
                }

                let mut input_product = Table::new_result_table(input_header);

                product(input_tables.clone(), &mut input_product, None);

                let header = input_product.header.clone();

                for constraint in constraints.into_iter() {
                    match constraint {
                        JoinConstraint::On(ref expr) => {
                            input_product.delete_where(|row| {
                                !ExpressionEvaluator::new(row, &header).with_tables(input_tables.clone())
                                                                       .eval_bool(expr)
                            });
                        }
                    }
                }

                input_product
            },
        }
    } else {
       let mut input_product = Table::new_result_table(input_header);
       let empty_row: TableRow = Vec::new();
       input_product.push_row(empty_row);

       input_product
    }
}

fn filter_inputs(input_product: &mut Table, input_tables: &Vec<&Table>, select_def: &SelectDef) {
    // https://www.sqlite.org/lang_select.html#whereclause

    if let Some(ref expr) = select_def.where_expr {
        let header = input_product.header.clone();
        input_product.delete_where(|row| {
            !ExpressionEvaluator::new(row, &header).with_tables(input_tables.clone())
                                                   .eval_bool(expr)
        });
    }
}

fn generate_result_set(input_product: Table, input_tables: &Vec<&Table>, select_def: &SelectDef) -> Table {
    // https://www.sqlite.org/lang_select.html#resultset
    let results_header: TableHeader = Vec::new();
    let mut results_table = Table::new_result_table(results_header);
    let mut rows: Vec<TableRow> = Vec::new();

    for row in input_product.data.values() {
        match select_def.result_column {
            ResultColumn::Expressions(ref exprs) => generate_row_from_expressions(&mut results_table, row, exprs, input_tables),
            ResultColumn::Asterisk => {
                if results_table.header.len() == 0 {
                    results_table.header = input_product.header.clone();
                }
                rows.push(row.clone());
            }
        }
    }

    if let Some(ref ordering_terms) = select_def.ordering_terms {
        debug!("ORDER BY");
        let mut ordering_terms = ordering_terms.clone();
        ordering_terms.as_mut_slice().reverse();
        for term in ordering_terms.iter() {
            rows.as_mut_slice().sort_by(|a, b| {
                // FIXME ... ugly.
                match term.order {
                    Order::Ascending => a[result_to_literal(
                            ExpressionEvaluator::new(a, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()].cmp(&b[result_to_literal(
                            ExpressionEvaluator::new(b, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()]),
                    Order::Descending => b[result_to_literal(
                            ExpressionEvaluator::new(b, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()].cmp(&a[result_to_literal(
                            ExpressionEvaluator::new(a, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()]),
                }
            });
        }
    }
    results_table.insert(rows, &None);

    results_table
}

fn generate_row_from_expressions(results_table: &mut Table, row: &TableRow, exprs: &Vec<Expression>, input_tables: &Vec<&Table>) {
    let mut new_row: TableRow = Vec::new();
    let push_header = if results_table.header.len() == 0 { true } else { false };

    for expr in exprs.iter() {
        if push_header {
            match ExpressionEvaluator::new(row, &results_table.header).with_tables(input_tables.clone())
                                                                      .with_column_def()
                                                                      .eval_expr(expr) {
                ExpressionResult::ColumnDef(def) => results_table.header.push(def.clone()),
                _ => {}, // FIXME No idea
            }
        }
        match ExpressionEvaluator::new(row, &results_table.header).with_tables(input_tables.clone())
                                                                  .eval_expr(expr) {
            ExpressionResult::Value(v) => new_row.push(v),
            _ => {}, // FIXME No idea
        }
    }

    results_table.push_row(new_row);
}
<commit_msg>Fix unused mut warning<commit_after>use table::{TableRow, TableHeader, Table};
use definitions::{ResultColumn, RusqlStatement, InsertDef, SelectDef};
use definitions::{AlterTableDef, AlterTable, Expression, FromClause, JoinOperator};
use definitions::{DeleteDef, InsertDataSource, UpdateDef, Order, JoinConstraint};
use definitions::{BinaryOperator};
use expressions::{ExpressionResult, ExpressionEvaluator, expr_to_literal, result_to_literal};
use rusql::Rusql;

peg_file! parser("sql.rustpeg");

pub fn rusql_exec<F: FnMut(&TableRow, &TableHeader)>(db: &mut Rusql, sql_str: &str, callback: F) -> Option<Table> {
    match parser::rusql_parse(sql_str) {
        Ok(res) => {
            for stmt in res.into_iter() {
                match stmt {
                    RusqlStatement::AlterTable(alter_table_def) => alter_table(db, alter_table_def),
                    RusqlStatement::CreateTable(table_def) => db.create_table(table_def),
                    RusqlStatement::Delete(delete_def) => delete(db, delete_def),
                    RusqlStatement::DropTable(drop_table_def) => db.drop_table(&drop_table_def.name),
                    RusqlStatement::Insert(insert_def) => insert(db, insert_def),
                    RusqlStatement::Select(select_def) => return Some(select(db, select_def, callback)),
                    RusqlStatement::Update(update_def) => update(db, update_def),
                }
            }
        }
        Err(e) => println!("syntax error: {}", e),
    }
    None
}

fn alter_table(db: &mut Rusql, alter_table_def: AlterTableDef) {
    match alter_table_def.mode {
        AlterTable::RenameTo(new_name) => db.rename_table(&alter_table_def.name, new_name),
        AlterTable::AddColumn(column_def) => db.get_mut_table(&alter_table_def.name)
                                               .add_column(column_def),
    }
}

fn delete(db: &mut Rusql, delete_def: DeleteDef) {
    let table = db.get_mut_table(&delete_def.name);

    if let Some(ref expr) = delete_def.where_expr {
        // FIXME just making the borrow checker happy...
        let header = table.header.clone();
        table.delete_where(|row| ExpressionEvaluator::new(row, &header).eval_bool(expr));
    } else {
        table.clear();
    }
}

fn insert(db: &mut Rusql, insert_def: InsertDef) {
    match insert_def.data_source {
        InsertDataSource::Values(column_data) => {
            let mut table = db.get_mut_table(&insert_def.table_name);
            table.insert(column_data, &insert_def.column_names);
        }
        InsertDataSource::Select(select_def) => {
            let results_table = select(db, select_def, |_,_| {});
            let mut table = db.get_mut_table(&insert_def.table_name);

            for (_, row) in results_table.data.into_iter() {
                table.push_row(row);
            }
        }
        _ => {}
    }
}

fn update(db: &mut Rusql, update_def: UpdateDef) {
    let mut table = db.get_mut_table(&update_def.name);

    for (_, row) in table.data.iter_mut() {
        if let Some(ref expr) = update_def.where_expr {
            if !ExpressionEvaluator::new(row, &table.header).eval_bool(expr) {
                continue;
            }
        }

        for &(ref name, ref expr) in update_def.set.iter() {
            let x = table.header.iter().position(|ref cols| &cols.name == name).unwrap();

            row[x] = expr_to_literal(expr);
        }
    }
}

fn product(tables: Vec<&Table>, input_product: &mut Table, new_row_opt: Option<TableRow>) {
    let mut remaining = tables.clone();

    if remaining.len() == 0 {
        if let Some(new_row) = new_row_opt {
            input_product.push_row(new_row);
        }
    } else {
        let table = remaining.remove(0);
        for row in table.data.values() {
            let mut new_row: TableRow = if let Some(ref new_row) = new_row_opt {
                new_row.clone()
            } else {
                Vec::new()
            };

            new_row.push_all(&*row.clone());

            product(remaining.clone(), input_product, Some(new_row));
        }
    }
}

fn select<F: FnMut(&TableRow, &TableHeader)>(db: &mut Rusql, select_def: SelectDef, mut callback: F) -> Table {
    let mut input_tables: Vec<&Table> = Vec::new();
    let mut input_product = generate_inputs(db, &mut input_tables, &select_def);

    filter_inputs(&mut input_product, &input_tables, &select_def);

    let results_table = generate_result_set(input_product, &input_tables, &select_def);

    for row in results_table.data.values() {
        callback(row, &results_table.header);
    }

    results_table
}

fn natural_join(tables: &Vec<&Table>, constraints: &mut Vec<JoinConstraint>) {
    // FIXME ...
    let mut columns: Vec<(String, String, String)> = Vec::new();

    for table in tables.iter() {
        for other in tables.iter() {
            if table == other {
                continue;
            }

            for col in table.header.iter() {
                for other_col in other.header.iter() {
                    if col.name == other_col.name {
                        columns.push((table.name.clone(), other.name.clone(), other_col.name.clone()));
                    }
                }
            }
        }
    }

    for (table1, table2, column_name) in columns.into_iter() {
        constraints.push(JoinConstraint::On(
                Expression::BinaryOperator((BinaryOperator::Equals,
                    box Expression::TableName((table1, box Expression::ColumnName(column_name.clone()))),
                    box Expression::TableName((table2, box Expression::ColumnName(column_name)))))));
    }
}

fn generate_inputs<'a>(db: &'a Rusql, input_tables: &mut Vec<&'a Table>, select_def: &SelectDef) -> Table {
    // https://www.sqlite.org/lang_select.html#fromclause
    let mut input_header: TableHeader = Vec::new();

    if let Some(ref from_clause) = select_def.from_clause {
        // FIXME CLEANUP PLZ
        match from_clause {
            &FromClause::TableOrSubquery(ref table_or_subquery) => {
                for name in table_or_subquery.iter() {
                    let table = db.get_table(name);
                    input_tables.push(table);
                    input_header.push_all(&*table.header.clone());
                }

                let mut input_product = Table::new_result_table(input_header);

                product(input_tables.clone(), &mut input_product, None);

                input_product
            },
            &FromClause::JoinClause(ref name, ref join_clauses) => {
                let table = db.get_table(name);
                let mut constraints: Vec<JoinConstraint> = Vec::new();
                input_tables.push(table);
                input_header.push_all(&*table.header.clone());

                if let &Some(ref join_clauses) = join_clauses {
                    for &(ref join_operator, ref name, ref join_const) in join_clauses.iter() {
                        let table = db.get_table(name);
                        input_tables.push(table);
                        input_header.push_all(&*table.header.clone());

                        if let &Some(ref constraint) = join_const {
                            constraints.push(constraint.clone());
                        }

                        match join_operator {
                            &JoinOperator::Natural => natural_join(input_tables, &mut constraints),
                            _ => {}
                        }
                    }
                }

                let mut input_product = Table::new_result_table(input_header);

                product(input_tables.clone(), &mut input_product, None);

                let header = input_product.header.clone();

                for constraint in constraints.into_iter() {
                    match constraint {
                        JoinConstraint::On(ref expr) => {
                            input_product.delete_where(|row| {
                                !ExpressionEvaluator::new(row, &header).with_tables(input_tables.clone())
                                                                       .eval_bool(expr)
                            });
                        }
                    }
                }

                input_product
            },
        }
    } else {
       let mut input_product = Table::new_result_table(input_header);
       let empty_row: TableRow = Vec::new();
       input_product.push_row(empty_row);

       input_product
    }
}

fn filter_inputs(input_product: &mut Table, input_tables: &Vec<&Table>, select_def: &SelectDef) {
    // https://www.sqlite.org/lang_select.html#whereclause

    if let Some(ref expr) = select_def.where_expr {
        let header = input_product.header.clone();
        input_product.delete_where(|row| {
            !ExpressionEvaluator::new(row, &header).with_tables(input_tables.clone())
                                                   .eval_bool(expr)
        });
    }
}

fn generate_result_set(input_product: Table, input_tables: &Vec<&Table>, select_def: &SelectDef) -> Table {
    // https://www.sqlite.org/lang_select.html#resultset
    let results_header: TableHeader = Vec::new();
    let mut results_table = Table::new_result_table(results_header);
    let mut rows: Vec<TableRow> = Vec::new();

    for row in input_product.data.values() {
        match select_def.result_column {
            ResultColumn::Expressions(ref exprs) => generate_row_from_expressions(&mut results_table, row, exprs, input_tables),
            ResultColumn::Asterisk => {
                if results_table.header.len() == 0 {
                    results_table.header = input_product.header.clone();
                }
                rows.push(row.clone());
            }
        }
    }

    if let Some(ref ordering_terms) = select_def.ordering_terms {
        debug!("ORDER BY");
        let mut ordering_terms = ordering_terms.clone();
        ordering_terms.as_mut_slice().reverse();
        for term in ordering_terms.iter() {
            rows.as_mut_slice().sort_by(|a, b| {
                // FIXME ... ugly.
                match term.order {
                    Order::Ascending => a[result_to_literal(
                            ExpressionEvaluator::new(a, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()].cmp(&b[result_to_literal(
                            ExpressionEvaluator::new(b, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()]),
                    Order::Descending => b[result_to_literal(
                            ExpressionEvaluator::new(b, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()].cmp(&a[result_to_literal(
                            ExpressionEvaluator::new(a, &results_table.header)
                                                 .as_column_alias()
                                                 .eval_expr(&term.expr)
                        ).to_uint()]),
                }
            });
        }
    }
    results_table.insert(rows, &None);

    results_table
}

fn generate_row_from_expressions(results_table: &mut Table, row: &TableRow, exprs: &Vec<Expression>, input_tables: &Vec<&Table>) {
    let mut new_row: TableRow = Vec::new();
    let push_header = if results_table.header.len() == 0 { true } else { false };

    for expr in exprs.iter() {
        if push_header {
            match ExpressionEvaluator::new(row, &results_table.header).with_tables(input_tables.clone())
                                                                      .with_column_def()
                                                                      .eval_expr(expr) {
                ExpressionResult::ColumnDef(def) => results_table.header.push(def.clone()),
                _ => {}, // FIXME No idea
            }
        }
        match ExpressionEvaluator::new(row, &results_table.header).with_tables(input_tables.clone())
                                                                  .eval_expr(expr) {
            ExpressionResult::Value(v) => new_row.push(v),
            _ => {}, // FIXME No idea
        }
    }

    results_table.push_row(new_row);
}
<|endoftext|>


<commit_before>//! Parsers and helper functions operating on strings, especially useful when writing parsers for
//! text-based formats.

/// `tag_s!(&str) => &str -> IResult<&str, &str>`
/// declares a string as a suite to recognize
///
/// consumes the recognized characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::{self,Done};
/// # fn main() {
///  fn test(input: &str) -> IResult<&str, &str> {
///    tag_s!(input, "abcd")
///  }
///  let r = test("abcdefgh");
///  assert_eq!(r, Done("efgh", "abcd"));
/// # }
/// ```
#[macro_export]
macro_rules! tag_s (
  ($i:expr, $tag: expr) => (
    {
      let res: $crate::IResult<&str,&str> = if $tag.len() > $i.len() {
        $crate::IResult::Incomplete($crate::Needed::Size($tag.len()))
      //} else if &$i[0..$tag.len()] == $tag {
      } else if ($i).starts_with($tag) {
        $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()])
      } else {
        $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagStr, $i))
      };
      res
    }
  );
);

/// `take_s!(nb) => &str -> IResult<&str, &str>`
/// generates a parser consuming the specified number of characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  // Desmond parser
///  named!(take5<&str,&str>, take_s!( 5 ) );
///
///  let a = "abcdefgh";
///
///  assert_eq!(take5(a), Done("fgh", "abcde"));
/// # }
/// ```
#[macro_export]
macro_rules! take_s (
  ($i:expr, $count:expr) => (
    {
      let cnt = $count as usize;
      let res: $crate::IResult<&str,&str> = if $i.len() < cnt {
        $crate::IResult::Incomplete($crate::Needed::Size(cnt))
      } else {
        $crate::IResult::Done(&$i[cnt..],&$i[0..cnt])
      };
      res
    }
  );
);

/// `is_not_s!(&str) => &str -> IResult<&str, &str>`
/// returns the longest list of characters that do not appear in the provided array
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( not_space<&str,&str>, is_not_s!( " \t\r\n" ) );
///
///  let r = not_space("abcdefgh\nijkl");
///  assert_eq!(r, Done("\nijkl", "abcdefgh"));
///  # }
/// ```
#[macro_export]
macro_rules! is_not_s (
  ($input:expr, $arr:expr) => (
    {
      let res: $crate::IResult<&str,&str> = match $input.chars().position(|c| {
        for i in $arr.chars() {
          if c == i { return true }
        }
        false
      }) {
        Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsNotStr,$input)),
        Some(n) => {
          let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      };
      res
    }
  );
);

/// `is_a_s!(&str) => &str -> IResult<&str, &str>`
/// returns the longest list of characters that appear in the provided array
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!(abcd<&str, &str>, is_a_s!( "abcd" ));
///
///  let r1 = abcd("aaaaefgh");
///  assert_eq!(r1, Done("efgh", "aaaa"));
///
///  let r2 = abcd("dcbaefgh");
///  assert_eq!(r2, Done("efgh", "dcba"));
/// # }
/// ```
#[macro_export]
macro_rules! is_a_s (
  ($input:expr, $arr:expr) => (
    {
      let res: $crate::IResult<&str,&str> = match $input.chars().position(|c| {
        for i in $arr.chars() {
          if c == i { return false }
        }
        true
      }) {
        Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsAStr,$input)),
        Some(n) => {
          let res: $crate::IResult<&str,&str> = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      };
      res
    }
  );
);

/// `take_while!(char -> bool) => &str -> IResult<&str, &str>`
/// returns the longest list of bytes until the provided function fails.
///
/// The argument is either a function `T -> bool` or a macro returning a `bool
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # use nom::is_alphanumeric;
/// # fn main() {
///  fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) }
///  named!( alpha<&str,&str>, take_while_s!( alphabetic ) );
///
///  let r = alpha("abcd\nefgh");
///  assert_eq!(r, Done("\nefgh", "abcd"));
/// # }
/// ```
#[macro_export]
macro_rules! take_while_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      match $input.chars().position(|c| !$submac!(c, $($args)*)) {
        Some(n) => {
          let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      }
    }
  );
  ($input:expr, $f:expr) => (
    take_while_s!($input, call!($f));
  );
);

/// `take_while1!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
/// returns the longest (non empty) list of bytes until the provided function fails.
///
/// The argument is either a function `T -> bool` or a macro returning a `bool`
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # use nom::is_alphanumeric;
/// # fn main() {
///  fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) }
///  named!( alpha<&str,&str>, take_while1_s!( alphabetic ) );
///
///  let r = alpha("abcd\nefgh");
///  assert_eq!(r, Done("\nefgh", "abcd"));
/// # }
/// ```
#[macro_export]
macro_rules! take_while1_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      match $input.chars().position(|c| !$submac!(c, $($args)*)) {
        Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1Str,$input)),
        Some(n) => {
          let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      }
    }
  );
  ($input:expr, $f:expr) => (
    take_while1_s!($input, call!($f));
  );
);

/// `take_till_s!(&[T] -> bool) => &[T] -> IResult<&[T], &[T]>`
/// returns the longest list of bytes until the provided function succeeds
///
/// The argument is either a function `&[T] -> bool` or a macro returning a `bool
#[macro_export]
macro_rules! take_till_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (

    {
      match $input.chars().position(|c| $submac!(c, $($args)*)) {
        Some(n) => $crate::IResult::Done(&$input[n..], &$input[..n]),
        None    => $crate::IResult::Done("", $input)
      }
    }
  );
  ($input:expr, $f:expr) => (
    take_till_s!($input, call!($f));
  );
);

#[cfg(test)]
mod test {
    use ::IResult;

    #[test]
    fn tag_str_succeed() {
        const INPUT: &'static str = "Hello World!";
        const TAG: &'static str = "Hello";
        fn test(input: &str) -> IResult<&str, &str> {
          tag_s!(input, TAG)
        }

        match test(INPUT) {
            IResult::Done(extra, output) => {
                assert!(extra == " World!", "Parser `tag_s` consumed leftover input.");
                assert!(output == TAG,
                    "Parser `tag_s` doesn't return the tag it matched on success. \
                     Expected `{}`, got `{}`.", TAG, output);
            },
            other => panic!("Parser `tag_s` didn't succeed when it should have. \
                             Got `{:?}`.", other),
        };
    }

    #[test]
    fn tag_str_incomplete() {
        const INPUT: &'static str = "Hello";
        const TAG: &'static str = "Hello World!";

        match tag_s!(INPUT, TAG) {
            IResult::Incomplete(_) => (),
            other => {
                panic!("Parser `tag_s` didn't require more input when it should have. \
                        Got `{:?}`.", other);
            }
        };
    }

    #[test]
    fn tag_str_error() {
        const INPUT: &'static str = "Hello World!";
        const TAG: &'static str = "Random"; // TAG must be closer than INPUT.

        match tag_s!(INPUT, TAG) {
            IResult::Error(_) => (),
            other => {
                panic!("Parser `tag_s` didn't fail when it should have. Got `{:?}`.`", other);
            },
        };
    }
}
<commit_msg>fix documentation<commit_after>//! Parsers and helper functions operating on strings, especially useful when writing parsers for
//! text-based formats.

/// `tag_s!(&str) => &str -> IResult<&str, &str>`
/// declares a string as a suite to recognize
///
/// consumes the recognized characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::{self,Done};
/// # fn main() {
///  fn test(input: &str) -> IResult<&str, &str> {
///    tag_s!(input, "abcd")
///  }
///  let r = test("abcdefgh");
///  assert_eq!(r, Done("efgh", "abcd"));
/// # }
/// ```
#[macro_export]
macro_rules! tag_s (
  ($i:expr, $tag: expr) => (
    {
      let res: $crate::IResult<&str,&str> = if $tag.len() > $i.len() {
        $crate::IResult::Incomplete($crate::Needed::Size($tag.len()))
      //} else if &$i[0..$tag.len()] == $tag {
      } else if ($i).starts_with($tag) {
        $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()])
      } else {
        $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagStr, $i))
      };
      res
    }
  );
);

/// `take_s!(nb) => &str -> IResult<&str, &str>`
/// generates a parser consuming the specified number of characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  // Desmond parser
///  named!(take5<&str,&str>, take_s!( 5 ) );
///
///  let a = "abcdefgh";
///
///  assert_eq!(take5(a), Done("fgh", "abcde"));
/// # }
/// ```
#[macro_export]
macro_rules! take_s (
  ($i:expr, $count:expr) => (
    {
      let cnt = $count as usize;
      let res: $crate::IResult<&str,&str> = if $i.len() < cnt {
        $crate::IResult::Incomplete($crate::Needed::Size(cnt))
      } else {
        $crate::IResult::Done(&$i[cnt..],&$i[0..cnt])
      };
      res
    }
  );
);

/// `is_not_s!(&str) => &str -> IResult<&str, &str>`
/// returns the longest list of characters that do not appear in the provided array
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( not_space<&str,&str>, is_not_s!( " \t\r\n" ) );
///
///  let r = not_space("abcdefgh\nijkl");
///  assert_eq!(r, Done("\nijkl", "abcdefgh"));
///  # }
/// ```
#[macro_export]
macro_rules! is_not_s (
  ($input:expr, $arr:expr) => (
    {
      let res: $crate::IResult<&str,&str> = match $input.chars().position(|c| {
        for i in $arr.chars() {
          if c == i { return true }
        }
        false
      }) {
        Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsNotStr,$input)),
        Some(n) => {
          let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      };
      res
    }
  );
);

/// `is_a_s!(&str) => &str -> IResult<&str, &str>`
/// returns the longest list of characters that appear in the provided array
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!(abcd<&str, &str>, is_a_s!( "abcd" ));
///
///  let r1 = abcd("aaaaefgh");
///  assert_eq!(r1, Done("efgh", "aaaa"));
///
///  let r2 = abcd("dcbaefgh");
///  assert_eq!(r2, Done("efgh", "dcba"));
/// # }
/// ```
#[macro_export]
macro_rules! is_a_s (
  ($input:expr, $arr:expr) => (
    {
      let res: $crate::IResult<&str,&str> = match $input.chars().position(|c| {
        for i in $arr.chars() {
          if c == i { return false }
        }
        true
      }) {
        Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsAStr,$input)),
        Some(n) => {
          let res: $crate::IResult<&str,&str> = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      };
      res
    }
  );
);

/// `take_while!(char -> bool) => &str -> IResult<&str, &str>`
/// returns the longest list of bytes until the provided function fails.
///
/// The argument is either a function `T -> bool` or a macro returning a `bool
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # use nom::is_alphanumeric;
/// # fn main() {
///  fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) }
///  named!( alpha<&str,&str>, take_while_s!( alphabetic ) );
///
///  let r = alpha("abcd\nefgh");
///  assert_eq!(r, Done("\nefgh", "abcd"));
/// # }
/// ```
#[macro_export]
macro_rules! take_while_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      match $input.chars().position(|c| !$submac!(c, $($args)*)) {
        Some(n) => {
          let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      }
    }
  );
  ($input:expr, $f:expr) => (
    take_while_s!($input, call!($f));
  );
);

/// `take_while1!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
/// returns the longest (non empty) list of bytes until the provided function fails.
///
/// The argument is either a function `T -> bool` or a macro returning a `bool`
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # use nom::is_alphanumeric;
/// # fn main() {
///  fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) }
///  named!( alpha<&str,&str>, take_while1_s!( alphabetic ) );
///
///  let r = alpha("abcd\nefgh");
///  assert_eq!(r, Done("\nefgh", "abcd"));
/// # }
/// ```
#[macro_export]
macro_rules! take_while1_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      match $input.chars().position(|c| !$submac!(c, $($args)*)) {
        Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1Str,$input)),
        Some(n) => {
          let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
          res
        },
        None    => {
          $crate::IResult::Done("", $input)
        }
      }
    }
  );
  ($input:expr, $f:expr) => (
    take_while1_s!($input, call!($f));
  );
);

/// `take_till_s!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
/// returns the longest list of bytes until the provided function succeeds
///
/// The argument is either a function `T -> bool` or a macro returning a `bool
#[macro_export]
macro_rules! take_till_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (

    {
      match $input.chars().position(|c| $submac!(c, $($args)*)) {
        Some(n) => $crate::IResult::Done(&$input[n..], &$input[..n]),
        None    => $crate::IResult::Done("", $input)
      }
    }
  );
  ($input:expr, $f:expr) => (
    take_till_s!($input, call!($f));
  );
);

#[cfg(test)]
mod test {
    use ::IResult;

    #[test]
    fn tag_str_succeed() {
        const INPUT: &'static str = "Hello World!";
        const TAG: &'static str = "Hello";
        fn test(input: &str) -> IResult<&str, &str> {
          tag_s!(input, TAG)
        }

        match test(INPUT) {
            IResult::Done(extra, output) => {
                assert!(extra == " World!", "Parser `tag_s` consumed leftover input.");
                assert!(output == TAG,
                    "Parser `tag_s` doesn't return the tag it matched on success. \
                     Expected `{}`, got `{}`.", TAG, output);
            },
            other => panic!("Parser `tag_s` didn't succeed when it should have. \
                             Got `{:?}`.", other),
        };
    }

    #[test]
    fn tag_str_incomplete() {
        const INPUT: &'static str = "Hello";
        const TAG: &'static str = "Hello World!";

        match tag_s!(INPUT, TAG) {
            IResult::Incomplete(_) => (),
            other => {
                panic!("Parser `tag_s` didn't require more input when it should have. \
                        Got `{:?}`.", other);
            }
        };
    }

    #[test]
    fn tag_str_error() {
        const INPUT: &'static str = "Hello World!";
        const TAG: &'static str = "Random"; // TAG must be closer than INPUT.

        match tag_s!(INPUT, TAG) {
            IResult::Error(_) => (),
            other => {
                panic!("Parser `tag_s` didn't fail when it should have. Got `{:?}`.`", other);
            },
        };
    }
}
<|endoftext|>