<commit_before>#![allow(dead_code)]
use utils;
//use std::ops::{Index, Deref, DerefMut};
use std::cell::RefCell;
use std::rc::Rc;

pub type MemShared = Rc<RefCell<Memory>>;

pub enum MemType
{
    RAM,
    BASIC,
    CHARGEN,
    IO,
    KERNAL,
}

// specific memory bank - RAM, ROM, IO
pub struct MemBank
{
    bank_type: MemType, // what am I?
    read_only: bool,    // RAM or ROM?
    offset: u16,        // offset from start of address space
    data: Vec<u8>,
}

impl MemBank
{
    pub fn new(mem_type: MemType) -> MemBank
    {
        let mut mem_bank = MemBank
        {
            bank_type: mem_type,
            read_only: true,
            offset: 0x0000,
            data: Vec::<u8>::new(),
        };

        match mem_bank.bank_type
        {
            MemType::BASIC   => {
                mem_bank.data = utils::open_file("rom/basic.rom", 0);
                mem_bank.offset = 0xA000;
            },
            MemType::CHARGEN => {
                mem_bank.data = utils::open_file("rom/chargen.rom", 0);
                mem_bank.offset = 0xD000;
            },
            MemType::KERNAL  => {
                mem_bank.data = utils::open_file("rom/kernal.rom", 0);
                mem_bank.offset = 0xE000;
            },
            MemType::RAM => {
                mem_bank.data = Vec::<u8>::with_capacity(0x10000);
                for _ in 0..0x10000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.read_only = false;
            },
            MemType::IO => {
                mem_bank.data = Vec::<u8>::with_capacity(0x1000);
                for _ in 0..0x1000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.offset = 0xD000;
                mem_bank.read_only = false;
            }
        }

        mem_bank
    }

    pub fn write(&mut self, addr: u16, val: u8)
    {
        match self.bank_type
        {
            MemType::RAM => self.data[(addr - self.offset) as usize] = val,
            MemType::IO => {
                match addr
                {
                    0xD016          => self.data[(addr - self.offset) as usize] = 0xC0 | val,
                    0xD019          => self.data[(addr - self.offset) as usize] = 0x70 | val,
                    0xD01A          => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    //0xD01E...0xD01F => (),  // cannot be written on real C64 but allow the VIC to do it anyway
                    0xD020...0xD02E => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD02F...0xD03F => (),                             // write ignored
                    0xD040...0xD3FF => self.write(0xD000 + (addr % 0x0040), val), // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize] = val
                }

            },
            _ => panic!("Can't write to ROM!")
        }
    }

    pub fn read(&mut self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                match addr
                {
                    0xD016          => 0xC0 | self.data[(addr - self.offset) as usize],
                    0xD018          => 0x01 | self.data[(addr - self.offset) as usize],
                    0xD019          => 0x70 | self.data[(addr - self.offset) as usize],
                    0xD01A          => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD01E...0xD01F => {                                  // cannot be written, cleared on read
                        let value = self.data[(addr - self.offset) as usize];
                        self.data[(addr - self.offset) as usize] = 0;
                        value
                    },
                    0xD020...0xD02E => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD02F...0xD03F => 0xFF,                              // always returns 0xFF
                    0xD040...0xD3FF => self.read(0xD000 + (addr % 0x0040)),          // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize]
                }
            },
            _ => self.data[(addr - self.offset) as usize]
        }
    }
}

// collective memory storage with all the banks and bank switching support
pub struct Memory
{
    ram:     MemBank,
    basic:   MemBank,
    chargen: MemBank,
    io:      MemBank,
    kernal:  MemBank,

    // bank switching flags
    pub basic_on:   bool,
    pub chargen_on: bool,
    pub io_on:  bool,
    pub kernal_on:  bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new_shared() -> MemShared
    {
        Rc::new(RefCell::new(Memory
        {
            ram:     MemBank::new(MemType::RAM),     // 64k
            basic:   MemBank::new(MemType::BASIC),   // 8k
            chargen: MemBank::new(MemType::CHARGEN), // 4k
            io:      MemBank::new(MemType::IO),      // 4k (VIC, SID, CIA, Color RAM)
            kernal:  MemBank::new(MemType::KERNAL),  // 8k
            basic_on:   false,
            chargen_on: false,
            io_on:      false,
            kernal_on:  false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        }))
    }

    // returns memory bank for current latch setting and address
    pub fn get_bank(&mut self, addr: u16) -> (&mut MemBank)
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram,
            0xA000...0xBFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xC000...0xCFFF => &mut self.ram,
            0xD000...0xDFFF => {
                if self.chargen_on { return &mut self.chargen }
                if self.io_on      { return &mut self.io; }
                return &mut self.ram;
            },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.kernal } else { &mut self.ram },
            _ => panic!("Address out of memory range")
        }
    }

    // returns specific modifiable memory bank
    pub fn get_ram_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::RAM => &mut self.ram,
            MemType::IO  => &mut self.io,
            _            => panic!("Unrecognized RAM bank"),
        }
    }

    // returns specific non-modifiable memory bank
    pub fn get_rom_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::BASIC   => &mut self.basic,
            MemType::CHARGEN => &mut self.chargen,
            MemType::KERNAL  => &mut self.kernal,
            _                => panic!("Unrecognized ROM Abank"),
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic ROMs
    }

    fn update_memory_latch(&mut self)
    {
        let ddr = self.ram.read(0x0000);
        let pr  = self.ram.read(0x0001);
        let latch = !ddr | pr;

        self.chargen_on = ((latch & 0x04) == 0) && ((latch & 0x03) != 0); // %0xx except %000
        self.io_on      = ((latch & 0x04) != 0) && ((latch & 0x03) != 0); // %1xx except %100
        self.basic_on   = (latch & 0x03) == 3;
        self.kernal_on  = (latch & 0x02) != 0;
    }

    // Write a byte to memory - returns whether RAM was written (true) or RAM under ROM (false)
    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
        // RAM under ROM written? Return false to let us know about it
        if self.get_bank(addr).read_only
        {
            self.ram.write(addr, value);
            return false;
        }
        else
        {
            self.get_bank(addr).write(addr, value);
        }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr < 0x0002 { self.update_memory_latch(); }

        return true;
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        // special location: current memory latch settings
        if addr == 0x0001
        {
            let ddr = self.ram.read(0x0000);
            let pr  = self.ram.read(0x0001);
            return (ddr & pr) | (!ddr & 0x17);
        }

        self.get_bank(addr).read(addr)
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_lo);
        let lo = self.write_byte(addr + 0x0001, value_le_hi);

        return hi && lo;
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_hi);
        let lo = self.write_byte(addr + 0x0001, value_le_lo);

        return hi && lo;
    }
}

<commit_msg>remove unused code<commit_after>#![allow(dead_code)]
use utils;
use std::cell::RefCell;
use std::rc::Rc;

pub type MemShared = Rc<RefCell<Memory>>;

pub enum MemType
{
    RAM,
    BASIC,
    CHARGEN,
    IO,
    KERNAL,
}

// specific memory bank - RAM, ROM, IO
pub struct MemBank
{
    bank_type: MemType, // what am I?
    read_only: bool,    // RAM or ROM?
    offset: u16,        // offset from start of address space
    data: Vec<u8>,
}

impl MemBank
{
    pub fn new(mem_type: MemType) -> MemBank
    {
        let mut mem_bank = MemBank
        {
            bank_type: mem_type,
            read_only: true,
            offset: 0x0000,
            data: Vec::<u8>::new(),
        };

        match mem_bank.bank_type
        {
            MemType::BASIC   => {
                mem_bank.data = utils::open_file("rom/basic.rom", 0);
                mem_bank.offset = 0xA000;
            },
            MemType::CHARGEN => {
                mem_bank.data = utils::open_file("rom/chargen.rom", 0);
                mem_bank.offset = 0xD000;
            },
            MemType::KERNAL  => {
                mem_bank.data = utils::open_file("rom/kernal.rom", 0);
                mem_bank.offset = 0xE000;
            },
            MemType::RAM => {
                mem_bank.data = Vec::<u8>::with_capacity(0x10000);
                for _ in 0..0x10000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.read_only = false;
            },
            MemType::IO => {
                mem_bank.data = Vec::<u8>::with_capacity(0x1000);
                for _ in 0..0x1000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.offset = 0xD000;
                mem_bank.read_only = false;
            }
        }

        mem_bank
    }

    pub fn write(&mut self, addr: u16, val: u8)
    {
        match self.bank_type
        {
            MemType::RAM => self.data[(addr - self.offset) as usize] = val,
            MemType::IO => {
                match addr
                {
                    0xD016          => self.data[(addr - self.offset) as usize] = 0xC0 | val,
                    0xD019          => self.data[(addr - self.offset) as usize] = 0x70 | val,
                    0xD01A          => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    //0xD01E...0xD01F => (),  // cannot be written on real C64 but allow the VIC to do it anyway
                    0xD020...0xD02E => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD02F...0xD03F => (),                             // write ignored
                    0xD040...0xD3FF => self.write(0xD000 + (addr % 0x0040), val), // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize] = val
                }

            },
            _ => panic!("Can't write to ROM!")
        }
    }

    pub fn read(&mut self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                match addr
                {
                    0xD016          => 0xC0 | self.data[(addr - self.offset) as usize],
                    0xD018          => 0x01 | self.data[(addr - self.offset) as usize],
                    0xD019          => 0x70 | self.data[(addr - self.offset) as usize],
                    0xD01A          => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD01E...0xD01F => {                                  // cannot be written, cleared on read
                        let value = self.data[(addr - self.offset) as usize];
                        self.data[(addr - self.offset) as usize] = 0;
                        value
                    },
                    0xD020...0xD02E => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD02F...0xD03F => 0xFF,                                 // always returns 0xFF
                    0xD040...0xD3FF => self.read(0xD000 + (addr % 0x0040)),  // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize]
                }
            },
            _ => self.data[(addr - self.offset) as usize]
        }
    }
}

// collective memory storage with all the banks and bank switching support
pub struct Memory
{
    ram:     MemBank,
    basic:   MemBank,
    chargen: MemBank,
    io:      MemBank,
    kernal:  MemBank,

    // bank switching flags
    pub basic_on:   bool,
    pub chargen_on: bool,
    pub io_on:      bool,
    pub kernal_on:  bool,
    //cart_lo_on: bool, // cart flag - unused for now
    //cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new_shared() -> MemShared
    {
        Rc::new(RefCell::new(Memory
        {
            ram:     MemBank::new(MemType::RAM),     // 64k
            basic:   MemBank::new(MemType::BASIC),   // 8k
            chargen: MemBank::new(MemType::CHARGEN), // 4k
            io:      MemBank::new(MemType::IO),      // 4k (VIC, SID, CIA, Color RAM)
            kernal:  MemBank::new(MemType::KERNAL),  // 8k
            basic_on:   false,
            chargen_on: false,
            io_on:      false,
            kernal_on:  false,
        }))
    }

    // returns memory bank for current latch setting and address
    pub fn get_bank(&mut self, addr: u16) -> (&mut MemBank)
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram,
            0xA000...0xBFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xC000...0xCFFF => &mut self.ram,
            0xD000...0xDFFF => {
                if self.chargen_on { return &mut self.chargen }
                if self.io_on      { return &mut self.io; }
                return &mut self.ram;
            },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.kernal } else { &mut self.ram },
            _ => panic!("Address out of memory range")
        }
    }

    // returns specific modifiable memory bank
    pub fn get_ram_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::RAM => &mut self.ram,
            MemType::IO  => &mut self.io,
            _            => panic!("Unrecognized RAM bank"),
        }
    }

    // returns specific non-modifiable memory bank
    pub fn get_rom_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::BASIC   => &mut self.basic,
            MemType::CHARGEN => &mut self.chargen,
            MemType::KERNAL  => &mut self.kernal,
            _                => panic!("Unrecognized ROM Abank"),
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic ROMs
    }

    fn update_memory_latch(&mut self)
    {
        let ddr = self.ram.read(0x0000);
        let pr  = self.ram.read(0x0001);
        let latch = !ddr | pr;

        self.chargen_on = ((latch & 0x04) == 0) && ((latch & 0x03) != 0); // %0xx except %000
        self.io_on      = ((latch & 0x04) != 0) && ((latch & 0x03) != 0); // %1xx except %100
        self.basic_on   = (latch & 0x03) == 3;
        self.kernal_on  = (latch & 0x02) != 0;
    }

    // Write a byte to memory - returns whether RAM was written (true) or RAM under ROM (false)
    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
        // RAM under ROM written? Return false to let us know about it
        if self.get_bank(addr).read_only
        {
            self.ram.write(addr, value);
            return false;
        }
        else
        {
            self.get_bank(addr).write(addr, value);
        }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr < 0x0002 { self.update_memory_latch(); }

        return true;
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        // special location: current memory latch settings
        if addr == 0x0001
        {
            let ddr = self.ram.read(0x0000);
            let pr  = self.ram.read(0x0001);
            return (ddr & pr) | (!ddr & 0x17);
        }

        self.get_bank(addr).read(addr)
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_lo);
        let lo = self.write_byte(addr + 0x0001, value_le_hi);

        return hi && lo;
    }
}

<|endoftext|>


<commit_before>//! Create or redefine SQL functions
use std::ffi::{CStr};
use std::mem;
use std::ptr;
use std::str;
use libc::{c_int, c_double, c_char};

use ffi;
pub use ffi::sqlite3_context as sqlite3_context;
pub use ffi::sqlite3_value as sqlite3_value;
pub use ffi::sqlite3_value_type as sqlite3_value_type;
pub use ffi::sqlite3_value_numeric_type as sqlite3_value_numeric_type;

use types::Null;

use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};

/// A trait for types that can be converted into the result of an SQL function.
pub trait ToResult {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToResult for $t {
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
                ffi::$f(ctx, *self)
            }
        }
    )
);

raw_to_impl!(c_int, sqlite3_result_int);
raw_to_impl!(i64, sqlite3_result_int64);
raw_to_impl!(c_double, sqlite3_result_double);

impl<'a> ToResult for bool {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            true => ffi::sqlite3_result_int(ctx, 1),
            _ => ffi::sqlite3_result_int(ctx, 0),
        }
    }
}

impl<'a> ToResult for &'a str {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        let length = self.len();
        if length > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return
        }
        match str_to_cstring(self) {
            Ok(c_str) => ffi::sqlite3_result_text(ctx, c_str.as_ptr(), length as c_int,
                                                ffi::SQLITE_TRANSIENT()),
            Err(_)    => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error
        }
    }
}

impl ToResult for String {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<'a> ToResult for &'a [u8] {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        if self.len() > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return
        }
        ffi::sqlite3_result_blob(
            ctx, mem::transmute(self.as_ptr()), self.len() as c_int, ffi::SQLITE_TRANSIENT())
    }
}

impl ToResult for Vec<u8> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<T: ToResult> ToResult for Option<T> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            None => ffi::sqlite3_result_null(ctx),
            Some(ref t) => t.set_result(ctx),
        }
    }
}

impl ToResult for Null {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        ffi::sqlite3_result_null(ctx)
    }
}

// sqlite3_result_error_code, c_int
// sqlite3_result_error_nomem
// sqlite3_result_error_toobig
// sqlite3_result_error, *const c_char, c_int
// sqlite3_result_zeroblob
// sqlite3_result_value

/// A trait for types that can be created from a SQLite function parameter value.
pub trait FromValue: Sized {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;

    /// FromValue types can implement this method and use sqlite3_value_type to check that
    /// the type reported by SQLite matches a type suitable for Self. This method is used
    /// by `???` to confirm that the parameter contains a valid type before
    /// attempting to retrieve the value.
    unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
        true
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident, $c:expr) => (
        impl FromValue for $t {
            unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
                Ok(ffi::$f(v))
            }

            unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
                sqlite3_value_numeric_type(v) == $c
            }
        }
    )
);

raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);

impl FromValue for bool {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
        match ffi::sqlite3_value_int(v) {
            0 => Ok(false),
            _ => Ok(true),
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for c_double {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
        Ok(ffi::sqlite3_value_double(v))
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT || sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for String {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_value_text(v);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
            let utf8_str = str::from_utf8(c_slice);
            utf8_str
                .map(|s| { s.to_string() })
                .map_err(|e| { SqliteError{code: 0, message: e.to_string()} })
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_TEXT
    }
}

impl FromValue for Vec<u8> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
        use std::slice::from_raw_parts;
        let c_blob = ffi::sqlite3_value_blob(v);
        let len = ffi::sqlite3_value_bytes(v);

        assert!(len >= 0, "unexpected negative return from sqlite3_value_bytes");
        let len = len as usize;

        Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_BLOB
    }
}

impl<T: FromValue> FromValue for Option<T> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
        if sqlite3_value_type(v) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromValue::parameter_value(v).map(|t| Some(t))
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_NULL ||
            T::parameter_has_valid_sqlite_type(v)
    }
}

// sqlite3_user_data
// sqlite3_get_auxdata
// sqlite3_set_auxdata

pub type ScalarFunc =
    Option<extern "C" fn (ctx: *mut sqlite3_context, argc: c_int, argv: *mut *mut sqlite3_value)>;

impl SqliteConnection {
    // TODO pApp
    pub fn create_scalar_function(&self, fn_name: &str, n_arg: c_int, deterministic: bool, x_func: ScalarFunc) -> SqliteResult<()> {
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
    }
}

impl InnerSqliteConnection {
    pub fn create_scalar_function(&mut self, fn_name: &str, n_arg: c_int, deterministic: bool, x_func: ScalarFunc) -> SqliteResult<()> {
        let c_name = try!(str_to_cstring(fn_name));
        let mut flags = ffi::SQLITE_UTF8;
        if deterministic {
            flags |= ffi::SQLITE_DETERMINISTIC;
        }
        let r = unsafe {
            ffi::sqlite3_create_function_v2(self.db(), c_name.as_ptr(), n_arg, flags, ptr::null_mut(), x_func, None, None, None)
        };
        self.decode_result(r)
    }
}

#[cfg(test)]
mod test {
    extern crate regex;

    use std::boxed::Box;
    use std::ffi::{CString};
    use std::mem;
    use libc::{c_int, c_double, c_void};
    use self::regex::Regex;

    use SqliteConnection;
    use ffi;
    use ffi::sqlite3_context as sqlite3_context;
    use ffi::sqlite3_value as sqlite3_value;
    use functions::{FromValue,ToResult};

    extern "C" fn half(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let arg = *argv.offset(0);
            if c_double::parameter_has_valid_sqlite_type(arg) {
                let value = c_double::parameter_value(arg).unwrap() / 2f64;
                value.set_result(ctx);
            } else {
                ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISMATCH);
            }
        }
    }

    #[test]
    fn test_half() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("half", 1, true, Some(half)).unwrap();
        let result = db.query_row("SELECT half(6)",
                                           &[],
                                           |r| r.get::<f64>(0));

        assert_eq!(3f64, result.unwrap());
    }

    extern "C" fn regexp_free(raw: *mut c_void) {
        let _: Box<Regex> = unsafe {
            Box::from_raw(mem::transmute(raw))
        };
    }

    extern "C" fn regexp(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let mut re_ptr = ffi::sqlite3_get_auxdata(ctx, 0) as *const Regex;
            let need_re = re_ptr.is_null();
            if need_re {
                let raw = String::parameter_value(*argv.offset(0));
                if raw.is_err() {
                    let msg = CString::new(format!("{}", raw.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return
                }
                let comp = Regex::new(raw.unwrap().as_ref());
                if comp.is_err() {
                    let msg = CString::new(format!("{}", comp.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return
                }
                let re = Box::new(comp.unwrap());
                re_ptr = Box::into_raw(re);
            }

            let text = String::parameter_value(*argv.offset(1));
            if text.is_ok() {
                let text = text.unwrap();
                (*re_ptr).is_match(text.as_ref()).set_result(ctx);
            }

            if need_re {
                ffi::sqlite3_set_auxdata(ctx, 0, mem::transmute(re_ptr), Some(regexp_free));
            }
        }
    }

    #[test]
    fn test_regexp() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("regexp", 2, true, Some(regexp)).unwrap();
        let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
                                           &[],
                                           |r| r.get::<bool>(0));

        assert_eq!(true, result.unwrap());
    }
}
<commit_msg>rustfmt - no code changes<commit_after>//! Create or redefine SQL functions
use std::ffi::CStr;
use std::mem;
use std::ptr;
use std::str;
use libc::{c_int, c_double, c_char};

use ffi;
pub use ffi::sqlite3_context;
pub use ffi::sqlite3_value;
pub use ffi::sqlite3_value_type;
pub use ffi::sqlite3_value_numeric_type;

use types::Null;

use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};

/// A trait for types that can be converted into the result of an SQL function.
pub trait ToResult {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToResult for $t {
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
                ffi::$f(ctx, *self)
            }
        }
    )
);

raw_to_impl!(c_int, sqlite3_result_int);
raw_to_impl!(i64, sqlite3_result_int64);
raw_to_impl!(c_double, sqlite3_result_double);

impl<'a> ToResult for bool {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            true => ffi::sqlite3_result_int(ctx, 1),
            _ => ffi::sqlite3_result_int(ctx, 0),
        }
    }
}

impl<'a> ToResult for &'a str {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        let length = self.len();
        if length > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return;
        }
        match str_to_cstring(self) {
            Ok(c_str) => {
                ffi::sqlite3_result_text(ctx,
                                         c_str.as_ptr(),
                                         length as c_int,
                                         ffi::SQLITE_TRANSIENT())
            }
            Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error
        }
    }
}

impl ToResult for String {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<'a> ToResult for &'a [u8] {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        if self.len() > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return;
        }
        ffi::sqlite3_result_blob(ctx,
                                 mem::transmute(self.as_ptr()),
                                 self.len() as c_int,
                                 ffi::SQLITE_TRANSIENT())
    }
}

impl ToResult for Vec<u8> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<T: ToResult> ToResult for Option<T> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            None => ffi::sqlite3_result_null(ctx),
            Some(ref t) => t.set_result(ctx),
        }
    }
}

impl ToResult for Null {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        ffi::sqlite3_result_null(ctx)
    }
}

// sqlite3_result_error_code, c_int
// sqlite3_result_error_nomem
// sqlite3_result_error_toobig
// sqlite3_result_error, *const c_char, c_int
// sqlite3_result_zeroblob
// sqlite3_result_value

/// A trait for types that can be created from a SQLite function parameter value.
pub trait FromValue: Sized {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;

    /// FromValue types can implement this method and use sqlite3_value_type to check that
    /// the type reported by SQLite matches a type suitable for Self. This method is used
    /// by `???` to confirm that the parameter contains a valid type before
    /// attempting to retrieve the value.
    unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
        true
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident, $c:expr) => (
        impl FromValue for $t {
            unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
                Ok(ffi::$f(v))
            }

            unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
                sqlite3_value_numeric_type(v) == $c
            }
        }
    )
);

raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);

impl FromValue for bool {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
        match ffi::sqlite3_value_int(v) {
            0 => Ok(false),
            _ => Ok(true),
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for c_double {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
        Ok(ffi::sqlite3_value_double(v))
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT ||
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for String {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_value_text(v);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
            let utf8_str = str::from_utf8(c_slice);
            utf8_str.map(|s| s.to_string())
                    .map_err(|e| {
                        SqliteError {
                            code: 0,
                            message: e.to_string(),
                        }
                    })
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_TEXT
    }
}

impl FromValue for Vec<u8> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
        use std::slice::from_raw_parts;
        let c_blob = ffi::sqlite3_value_blob(v);
        let len = ffi::sqlite3_value_bytes(v);

        assert!(len >= 0,
                "unexpected negative return from sqlite3_value_bytes");
        let len = len as usize;

        Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_BLOB
    }
}

impl<T: FromValue> FromValue for Option<T> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
        if sqlite3_value_type(v) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromValue::parameter_value(v).map(|t| Some(t))
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_NULL || T::parameter_has_valid_sqlite_type(v)
    }
}

// sqlite3_user_data
// sqlite3_get_auxdata
// sqlite3_set_auxdata

pub type ScalarFunc = Option<extern "C" fn(ctx: *mut sqlite3_context,
                                           argc: c_int,
                                           argv: *mut *mut sqlite3_value)
                                          >;

impl SqliteConnection {
    // TODO pApp
    pub fn create_scalar_function(&self,
                                  fn_name: &str,
                                  n_arg: c_int,
                                  deterministic: bool,
                                  x_func: ScalarFunc)
                                  -> SqliteResult<()> {
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
    }
}

impl InnerSqliteConnection {
    pub fn create_scalar_function(&mut self,
                                  fn_name: &str,
                                  n_arg: c_int,
                                  deterministic: bool,
                                  x_func: ScalarFunc)
                                  -> SqliteResult<()> {
        let c_name = try!(str_to_cstring(fn_name));
        let mut flags = ffi::SQLITE_UTF8;
        if deterministic {
            flags |= ffi::SQLITE_DETERMINISTIC;
        }
        let r = unsafe {
            ffi::sqlite3_create_function_v2(self.db(),
                                            c_name.as_ptr(),
                                            n_arg,
                                            flags,
                                            ptr::null_mut(),
                                            x_func,
                                            None,
                                            None,
                                            None)
        };
        self.decode_result(r)
    }
}

#[cfg(test)]
mod test {
    extern crate regex;

    use std::boxed::Box;
    use std::ffi::CString;
    use std::mem;
    use libc::{c_int, c_double, c_void};
    use self::regex::Regex;

    use SqliteConnection;
    use ffi;
    use ffi::sqlite3_context;
    use ffi::sqlite3_value;
    use functions::{FromValue, ToResult};

    extern "C" fn half(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let arg = *argv.offset(0);
            if c_double::parameter_has_valid_sqlite_type(arg) {
                let value = c_double::parameter_value(arg).unwrap() / 2f64;
                value.set_result(ctx);
            } else {
                ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISMATCH);
            }
        }
    }

    #[test]
    fn test_half() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("half", 1, true, Some(half)).unwrap();
        let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));

        assert_eq!(3f64, result.unwrap());
    }

    extern "C" fn regexp_free(raw: *mut c_void) {
        let _: Box<Regex> = unsafe { Box::from_raw(mem::transmute(raw)) };
    }

    extern "C" fn regexp(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let mut re_ptr = ffi::sqlite3_get_auxdata(ctx, 0) as *const Regex;
            let need_re = re_ptr.is_null();
            if need_re {
                let raw = String::parameter_value(*argv.offset(0));
                if raw.is_err() {
                    let msg = CString::new(format!("{}", raw.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return;
                }
                let comp = Regex::new(raw.unwrap().as_ref());
                if comp.is_err() {
                    let msg = CString::new(format!("{}", comp.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return;
                }
                let re = Box::new(comp.unwrap());
                re_ptr = Box::into_raw(re);
            }

            let text = String::parameter_value(*argv.offset(1));
            if text.is_ok() {
                let text = text.unwrap();
                (*re_ptr).is_match(text.as_ref()).set_result(ctx);
            }

            if need_re {
                ffi::sqlite3_set_auxdata(ctx, 0, mem::transmute(re_ptr), Some(regexp_free));
            }
        }
    }

    #[test]
    fn test_regexp() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("regexp", 2, true, Some(regexp)).unwrap();
        let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
                                  &[],
                                  |r| r.get::<bool>(0));

        assert_eq!(true, result.unwrap());
    }
}
<|endoftext|>


<commit_before>
use parsers::*;
use regex::{Captures, Regex};

/*
pub enum AddOp {
  Add,
  Subtract,
}

pub enum MultOp {
  Multiply,
  Divide,
}
*/

//type AddTerm = (AddOp, Expr);
//type MultTerm = (MultOp, Expr);

#[deriving(Show)]
pub enum Expr {
  Variable(String),
  Num(int),
  Plus(Vec<Expr>),
  //Minus(Vec<Expr>),
  Mult(Vec<Expr>),
  //Divide(Vec<Expr>),
  //AddSub(Vec<AddTerm>), //a + b - c + d becomes [(+ a) (+ b) (- c) (+ d)]
  //MultDiv(Vec<MultTerm>),
}

pub enum Statement {
  Assign(String, Expr),
  Output(Expr),
}

#[deriving(Show)]
#[deriving(Eq)]
#[deriving(PartialEq)]
#[deriving(Clone)]
pub enum Token {
  Equals,
  Ident(String),
  Number(int),
  PlusSign,
  MinusSign,
  MultSign,
  DivideSign,
  OutputCmd,
  NewLine,
  OpenParen,
  CloseParen,
}

pub macro_rules! or {
  ($a: expr, $b: expr : $typ: ty) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| $b,
    } as $typ
 };
  ($a: expr, $b: expr $(, $c: expr)* : $typ: ty) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| or!($b, $($c),* : $typ),
    } as $typ
  };
}
pub macro_rules! seq {
  ($a: expr, $b: expr : $typ: ty) => {
    box DualParser{
      first: $a,
      second: $b,
    } as $typ
 };
  ($a: expr, $b: expr $(, $c: expr)* : $typ: ty) => {
    box DualParser{
      first: $a,
      second: seq!($b, $($c),* : $typ),
    } as $typ
  };
}

pub macro_rules! map {
  ($a: expr, $b: expr) => {
    box MapParser{
      parser: $a,
      mapper: box $b
    }
  }
}

pub macro_rules! link {
  ($a: expr, $b: expr) => {
    box DualParser{
      first: $a,
      second: $b,
    }
  }
}

pub macro_rules! repsep {
  ($rep: expr, $sep: expr, $min: expr) => {
    box RepSepParser{
      rep: $rep,
      sep: $sep,
      min_reps: $min,
    }
  }
}

pub macro_rules! rep {
  ($rep: expr) => {
    box RepParser{
      parser: $rep,
    }
  }
}

type Lexer<'a> = Box<Parser<'a, &'a str, Token> + 'a>;

pub fn token<'a>() -> Box<Parser<'a, &'a str, Vec<Token>> + 'a> {

  macro_rules! literal{
    ($reg: expr, $lit: expr ) => {map!(
      box RegexLiteralParser{regex : Regex::new($reg).unwrap()},
      |&: ()| $lit
    ) as Lexer<'a>}
  }

  //changing these to values creates weird conflicting lifetime errors
  fn ident<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*([a-z]+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Ident(from_str(caps.at(1)).unwrap())
  )}

  fn number<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*(\d+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Number(from_str(caps.at(1)).unwrap())
  )}

  box RepParser{
    parser: or!(
      literal!(r"^[ \t]*out", OutputCmd),
      literal!(r"^[ \t]*\r?\n[ \t]*", NewLine),
      literal!(r"^[ \t]*\(", OpenParen),
      literal!(r"^[ \t]*\)", CloseParen),
      number(),
      literal!(r"^[ \t]*\+", PlusSign),
      literal!(r"^[ \t]*=", Equals),
      ident(),
      literal!(r"^[ \t]*\*", MultSign)
      : Lexer<'a>
    )
  }

}

type LParser<'a> = Box<Parser<'a, &'a [Token], Expr> + 'a>;

fn assign<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser: box DualParser {
      first: box DualParser {
        first: variable(),
        second: literal(Equals),
      },
      second: expr()
    },
    mapper: box |&: ((var, _), expr): ((Expr, Token), Expr)| -> Statement match var{
      Variable(name) => Assign(name, expr),
      _ => panic!("FUCK")
    }
  }
}

fn output<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser : box DualParser {
      first: literal(OutputCmd),
      second: expr(),
    },
    mapper: box |&: (_, var): (Token, Expr)| Output(var)
  }
}

pub fn statement<'a>() -> Box<Parser<'a, &'a [Token], Vec<Statement>> + 'a> {
  rep!(
    map!(
      seq!(
        or!(output(), assign(): Box<Parser<'a, &'a [Token], Statement>>),
        literal(NewLine)
        : Box<Parser<'a, &'a [Token], (Statement, Token)>>
      ),
      |&: (stmt, _): (Statement, Token)| stmt
    )
  )
}

fn variable<'a>() -> LParser<'a> {
  box MatchParser{
    matcher: box |&: input: &Token| match input {
      &Ident(ref str) => Ok(Variable(str.clone())),
      other => Err(format!("Expected variable, got {}", other))
    }
  }
}

fn expr<'a>() -> LParser<'a> {

  fn match_num<'a>() -> Box<Parser<'a, &'a[Token], Expr> + 'a> {
    box MatchParser{matcher: box |&: input: &Token| -> Result<Expr, String> match input {
      &Number(num) => Ok(Num(num)),
      other => Err(format!("wrong type, expected number, got {}", other))
    }}
  }

  fn term<'a>() -> LParser<'a> {
    box OrParser{
      a: box |&:| paren_expr(),
      b: box |&:| box OrParser {
        a: box |&:| variable(),
        b: box |&:| match_num(),
      } as LParser<'a>
    }
  }

  fn mult<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: term(),
        sep: literal(MultSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Mult(ops)
    }
  }

  fn simple_expr<'a>() -> LParser<'a> {
    box OrParser{
      b: box |&:| term(),
      a: box |&:| mult()
    }
  }

  fn plus<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: simple_expr(),
        sep: literal(PlusSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Plus(ops)
    }
  }

  fn paren_expr<'a>() -> LParser<'a> {
    box MapParser {
      parser: box DualParser {
        first: box DualParser {
          first: literal(OpenParen),
          second: expr(),
        },
        second: literal(CloseParen),
      },
      mapper: box |&: ((_, e), _): ((Token, Expr), Token)| e
    }
  }

  let expr = box OrParser{
      a: box |&:| plus(),
      b: box |&:| simple_expr(),
  };

  expr
}
<commit_msg>new arithmetic model<commit_after>
use parsers::*;
use regex::{Captures, Regex};

pub enum AddOp {
  Add,
  Subtract,
}

pub enum MultOp {
  Multiply,
  Divide,
}

type AddTerm = (AddOp, Expr);
type MultTerm = (MultOp, Expr);

#[deriving(Show)]
pub enum Expr {
  Variable(String),
  Num(int),
  AddSub(Vec<AddTerm>), //a + b - c + d becomes [(+ a) (+ b) (- c) (+ d)]
  MultDiv(Vec<MultTerm>),
}

pub enum Statement {
  Assign(String, Expr),
  Output(Expr),
}

#[deriving(Show)]
#[deriving(Eq)]
#[deriving(PartialEq)]
#[deriving(Clone)]
pub enum Token {
  Equals,
  Ident(String),
  Number(int),
  PlusSign,
  MinusSign,
  MultSign,
  DivideSign,
  OutputCmd,
  NewLine,
  OpenParen,
  CloseParen,
}

pub macro_rules! or {
  ($a: expr, $b: expr : $typ: ty) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| $b,
    } as $typ
 };
  ($a: expr, $b: expr $(, $c: expr)* : $typ: ty) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| or!($b, $($c),* : $typ),
    } as $typ
  };
}
pub macro_rules! seq {
  ($a: expr, $b: expr : $typ: ty) => {
    box DualParser{
      first: $a,
      second: $b,
    } as $typ
 };
  ($a: expr, $b: expr $(, $c: expr)* : $typ: ty) => {
    box DualParser{
      first: $a,
      second: seq!($b, $($c),* : $typ),
    } as $typ
  };
}

pub macro_rules! map {
  ($a: expr, $b: expr) => {
    box MapParser{
      parser: $a,
      mapper: box $b
    }
  }
}

pub macro_rules! link {
  ($a: expr, $b: expr) => {
    box DualParser{
      first: $a,
      second: $b,
    }
  }
}

pub macro_rules! repsep {
  ($rep: expr, $sep: expr, $min: expr) => {
    box RepSepParser{
      rep: $rep,
      sep: $sep,
      min_reps: $min,
    }
  }
}

pub macro_rules! rep {
  ($rep: expr) => {
    box RepParser{
      parser: $rep,
    }
  }
}

type Lexer<'a> = Box<Parser<'a, &'a str, Token> + 'a>;

pub fn token<'a>() -> Box<Parser<'a, &'a str, Vec<Token>> + 'a> {

  macro_rules! literal{
    ($reg: expr, $lit: expr ) => {map!(
      box RegexLiteralParser{regex : Regex::new($reg).unwrap()},
      |&: ()| $lit
    ) as Lexer<'a>}
  }

  //changing these to values creates weird conflicting lifetime errors
  fn ident<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*([a-z]+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Ident(from_str(caps.at(1)).unwrap())
  )}

  fn number<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*(\d+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Number(from_str(caps.at(1)).unwrap())
  )}

  box RepParser{
    parser: or!(
      literal!(r"^[ \t]*out", OutputCmd),
      literal!(r"^[ \t]*\r?\n[ \t]*", NewLine),
      literal!(r"^[ \t]*\(", OpenParen),
      literal!(r"^[ \t]*\)", CloseParen),
      number(),
      literal!(r"^[ \t]*\+", PlusSign),
      literal!(r"^[ \t]*=", Equals),
      ident(),
      literal!(r"^[ \t]*\*", MultSign)
      : Lexer<'a>
    )
  }

}

type LParser<'a> = Box<Parser<'a, &'a [Token], Expr> + 'a>;

fn assign<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser: box DualParser {
      first: box DualParser {
        first: variable(),
        second: literal(Equals),
      },
      second: expr()
    },
    mapper: box |&: ((var, _), expr): ((Expr, Token), Expr)| -> Statement match var{
      Variable(name) => Assign(name, expr),
      _ => panic!("FUCK")
    }
  }
}

fn output<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser : box DualParser {
      first: literal(OutputCmd),
      second: expr(),
    },
    mapper: box |&: (_, var): (Token, Expr)| Output(var)
  }
}

pub fn statement<'a>() -> Box<Parser<'a, &'a [Token], Vec<Statement>> + 'a> {
  rep!(
    map!(
      seq!(
        or!(output(), assign(): Box<Parser<'a, &'a [Token], Statement>>),
        literal(NewLine)
        : Box<Parser<'a, &'a [Token], (Statement, Token)>>
      ),
      |&: (stmt, _): (Statement, Token)| stmt
    )
  )
}

fn variable<'a>() -> LParser<'a> {
  box MatchParser{
    matcher: box |&: input: &Token| match input {
      &Ident(ref str) => Ok(Variable(str.clone())),
      other => Err(format!("Expected variable, got {}", other))
    }
  }
}

fn expr<'a>() -> LParser<'a> {

  fn match_num<'a>() -> Box<Parser<'a, &'a[Token], Expr> + 'a> {
    box MatchParser{matcher: box |&: input: &Token| -> Result<Expr, String> match input {
      &Number(num) => Ok(Num(num)),
      other => Err(format!("wrong type, expected number, got {}", other))
    }}
  }

  fn term<'a>() -> LParser<'a> {
    box OrParser{
      a: box |&:| paren_expr(),
      b: box |&:| box OrParser {
        a: box |&:| variable(),
        b: box |&:| match_num(),
      } as LParser<'a>
    }
  }

  fn mult<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: term(),
        sep: literal(MultSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Mult(ops)
    }
  }

  fn simple_expr<'a>() -> LParser<'a> {
    box OrParser{
      b: box |&:| term(),
      a: box |&:| mult()
    }
  }

  fn plus<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: simple_expr(),
        sep: literal(PlusSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Plus(ops)
    }
  }

  fn paren_expr<'a>() -> LParser<'a> {
    box MapParser {
      parser: box DualParser {
        first: box DualParser {
          first: literal(OpenParen),
          second: expr(),
        },
        second: literal(CloseParen),
      },
      mapper: box |&: ((_, e), _): ((Token, Expr), Token)| e
    }
  }

  let expr = box OrParser{
      a: box |&:| plus(),
      b: box |&:| simple_expr(),
  };

  expr
}
<|endoftext|>


<commit_before>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )* }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = { string_literal |
                    array_literal |
                    object_literal |
                    number_literal |
                    null_literal |
                    boolean_literal }

        null_literal = { ["null"] }
        boolean_literal = { ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["<"]|[">"]|["-"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
        name = _{ subexpression | reference }

        param = { !["as"] ~ (literal | reference | subexpression) }
        hash = { identifier ~ ["="] ~ param }
        block_param = { ["as"] ~ ["|"] ~ identifier ~ identifier? ~ ["|"]}
        exp_line = _{ identifier ~ (hash|param)* ~ block_param?}

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        pre_whitespace_omitter = { ["~"] }
        pro_whitespace_omitter = { ["~"] }

        expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
                        pro_whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ pre_whitespace_omitter? ~ name ~
                                      pro_whitespace_omitter? ~ ["}}}"] }

        helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        pro_whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                      pro_whitespace_omitter? ~ ["}}"] }
        helper_block = _{ helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                         helper_block_end }

        raw_block_start = { ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                                       pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                     pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

        hbs_comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_expression |
            helper_block |
            raw_block |
            hbs_comment )*
        }

        parameter = _{ param ~ eoi }
        handlebars = _{ template ~ eoi }

// json path visitor
        path_ident = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["@"]|["$"]|["<"]|[">"]|["-"]}
        path_id = { path_ident+ }
        path_num_id = { ['0'..'9']+ }
        path_raw_id = { path_ident* }
        path_this = { ["this"] }
        path_sep = _{ ["/"] | ["."] }
        path_up = { [".."] }
        path_var = { path_id }
        path_key = { ["["] ~ (["\""]|["'"])? ~ path_raw_id ~ (["\""]|["'"])? ~ ["]"] }
        path_idx = { ["["] ~ path_num_id ~ ["]"]}
        path_item = _{ path_this|path_up|path_var }
        path = _{ ["./"]? ~ path_item ~ ((path_sep ~ path_item) | (path_sep? ~  (path_key | path_idx)))* ~ eoi }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]",
                 "some-name",
                 "this.[0].ok"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hbs_comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.subexpression());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_expression() {
    let s = vec!["{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}",
                 "{{exp key=1}}",
                 "{{exp key=ref}}",
                 "{{exp key=(sub)}}",
                 "{{exp key=(sub 0)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}",
                 "{{#each people as |person|}}",
                 "{{#each-obj obj as |key val|}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_block_param() {
    let s = vec!["as |person|", "as |key val|"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.block_param());
        assert!(rdp.end());
    }
}

#[test]
fn test_path() {
    let s = vec!["a.b.c.d",
                 "a[0][1][2]",
                 "a[\"abc\"]",
                 "a/v/c.d.s",
                 "a[0]/b/c/../d",
                 "a[\"bbc\"]/b/c/../d",
                 "../a/b[0][1]",
                 "./this[0][1]/this/../a"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.path());
        assert!(rdp.end());
    }
}
<commit_msg>(feat) added directive syntax<commit_after>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )* }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = { string_literal |
                    array_literal |
                    object_literal |
                    number_literal |
                    null_literal |
                    boolean_literal }

        null_literal = { ["null"] }
        boolean_literal = { ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["<"]|[">"]|["-"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
        name = _{ subexpression | reference }

        param = { !["as"] ~ (literal | reference | subexpression) }
        hash = { identifier ~ ["="] ~ param }
        block_param = { ["as"] ~ ["|"] ~ identifier ~ identifier? ~ ["|"]}
        exp_line = _{ identifier ~ (hash|param)* ~ block_param?}

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        pre_whitespace_omitter = { ["~"] }
        pro_whitespace_omitter = { ["~"] }

        expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
                        pro_whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ pre_whitespace_omitter? ~ name ~
                                      pro_whitespace_omitter? ~ ["}}}"] }

        helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        directive_expression = { ["{{"] ~ pre_whitespace_omitter? ~ ["*"] ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        pro_whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                      pro_whitespace_omitter? ~ ["}}"] }
        helper_block = _{ helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                          helper_block_end }

        directive_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ ["*"] ~ exp_line ~
                                           pro_whitespace_omitter? ~ ["}}"] }
        directive_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                         pro_whitespace_omitter? ~ ["}}"] }
        directive_block = _{ directive_block_start ~ template ~
                             directive_block_end }

        raw_block_start = { ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                                       pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                     pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

        hbs_comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_expression |
            helper_block |
            raw_block |
            hbs_comment |
            directive_expression |
            directive_block )*
        }

        parameter = _{ param ~ eoi }
        handlebars = _{ template ~ eoi }

// json path visitor
        path_ident = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["@"]|["$"]|["<"]|[">"]|["-"]}
        path_id = { path_ident+ }
        path_num_id = { ['0'..'9']+ }
        path_raw_id = { path_ident* }
        path_this = { ["this"] }
        path_sep = _{ ["/"] | ["."] }
        path_up = { [".."] }
        path_var = { path_id }
        path_key = { ["["] ~ (["\""]|["'"])? ~ path_raw_id ~ (["\""]|["'"])? ~ ["]"] }
        path_idx = { ["["] ~ path_num_id ~ ["]"]}
        path_item = _{ path_this|path_up|path_var }
        path = _{ ["./"]? ~ path_item ~ ((path_sep ~ path_item) | (path_sep? ~  (path_key | path_idx)))* ~ eoi }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]",
                 "some-name",
                 "this.[0].ok"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hbs_comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.subexpression());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_expression() {
    let s = vec!["{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}",
                 "{{exp key=1}}",
                 "{{exp key=ref}}",
                 "{{exp key=(sub)}}",
                 "{{exp key=(sub 0)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}",
                 "{{#each people as |person|}}",
                 "{{#each-obj obj as |key val|}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_block_param() {
    let s = vec!["as |person|", "as |key val|"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.block_param());
        assert!(rdp.end());
    }
}

#[test]
fn test_path() {
    let s = vec!["a.b.c.d",
                 "a[0][1][2]",
                 "a[\"abc\"]",
                 "a/v/c.d.s",
                 "a[0]/b/c/../d",
                 "a[\"bbc\"]/b/c/../d",
                 "../a/b[0][1]",
                 "./this[0][1]/this/../a"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.path());
        assert!(rdp.end());
    }
}

#[test]
fn test_directive_expression() {
    let s = vec!["{{* ssh}}", "{{~* ssh}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.directive_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_directive_block() {
    let s = vec!["{{#* inline}}something{{/inline}}",
                 "{{~#* inline}}hello{{/inline}}",
                 "{{#* inline \"partialname\"}}something{{/inline}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.directive_block());
        assert!(rdp.end());
    }
}
<|endoftext|>