<commit_before>// FIXME This is the simplest most naive implementation of an allocator. I
// basically envisioned it in C in my head and translated it on the fly. I hope
// to revisit this someday when I know the language better, but in the meantime
// don't take this as an example for anything ever.

#![allocator]

use core::cmp;
use core::ptr;
use core::mem;

use self::spin::Mutex;

extern crate spin;

const SPLIT_FUDGE_FACTOR: usize = 32;

#[repr(C)]
struct Region {
    size: usize,
    prev: Option<*mut Region>,
    next: Option<*mut Region>,
}

pub struct Allocator {
    heap_start: *mut u8,
    heap_size: usize,
    free_list: Option<*mut Region>,
}

static mut ALLOCATOR: Mutex<Allocator> = Mutex::new(Allocator{
    heap_start: 0 as *mut u8,
    heap_size: 0,
    free_list: None
});

pub fn init_global_allocator(size: u64, raw_bytes: *mut u8) {
    static mut CALLED: bool = false;

    unsafe {
        assert!(!CALLED);
        init_allocator(&mut ALLOCATOR.lock(), size as usize, raw_bytes);
        CALLED = true;
    }
}

pub fn init_allocator(allocator: &mut Allocator, size: usize, raw_bytes: *mut u8) {

    assert!(!raw_bytes.is_null());

    let mut region = raw_bytes as *mut Region;
    unsafe{
        (*region).size = size;
        (*region).next = None;
        (*region).prev = None;
    }
    allocator.heap_size = size;
    allocator.heap_start = raw_bytes;
    allocator.free_list = Some(raw_bytes as *mut Region);
}

/*
impl Default for Allocator {
    fn default() -> Self {
        Allocator{ heap_start: 0 as *mut u8, heap_size: 0, free_list: None}
    }
}
*/

impl Allocator {

    pub fn free(&mut self, bytes: *mut u8) {

        let mut region: *mut Region;

        if bytes.is_null() {
            return;
        }

        unsafe {
            let offset = -(mem::size_of::<Region>() as isize);
            region = bytes.offset(offset) as *mut Region;

            assert!(region as *mut u8 >= self.heap_start);

            assert!(!region.is_null());

            (*region).prev = None;
            (*region).next = self.free_list;
        }

        self.free_list = Some(region);
    }

    pub fn alloc(&mut self, size: usize) -> *mut u8 {

        let region_offset = mem::size_of::<Region>() as isize;
        let real_size = size + mem::size_of::<Region>();
        let mut current_region = self.free_list;

        while let Some(region) = current_region {

            unsafe {
                if (*region).size >= real_size {
                    let new_next: Option<*mut Region>;
                    let new_prev: Option<*mut Region>;
                    let split = (*region).size - real_size;
                    if split > (region_offset as usize) + SPLIT_FUDGE_FACTOR {
                         let split_region =
                             (region as *mut u8).offset((size as isize) + region_offset) as *mut Region;
                         new_next = Some(split_region);
                         new_prev = Some(split_region);
                    } else {
                        new_next = (*region).next;
                        new_prev = (*region).prev;
                    }
                    match (*region).prev {
                        None => {},
                        Some(prev) => (*prev).next = new_next,
                    }
                    match (*region).next {
                        None => {},
                        Some(next) => (*next).prev = new_prev,
                    }
                    if new_next == None && new_prev == None {
                        self.free_list = None;
                    }
                    return (region as *mut u8).offset(region_offset);
                }
                current_region = (*region).next;
            }
        }

        ptr::null::<u8>() as *mut u8
    }
}

#[no_mangle]
pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
    unsafe {
        ALLOCATOR.lock().alloc(size)
    }
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
    unsafe {
        ALLOCATOR.lock().free(ptr);
    }
}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, new_size: usize,
                                align: usize) -> *mut u8 {
    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(old_size, new_size)) };
    __rust_deallocate(ptr, old_size, align);
    new_ptr
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
                                        _size: usize, _align: usize) -> usize {
        old_size
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
        size
}

#[cfg(test)]
mod tests {
    use super::Allocator;
    use super::Region;
    use super::init_allocator;

    #[test]
    fn test_init_allocator() {

        let mut al = Allocator{
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 100] = [0; 100];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        //init_allocator(&mut al, mem::size_of::<[u8; 100]>(), pmemory);
        init_allocator(&mut al, 100, pmemory);
        assert_eq!(al.heap_size, 100);
        assert_eq!(al.heap_start, pmemory);

        match al.free_list {
            None => assert!(false),
            Some(fl) => {
                assert!(!fl.is_null());
                unsafe {
                    assert_eq!((*fl).size, 100);
                    assert_eq!((*fl).next, None);
                };
            }
        }
    }

    #[test]
    fn test_alloc_and_free() {

        let mut al = Allocator{
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 1000] = [0; 1000];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        init_allocator(&mut al, mem::size_of::<[u8; 1000]>(), pmemory);

        let m0_size = 10000 - mem::size_of::<Region>();
        let m0 = al.alloc(m0_size);
        assert!(m0.is_null());

        let m1_size = 1000 - mem::size_of::<Region>();
        let m1 = al.alloc(m1_size);
        assert!(!m1.is_null());

        assert_eq!(al.free_list, None);
        al.free(m1);
        assert_ne!(al.free_list, None);

        let m2_size = 100;
        let m2 = al.alloc(m2_size);
        assert!(!m2.is_null());

        let m3_size = 10;
        let m3 = al.alloc(m3_size);
        assert!(!m3.is_null());

        let m4_size = 1;
        let m4 = al.alloc(m4_size);
        assert!(!m4.is_null());

        assert_ne!(al.free_list, None);
        al.free(m3);

        assert_ne!(al.free_list, None);
        al.free(m2);

        assert_ne!(al.free_list, None);
        al.free(m4);
    }
}
<commit_msg>Remove commented out code<commit_after>// FIXME This is the simplest most naive implementation of an allocator. I
// basically envisioned it in C in my head and translated it on the fly. I hope
// to revisit this someday when I know the language better, but in the meantime
// don't take this as an example for anything ever.

#![allocator]

use core::cmp;
use core::ptr;
use core::mem;

use self::spin::Mutex;

extern crate spin;

const SPLIT_FUDGE_FACTOR: usize = 32;

#[repr(C)]
struct Region {
    size: usize,
    prev: Option<*mut Region>,
    next: Option<*mut Region>,
}

pub struct Allocator {
    heap_start: *mut u8,
    heap_size: usize,
    free_list: Option<*mut Region>,
}

static mut ALLOCATOR: Mutex<Allocator> = Mutex::new(Allocator{
    heap_start: 0 as *mut u8,
    heap_size: 0,
    free_list: None
});

pub fn init_global_allocator(size: u64, raw_bytes: *mut u8) {
    static mut CALLED: bool = false;

    unsafe {
        assert!(!CALLED);
        init_allocator(&mut ALLOCATOR.lock(), size as usize, raw_bytes);
        CALLED = true;
    }
}

pub fn init_allocator(allocator: &mut Allocator, size: usize, raw_bytes: *mut u8) {

    assert!(!raw_bytes.is_null());

    let mut region = raw_bytes as *mut Region;
    unsafe{
        (*region).size = size;
        (*region).next = None;
        (*region).prev = None;
    }
    allocator.heap_size = size;
    allocator.heap_start = raw_bytes;
    allocator.free_list = Some(raw_bytes as *mut Region);
}

impl Allocator {

    pub fn free(&mut self, bytes: *mut u8) {

        let mut region: *mut Region;

        if bytes.is_null() {
            return;
        }

        unsafe {
            let offset = -(mem::size_of::<Region>() as isize);
            region = bytes.offset(offset) as *mut Region;

            assert!(region as *mut u8 >= self.heap_start);

            assert!(!region.is_null());

            (*region).prev = None;
            (*region).next = self.free_list;
        }

        self.free_list = Some(region);
    }

    pub fn alloc(&mut self, size: usize) -> *mut u8 {

        let region_offset = mem::size_of::<Region>() as isize;
        let real_size = size + mem::size_of::<Region>();
        let mut current_region = self.free_list;

        while let Some(region) = current_region {

            unsafe {
                if (*region).size >= real_size {
                    let new_next: Option<*mut Region>;
                    let new_prev: Option<*mut Region>;
                    let split = (*region).size - real_size;
                    if split > (region_offset as usize) + SPLIT_FUDGE_FACTOR {
                         let split_region =
                             (region as *mut u8).offset((size as isize) + region_offset) as *mut Region;
                         new_next = Some(split_region);
                         new_prev = Some(split_region);
                    } else {
                        new_next = (*region).next;
                        new_prev = (*region).prev;
                    }
                    match (*region).prev {
                        None => {},
                        Some(prev) => (*prev).next = new_next,
                    }
                    match (*region).next {
                        None => {},
                        Some(next) => (*next).prev = new_prev,
                    }
                    if new_next == None && new_prev == None {
                        self.free_list = None;
                    }
                    return (region as *mut u8).offset(region_offset);
                }
                current_region = (*region).next;
            }
        }

        ptr::null::<u8>() as *mut u8
    }
}

#[no_mangle]
pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
    unsafe {
        ALLOCATOR.lock().alloc(size)
    }
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
    unsafe {
        ALLOCATOR.lock().free(ptr);
    }
}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, new_size: usize,
                                align: usize) -> *mut u8 {
    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(old_size, new_size)) };
    __rust_deallocate(ptr, old_size, align);
    new_ptr
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
                                        _size: usize, _align: usize) -> usize {
        old_size
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
        size
}

#[cfg(test)]
mod tests {
    use super::Allocator;
    use super::Region;
    use super::init_allocator;

    #[test]
    fn test_init_allocator() {

        let mut al = Allocator{
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 100] = [0; 100];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        //init_allocator(&mut al, mem::size_of::<[u8; 100]>(), pmemory);
        init_allocator(&mut al, 100, pmemory);
        assert_eq!(al.heap_size, 100);
        assert_eq!(al.heap_start, pmemory);

        match al.free_list {
            None => assert!(false),
            Some(fl) => {
                assert!(!fl.is_null());
                unsafe {
                    assert_eq!((*fl).size, 100);
                    assert_eq!((*fl).next, None);
                };
            }
        }
    }

    #[test]
    fn test_alloc_and_free() {

        let mut al = Allocator{
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 1000] = [0; 1000];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        init_allocator(&mut al, mem::size_of::<[u8; 1000]>(), pmemory);

        let m0_size = 10000 - mem::size_of::<Region>();
        let m0 = al.alloc(m0_size);
        assert!(m0.is_null());

        let m1_size = 1000 - mem::size_of::<Region>();
        let m1 = al.alloc(m1_size);
        assert!(!m1.is_null());

        assert_eq!(al.free_list, None);
        al.free(m1);
        assert_ne!(al.free_list, None);

        let m2_size = 100;
        let m2 = al.alloc(m2_size);
        assert!(!m2.is_null());

        let m3_size = 10;
        let m3 = al.alloc(m3_size);
        assert!(!m3.is_null());

        let m4_size = 1;
        let m4 = al.alloc(m4_size);
        assert!(!m4.is_null());

        assert_ne!(al.free_list, None);
        al.free(m3);

        assert_ne!(al.free_list, None);
        al.free(m2);

        assert_ne!(al.free_list, None);
        al.free(m4);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

//! # Cap'n Proto Runtime Library
//!
//! [Cap'n Proto](http://kentonv.github.io/capnproto/) is an extremely efficient protocol for
//! sharing data and capabilities.
//!
//! The Rust implementation is split into three separate crates.
//!
//! Code generation is handled by [capnpc-rust](https://github.com/dwrensha/capnpc-rust).
//!
//! The present crate is the runtime library required by that generated code. It is hosted on Github
//! [here](https://github.com/dwrensha/capnproto-rust).
//!
//! [capnp-rpc-rust](https://github.com/dwrensha/capnp-rpc-rust) is an implementation of a
//! distributed object-capability layer.

#![feature(phase)]
#![allow(experimental)]
#![feature(unsafe_destructor)]
#![allow(raw_pointer_derive)]

#![crate_name="capnp"]
#![crate_type = "lib"]

// import logging macros
#[macro_use] extern crate log;
extern crate libc;

// reexports
pub use blob::{text, data};
pub use common::{MessageSize};
pub use list::{primitive_list, enum_list, struct_list, text_list, data_list, list_list};
pub use message::{MessageBuilder, BuilderOptions, MessageReader, ReaderOptions};
pub use message::MallocMessageBuilder;
pub use serialize::OwnedSpaceMessageReader;

pub mod any_pointer;
pub mod arena;
pub mod blob;
pub mod capability;
pub mod common;
pub mod endian;
pub mod io;
pub mod layout;
pub mod list;
pub mod mask;
pub mod message;
pub mod serialize;
pub mod serialize_packed;
pub mod traits;

#[cfg(test)]
pub mod layout_test;
#[cfg(test)]
pub mod serialize_packed_test;

<commit_msg>drop feature(phase)<commit_after>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

//! # Cap'n Proto Runtime Library
//!
//! [Cap'n Proto](http://kentonv.github.io/capnproto/) is an extremely efficient protocol for
//! sharing data and capabilities.
//!
//! The Rust implementation is split into three separate crates.
//!
//! Code generation is handled by [capnpc-rust](https://github.com/dwrensha/capnpc-rust).
//!
//! The present crate is the runtime library required by that generated code. It is hosted on Github
//! [here](https://github.com/dwrensha/capnproto-rust).
//!
//! [capnp-rpc-rust](https://github.com/dwrensha/capnp-rpc-rust) is an implementation of a
//! distributed object-capability layer.

#![allow(experimental)]
#![feature(unsafe_destructor)]
#![allow(raw_pointer_derive)]

#![crate_name="capnp"]
#![crate_type = "lib"]

// import logging macros
#[macro_use] extern crate log;
extern crate libc;

// reexports
pub use blob::{text, data};
pub use common::{MessageSize};
pub use list::{primitive_list, enum_list, struct_list, text_list, data_list, list_list};
pub use message::{MessageBuilder, BuilderOptions, MessageReader, ReaderOptions};
pub use message::MallocMessageBuilder;
pub use serialize::OwnedSpaceMessageReader;

pub mod any_pointer;
pub mod arena;
pub mod blob;
pub mod capability;
pub mod common;
pub mod endian;
pub mod io;
pub mod layout;
pub mod list;
pub mod mask;
pub mod message;
pub mod serialize;
pub mod serialize_packed;
pub mod traits;

#[cfg(test)]
pub mod layout_test;
#[cfg(test)]
pub mod serialize_packed_test;

<|endoftext|>


<commit_before>pub fn alive_or_dead(o_p: &mut Vec<i32>, t_p: &mut Vec<i32>) {
    for x in 0..o_p.len() - 1 {
        if t_p[x] == o_p[x] && t_p[x + 1] == o_p[x + 1]{
            println!("DEAD");
        } else {
            println!("ALIVE");
        }
    }
}

#[test]
fn it_can_log_all_positions() {
    let mut two_pos = vec![];
    let mut all_pos = vec![];

}
<commit_msg>notes for tomorrow - collision improvement or new project # Learning goals acheived<commit_after>pub fn alive_or_dead(o_p: &mut Vec<i32>, t_p: &mut Vec<i32>) {
    for x in 0..o_p.len() - 1 {
        if t_p[x] == o_p[x] && t_p[x + 1] == o_p[x + 1]{
            println!("DEAD");
        } else {
            println!("ALIVE");
        }
    }
}

// work on deciding to not have trails or to keep trails

// trails are in the combined array

// basic collision is comparing latests positions

// complex collision is checking position to all previous positions

#[test]
fn it_can_log_all_positions() {
    let mut two_pos = vec![];
    let mut all_pos = vec![];
}
<|endoftext|>


<commit_before>/// 2D geometric vector.
#[deriving(Show, PartialEq, PartialOrd, Clone, Decodable, Encodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Add<U, V>, U, V> Add<V2<U>, V2<V>> for V2<T> {
    fn add(&self, rhs: &V2<U>) -> V2<V> { V2(self.0 + rhs.0, self.1 + rhs.1) }
}

impl<T: Sub<U, V>, U, V> Sub<V2<U>, V2<V>> for V2<T> {
    fn sub(&self, rhs: &V2<U>) -> V2<V> { V2(self.0 - rhs.0, self.1 - rhs.1) }
}

impl<T: Neg<U>, U> Neg<V2<U>> for V2<T> {
    fn neg(&self) -> V2<U> { V2(-self.0, -self.1) }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T, ..2] { [self.0, self.1] }
}

impl<T> V2<T> {
    pub fn map<U>(self, f: |T| -> U) -> V2<U> { V2(f(self.0), f(self.1)) }
}

impl<T: Primitive> V2<T> {
    // Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> { V2(self.0 * rhs.0, self.1 * rhs.1) }
}

/// A rectangle type consisting of position and size vectors.
#[deriving(Show, PartialEq, PartialOrd, Clone, Decodable, Encodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Primitive> Rect<T> {
    pub fn area(&self) -> T { (self.1).0 * (self.1).1 }

    pub fn mn(&self) -> V2<T> { self.0 }

    pub fn mx(&self) -> V2<T> { self.0 + self.1 }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }
}
<commit_msg>Vec multiplication<commit_after>/// 2D geometric vector.
#[deriving(Show, PartialEq, PartialOrd, Clone, Decodable, Encodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Add<U, V>, U, V> Add<V2<U>, V2<V>> for V2<T> {
    fn add(&self, rhs: &V2<U>) -> V2<V> { V2(self.0 + rhs.0, self.1 + rhs.1) }
}

impl<T: Sub<U, V>, U, V> Sub<V2<U>, V2<V>> for V2<T> {
    fn sub(&self, rhs: &V2<U>) -> V2<V> { V2(self.0 - rhs.0, self.1 - rhs.1) }
}

impl<T: Neg<U>, U> Neg<V2<U>> for V2<T> {
    fn neg(&self) -> V2<U> { V2(-self.0, -self.1) }
}

impl<T: Mul<U, V>, U, V> Mul<U, V2<V>> for V2<T> {
    fn mul(&self, rhs: &U) -> V2<V> { V2(self.0 * *rhs, self.1 * *rhs) }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T, ..2] { [self.0, self.1] }
}

impl<T> V2<T> {
    pub fn map<U>(self, f: |T| -> U) -> V2<U> { V2(f(self.0), f(self.1)) }
}

impl<T: Primitive> V2<T> {
    // Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> { V2(self.0 * rhs.0, self.1 * rhs.1) }
}

/// A rectangle type consisting of position and size vectors.
#[deriving(Show, PartialEq, PartialOrd, Clone, Decodable, Encodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Primitive> Rect<T> {
    pub fn area(&self) -> T { (self.1).0 * (self.1).1 }

    pub fn mn(&self) -> V2<T> { self.0 }

    pub fn mx(&self) -> V2<T> { self.0 + self.1 }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }
}
<|endoftext|>


<commit_before>// An item is line of text that read from `find` command or stdin together with
// the internal states, such as selected or not

use ansi::ANSIParser;
use curses::attr_t;
use field::*;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::default::Default;
use std::sync::Arc;

// An item will store everything that one line input will need to be operated and displayed.
//
// What's special about an item?
// The simplest version of an item is a line of string, but things are getting more complex:
// - The conversion of lower/upper case is slow in rust, because it involds unicode.
// - We may need to interpret the ANSI codes in the text.
// - The text can be transformed and limited while searching.

// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
// more than one line.

#[derive(Debug)]
pub struct Item {
    // (num of run, number of index)
    index: (usize, usize),

    // The text that will be ouptut when user press `enter`
    orig_text: String,

    // The text that will shown into the screen. Can be transformed.
    text: String,

    // cache of the lower case version of text. To improve speed
    chars: Vec<char>,

    // the ansi state (color) of the text
    ansi_states: Vec<(usize, attr_t)>,
    matching_ranges: Vec<(usize, usize)>,

    // For the transformed ANSI case, the output will need another transform.
    using_transform_fields: bool,
    ansi_enabled: bool,
}

impl<'a> Item {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
        index: (usize, usize),
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (text, states_text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields))
        } else if using_transform_fields {
            // transformed, not ansi
            (parse_transform_fields(delimiter, &orig_text, trans_fields), Vec::new())
        } else if ansi_enabled {
            // not transformed, ansi
            ansi_parser.parse_ansi(&orig_text)
        } else {
            // normal case
            ("".to_string(), Vec::new())
        };

        let mut ret = Item {
            index: index,
            orig_text,
            text: text,
            chars: Vec::new(),
            ansi_states: states_text,
            using_transform_fields: !trans_fields.is_empty(),
            matching_ranges: Vec::new(),
            ansi_enabled: ansi_enabled,
        };

        let chars: Vec<char> = if ret.get_text().as_bytes().is_ascii() {
            ret.get_text().as_bytes().iter().map(|&s| s as char).collect()
        } else {
            ret.get_text().chars().collect()
        };

        let matching_ranges = if !matching_fields.is_empty() {
            parse_matching_fields(delimiter, ret.get_text(), matching_fields)
        } else {
            vec![(0, chars.len())]
        };

        ret.chars = chars;
        ret.matching_ranges = matching_ranges;
        ret
    }

    pub fn get_text(&self) -> &str {
        if !self.using_transform_fields && !self.ansi_enabled {
            &self.orig_text
        } else {
            &self.text
        }
    }

    pub fn get_orig_text(&'a self) -> Cow<'a, str> {
        Cow::Borrowed(&self.orig_text)
    }

    pub fn get_output_text(&'a self) -> Cow<'a, str> {
        if self.using_transform_fields && self.ansi_enabled {
            let mut ansi_parser: ANSIParser = Default::default();
            let (text, _) = ansi_parser.parse_ansi(&self.orig_text);
            Cow::Owned(text)
        } else if !self.using_transform_fields && self.ansi_enabled {
            Cow::Borrowed(&self.text)
        } else {
            Cow::Borrowed(&self.orig_text)
        }
    }

    pub fn get_chars(&self) -> &[char] {
        &self.chars
    }

    pub fn get_ansi_states(&self) -> &Vec<(usize, attr_t)> {
        &self.ansi_states
    }

    pub fn get_index(&self) -> usize {
        self.index.1
    }

    pub fn get_full_index(&self) -> (usize, usize) {
        self.index
    }

    pub fn get_matching_ranges(&self) -> &[(usize, usize)] {
        &self.matching_ranges
    }
}

impl Clone for Item {
    fn clone(&self) -> Item {
        Item {
            index: self.index,
            orig_text: self.orig_text.clone(),
            text: self.text.clone(),
            chars: self.chars.clone(),
            ansi_states: self.ansi_states.clone(),
            using_transform_fields: self.using_transform_fields,
            matching_ranges: self.matching_ranges.clone(),
            ansi_enabled: self.ansi_enabled,
        }
    }
}

// A bunch of items
pub type ItemGroup = Vec<Arc<Item>>;
pub type MatchedItemGroup = Vec<MatchedItem>;

pub type Rank = [i64; 4]; // score, index, start, end

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    Range(usize, usize),
    Chars(Vec<usize>),
}

#[derive(Clone, Debug)]
pub struct MatchedItem {
    pub item: Arc<Item>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that metched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<Item>) -> Self {
        MatchedItem {
            item: item,
            rank: [0, 0, 0, 0],
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }
}

impl Ord for MatchedItem {
    fn cmp(&self, other: &MatchedItem) -> Ordering {
        self.rank.cmp(&other.rank)
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for MatchedItem {
    fn partial_cmp(&self, other: &MatchedItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MatchedItem {
    fn eq(&self, other: &MatchedItem) -> bool {
        self.rank == other.rank
    }
}

impl Eq for MatchedItem {}
<commit_msg>use variables name when creating Item.<commit_after>// An item is line of text that read from `find` command or stdin together with
// the internal states, such as selected or not

use ansi::ANSIParser;
use curses::attr_t;
use field::*;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::default::Default;
use std::sync::Arc;

// An item will store everything that one line input will need to be operated and displayed.
//
// What's special about an item?
// The simplest version of an item is a line of string, but things are getting more complex:
// - The conversion of lower/upper case is slow in rust, because it involds unicode.
// - We may need to interpret the ANSI codes in the text.
// - The text can be transformed and limited while searching.

// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
// more than one line.

#[derive(Debug)]
pub struct Item {
    // (num of run, number of index)
    index: (usize, usize),

    // The text that will be ouptut when user press `enter`
    orig_text: String,

    // The text that will shown into the screen. Can be transformed.
    text: String,

    // cache of the lower case version of text. To improve speed
    chars: Vec<char>,

    // the ansi state (color) of the text
    ansi_states: Vec<(usize, attr_t)>,
    matching_ranges: Vec<(usize, usize)>,

    // For the transformed ANSI case, the output will need another transform.
    using_transform_fields: bool,
    ansi_enabled: bool,
}

impl<'a> Item {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
        index: (usize, usize),
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (text, ansi_states) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields))
        } else if using_transform_fields {
            // transformed, not ansi
            (parse_transform_fields(delimiter, &orig_text, trans_fields), Vec::new())
        } else if ansi_enabled {
            // not transformed, ansi
            ansi_parser.parse_ansi(&orig_text)
        } else {
            // normal case
            ("".to_string(), Vec::new())
        };

        let mut ret = Item {
            index,
            orig_text,
            text,
            chars: Vec::new(),
            ansi_states,
            using_transform_fields: !trans_fields.is_empty(),
            matching_ranges: Vec::new(),
            ansi_enabled,
        };

        let chars: Vec<char> = if ret.get_text().as_bytes().is_ascii() {
            ret.get_text().as_bytes().iter().map(|&s| s as char).collect()
        } else {
            ret.get_text().chars().collect()
        };

        let matching_ranges = if !matching_fields.is_empty() {
            parse_matching_fields(delimiter, ret.get_text(), matching_fields)
        } else {
            vec![(0, chars.len())]
        };

        ret.chars = chars;
        ret.matching_ranges = matching_ranges;
        ret
    }

    pub fn get_text(&self) -> &str {
        if !self.using_transform_fields && !self.ansi_enabled {
            &self.orig_text
        } else {
            &self.text
        }
    }

    pub fn get_orig_text(&'a self) -> Cow<'a, str> {
        Cow::Borrowed(&self.orig_text)
    }

    pub fn get_output_text(&'a self) -> Cow<'a, str> {
        if self.using_transform_fields && self.ansi_enabled {
            let mut ansi_parser: ANSIParser = Default::default();
            let (text, _) = ansi_parser.parse_ansi(&self.orig_text);
            Cow::Owned(text)
        } else if !self.using_transform_fields && self.ansi_enabled {
            Cow::Borrowed(&self.text)
        } else {
            Cow::Borrowed(&self.orig_text)
        }
    }

    pub fn get_chars(&self) -> &[char] {
        &self.chars
    }

    pub fn get_ansi_states(&self) -> &Vec<(usize, attr_t)> {
        &self.ansi_states
    }

    pub fn get_index(&self) -> usize {
        self.index.1
    }

    pub fn get_full_index(&self) -> (usize, usize) {
        self.index
    }

    pub fn get_matching_ranges(&self) -> &[(usize, usize)] {
        &self.matching_ranges
    }
}

impl Clone for Item {
    fn clone(&self) -> Item {
        Item {
            index: self.index,
            orig_text: self.orig_text.clone(),
            text: self.text.clone(),
            chars: self.chars.clone(),
            ansi_states: self.ansi_states.clone(),
            using_transform_fields: self.using_transform_fields,
            matching_ranges: self.matching_ranges.clone(),
            ansi_enabled: self.ansi_enabled,
        }
    }
}

// A bunch of items
pub type ItemGroup = Vec<Arc<Item>>;
pub type MatchedItemGroup = Vec<MatchedItem>;

pub type Rank = [i64; 4]; // score, index, start, end

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    Range(usize, usize),
    Chars(Vec<usize>),
}

#[derive(Clone, Debug)]
pub struct MatchedItem {
    pub item: Arc<Item>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that metched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<Item>) -> Self {
        MatchedItem {
            item: item,
            rank: [0, 0, 0, 0],
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }
}

impl Ord for MatchedItem {
    fn cmp(&self, other: &MatchedItem) -> Ordering {
        self.rank.cmp(&other.rank)
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for MatchedItem {
    fn partial_cmp(&self, other: &MatchedItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MatchedItem {
    fn eq(&self, other: &MatchedItem) -> bool {
        self.rank == other.rank
    }
}

impl Eq for MatchedItem {}
<|endoftext|>


<commit_before>use state::editor::Editor;
use io::parse::{Inst, Parameter};
use state::mode::{CommandMode, Mode, PrimitiveMode};
use edit::insert::{InsertMode, InsertOptions};
use io::redraw::RedrawTask;
use edit::buffer::TextBuffer;
use core::prompt::PromptCommand;

// TODO: Move the command definitions outta here
impl Editor {
    /// Execute an instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use io::key::Key::*;
        use state::mode::Mode::*;
        use state::mode::PrimitiveMode::*;
        use state::mode::CommandMode::*;

        let n = para.d();
        let bef = self.pos();
        let mut mov = false;

        match (self.cursor().mode, cmd.key) {
            (Primitive(Prompt), Char(' ')) if self.key_state.shift => {
                self.prompt = String::new();
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
            }
            (Primitive(Insert(_)), Escape) => {
                let left = self.left(1);
                self.goto(left);
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
            }
            (Primitive(Insert(_)), Char(' ')) if self.key_state.shift => {
                let left = self.left(1);
                self.goto(left);
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
            }
            (_, Char(' ')) if self.key_state.shift => {
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal)
            }
            (_, Char(' ')) if self.key_state.alt => self.next_cursor(),
            _ if self.key_state.alt => if let Some(m) = self.to_motion(Inst(para, cmd)) {
                self.goto(m);
            },
            (Command(Normal), Char('i')) => {
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('I')) => {
                self.cursor_mut().x = 0;
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('a')) => {
                let pos = self.right(1, false);
                self.goto(pos);
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('A')) => {
                let pos = (self.buffers.current_buffer()[self.y()].len(), self.y());
                //let pos = self.right(1, false);
                self.goto(pos);
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('o')) => {
                let y = self.y();
                let ind = if self.options.autoindent {
                    self.buffers.current_buffer().get_indent(y).to_owned()
                } else {
                    String::new()
                };
                let last = ind.len();
                self.buffers
                    .current_buffer_mut()
                    .insert_line(y + 1, ind.into());
                self.goto((last, y + 1));
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('h')) => {
                let left = self.left(n);
                self.goto(left);
                mov = true;
            }
            (Command(Normal), Char('j')) => {
                let down = self.down(n);
                self.goto(down);
                mov = true;
            }
            (Command(Normal), Char('k')) => {
                let up = self.up(n);
                self.goto(up);
                mov = true;
            }
            (Command(Normal), Char('l')) => {
                let right = self.right(n, true);
                self.goto(right);
                mov = true;
            }
            (Command(Normal), Char('J')) => {
                let down = self.down(15 * n);
                self.goto(down);
                mov = true;
            }
            (Command(Normal), Char('K')) => {
                let up = self.up(15 * n);
                self.goto(up);
                mov = true;
            }
            (Command(Normal), Char('x')) => {
                self.delete();
                let bounded = self.bound(self.pos(), true);
                self.goto(bounded);
            }
            (Command(Normal), Char('X')) => {
                self.backspace();
                let bounded = self.bound(self.pos(), true);
                self.goto(bounded);
            }
            (Command(Normal), Char('L')) => {
                if self.buffers.current_buffer()[self.y()].len() != 0 {
                    let ln_end = (self.buffers.current_buffer()[self.y()].len() - 1, self.y());
                    self.goto(ln_end);
                    mov = true;
                }
            }
            (Command(Normal), Char('H')) => {
                self.cursor_mut().x = 0;
                mov = true;
            }
            (Command(Normal), Char('r')) => {
                let (x, y) = self.pos();
                let c = self.get_char();
                let current_buffer = self.buffers.current_buffer_info_mut();
                // If there is nothing in the current buffer
                // ignore the command
                if current_buffer.raw_buffer[y].len() > 0 {
                    current_buffer.raw_buffer[y].remove(x);
                }
                current_buffer.raw_buffer[y].insert(x, c);
            }
            (Command(Normal), Char('R')) => {
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Replace,
                }));
            }
            (Command(Normal), Char('d')) => {
                let ins = self.get_inst();
                if let Some(m) = self.to_motion_unbounded(ins) {
                    self.remove_rb(m);
                }
            }
            (Command(Normal), Char('c')) => {
                let ins = self.get_inst();
                if let Some(m) = self.to_motion_unbounded(ins) {
                    self.remove_rb(m);
                    self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                        mode: InsertMode::Insert,
                    }));
                }
            }
            (Command(Normal), Char('G')) => {
                let last = self.buffers.current_buffer().len() - 1;
                self.goto((0, last));
                mov = true;
            }
            (Command(Normal), Char('g')) => {
                if let Parameter::Int(n) = para {
                    self.goto((0, n.wrapping_sub(1)));
                    mov = true;
                } else {
                    let inst = self.get_inst();
                    if let Some(m) = self.to_motion(inst) {
                        self.goto(m); // fix
                        mov = true;
                    }
                }
            }
            (Command(Normal), Char('b')) => {
                // Branch cursor
                if self.buffers.current_buffer_info().cursors.len() < 255 {
                    let cursor = self.cursor().clone();
                    let current_cursor_index =
                        self.buffers.current_buffer_info().current_cursor as usize;
                    self.buffers
                        .current_buffer_info_mut()
                        .cursors
                        .insert(current_cursor_index, cursor);
                    self.next_cursor();
                } else {
                    self.status_bar.msg = format!("At max 255 cursors");
                }
            }
            (Command(Normal), Char('B')) => {
                // Delete cursor
                if self.buffers.current_buffer_info().cursors.len() > 1 {
                    let current_cursor_index = self.buffers.current_buffer_info().current_cursor;
                    self.buffers
                        .current_buffer_info_mut()
                        .cursors
                        .remove(current_cursor_index as usize);
                    self.prev_cursor();
                } else {
                    self.status_bar.msg = format!("No other cursors!");
                }
            }
            (Command(Normal), Char('t')) => {
                let ch = self.get_char();

                let pos = self.next_ocur(ch, n);
                if let Some(p) = pos {
                    let y = self.y();
                    self.goto((p, y));
                    mov = true;
                }
            }
            (Command(Normal), Char('f')) => {
                let ch = self.get_char();

                let pos = self.previous_ocur(ch, n);
                if let Some(p) = pos {
                    let y = self.y();
                    self.goto((p, y));
                    mov = true;
                }
            }
            (Command(Normal), Char('W')) => {
                let pos = self._next_word_forward(n);
                if let Some(p) = pos {
                    let y = self.y();
                    self.goto((p, y));
                    mov = true;
                }
            }
            (Command(Normal), Char(';')) => {
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt)
            }
            (Command(Normal), Char(' ')) => self.next_cursor(),
            (Command(Normal), Char('z')) => {
                let Inst(param, cmd) = self.get_inst();
                match param {
                    Parameter::Null => if let Some(m) = self.to_motion(Inst(param, cmd)) {
                        self.buffers.current_buffer_info_mut().scroll_y = m.1;
                        self.goto(m);
                    },
                    Parameter::Int(n) => {
                        self.buffers.current_buffer_info_mut().scroll_y = n;
                    }
                }
                self.redraw_task = RedrawTask::Full;
            }
            (Command(Normal), Char('Z')) => {
                self.buffers.current_buffer_info_mut().scroll_y = self.y() - 3;
                self.redraw_task = RedrawTask::Full;
            }
            (Command(Normal), Char('~')) => {
                self.invert_chars(n);
            }
            (Command(Normal), Char('.')) => if let Some(inst) = self.previous_instruction {
                self.exec(inst);
            } else {
                self.status_bar.msg = "No previous command".into();
                self.redraw_task = RedrawTask::StatusBar;
            },
            (Command(Normal), Char(c)) => {
                self.status_bar.msg = format!("Unknown command: {}", c);
                self.redraw_task = RedrawTask::StatusBar;
            }
            (Primitive(Insert(opt)), k) => self.insert(k, opt),
            (Primitive(Prompt), Char('\n')) => {
                self.cursor_mut().mode = Command(Normal);
                if let Some(cmd) = PromptCommand::parse(&self.prompt.clone()) {
                    self.invoke(cmd);
                    self.prompt = String::new();
                    self.redraw_task = RedrawTask::StatusBar;
                } else {
                    self.status_bar.msg = format!("Unknown command: {}", self.prompt);
                }
            }
            (Primitive(Prompt), Backspace) => {
                self.prompt.pop();
                self.redraw_task = RedrawTask::StatusBar;
            }
            (Primitive(Prompt), Char(c)) => {
                self.prompt.push(c);
                self.redraw_task = RedrawTask::StatusBar;
            }
            _ => {
                self.status_bar.msg = format!("Unknown command");
                self.redraw_task = RedrawTask::StatusBar;
            }
        }
        if mov {
            self.redraw_task = RedrawTask::Cursor(bef, self.pos());
        }

        if !(self.cursor().mode == Command(Normal) && cmd.key == Char('.')) {
            self.previous_instruction = Some(Inst(para, cmd));
        }
    }
}
<commit_msg>Fix bug when entering invalid command in prompt<commit_after>use state::editor::Editor;
use io::parse::{Inst, Parameter};
use state::mode::{CommandMode, Mode, PrimitiveMode};
use edit::insert::{InsertMode, InsertOptions};
use io::redraw::RedrawTask;
use edit::buffer::TextBuffer;
use core::prompt::PromptCommand;

// TODO: Move the command definitions outta here
impl Editor {
    /// Execute an instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use io::key::Key::*;
        use state::mode::Mode::*;
        use state::mode::PrimitiveMode::*;
        use state::mode::CommandMode::*;

        let n = para.d();
        let bef = self.pos();
        let mut mov = false;

        match (self.cursor().mode, cmd.key) {
            (Primitive(Prompt), Char(' ')) if self.key_state.shift => {
                self.prompt = String::new();
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
            }
            (Primitive(Insert(_)), Escape) => {
                let left = self.left(1);
                self.goto(left);
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
            }
            (Primitive(Insert(_)), Char(' ')) if self.key_state.shift => {
                let left = self.left(1);
                self.goto(left);
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
            }
            (_, Char(' ')) if self.key_state.shift => {
                self.cursor_mut().mode = Mode::Command(CommandMode::Normal)
            }
            (_, Char(' ')) if self.key_state.alt => self.next_cursor(),
            _ if self.key_state.alt => if let Some(m) = self.to_motion(Inst(para, cmd)) {
                self.goto(m);
            },
            (Command(Normal), Char('i')) => {
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('I')) => {
                self.cursor_mut().x = 0;
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('a')) => {
                let pos = self.right(1, false);
                self.goto(pos);
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('A')) => {
                let pos = (self.buffers.current_buffer()[self.y()].len(), self.y());
                //let pos = self.right(1, false);
                self.goto(pos);
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('o')) => {
                let y = self.y();
                let ind = if self.options.autoindent {
                    self.buffers.current_buffer().get_indent(y).to_owned()
                } else {
                    String::new()
                };
                let last = ind.len();
                self.buffers
                    .current_buffer_mut()
                    .insert_line(y + 1, ind.into());
                self.goto((last, y + 1));
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Insert,
                }));
            }
            (Command(Normal), Char('h')) => {
                let left = self.left(n);
                self.goto(left);
                mov = true;
            }
            (Command(Normal), Char('j')) => {
                let down = self.down(n);
                self.goto(down);
                mov = true;
            }
            (Command(Normal), Char('k')) => {
                let up = self.up(n);
                self.goto(up);
                mov = true;
            }
            (Command(Normal), Char('l')) => {
                let right = self.right(n, true);
                self.goto(right);
                mov = true;
            }
            (Command(Normal), Char('J')) => {
                let down = self.down(15 * n);
                self.goto(down);
                mov = true;
            }
            (Command(Normal), Char('K')) => {
                let up = self.up(15 * n);
                self.goto(up);
                mov = true;
            }
            (Command(Normal), Char('x')) => {
                self.delete();
                let bounded = self.bound(self.pos(), true);
                self.goto(bounded);
            }
            (Command(Normal), Char('X')) => {
                self.backspace();
                let bounded = self.bound(self.pos(), true);
                self.goto(bounded);
            }
            (Command(Normal), Char('L')) => {
                if self.buffers.current_buffer()[self.y()].len() != 0 {
                    let ln_end = (self.buffers.current_buffer()[self.y()].len() - 1, self.y());
                    self.goto(ln_end);
                    mov = true;
                }
            }
            (Command(Normal), Char('H')) => {
                self.cursor_mut().x = 0;
                mov = true;
            }
            (Command(Normal), Char('r')) => {
                let (x, y) = self.pos();
                let c = self.get_char();
                let current_buffer = self.buffers.current_buffer_info_mut();
                // If there is nothing in the current buffer
                // ignore the command
                if current_buffer.raw_buffer[y].len() > 0 {
                    current_buffer.raw_buffer[y].remove(x);
                }
                current_buffer.raw_buffer[y].insert(x, c);
            }
            (Command(Normal), Char('R')) => {
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                    mode: InsertMode::Replace,
                }));
            }
            (Command(Normal), Char('d')) => {
                let ins = self.get_inst();
                if let Some(m) = self.to_motion_unbounded(ins) {
                    self.remove_rb(m);
                }
            }
            (Command(Normal), Char('c')) => {
                let ins = self.get_inst();
                if let Some(m) = self.to_motion_unbounded(ins) {
                    self.remove_rb(m);
                    self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                        mode: InsertMode::Insert,
                    }));
                }
            }
            (Command(Normal), Char('G')) => {
                let last = self.buffers.current_buffer().len() - 1;
                self.goto((0, last));
                mov = true;
            }
            (Command(Normal), Char('g')) => {
                if let Parameter::Int(n) = para {
                    self.goto((0, n.wrapping_sub(1)));
                    mov = true;
                } else {
                    let inst = self.get_inst();
                    if let Some(m) = self.to_motion(inst) {
                        self.goto(m); // fix
                        mov = true;
                    }
                }
            }
            (Command(Normal), Char('b')) => {
                // Branch cursor
                if self.buffers.current_buffer_info().cursors.len() < 255 {
                    let cursor = self.cursor().clone();
                    let current_cursor_index =
                        self.buffers.current_buffer_info().current_cursor as usize;
                    self.buffers
                        .current_buffer_info_mut()
                        .cursors
                        .insert(current_cursor_index, cursor);
                    self.next_cursor();
                } else {
                    self.status_bar.msg = format!("At max 255 cursors");
                }
            }
            (Command(Normal), Char('B')) => {
                // Delete cursor
                if self.buffers.current_buffer_info().cursors.len() > 1 {
                    let current_cursor_index = self.buffers.current_buffer_info().current_cursor;
                    self.buffers
                        .current_buffer_info_mut()
                        .cursors
                        .remove(current_cursor_index as usize);
                    self.prev_cursor();
                } else {
                    self.status_bar.msg = format!("No other cursors!");
                }
            }
            (Command(Normal), Char('t')) => {
                let ch = self.get_char();

                let pos = self.next_ocur(ch, n);
                if let Some(p) = pos {
                    let y = self.y();
                    self.goto((p, y));
                    mov = true;
                }
            }
            (Command(Normal), Char('f')) => {
                let ch = self.get_char();

                let pos = self.previous_ocur(ch, n);
                if let Some(p) = pos {
                    let y = self.y();
                    self.goto((p, y));
                    mov = true;
                }
            }
            (Command(Normal), Char('W')) => {
                let pos = self._next_word_forward(n);
                if let Some(p) = pos {
                    let y = self.y();
                    self.goto((p, y));
                    mov = true;
                }
            }
            (Command(Normal), Char(';')) => {
                self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt)
            }
            (Command(Normal), Char(' ')) => self.next_cursor(),
            (Command(Normal), Char('z')) => {
                let Inst(param, cmd) = self.get_inst();
                match param {
                    Parameter::Null => if let Some(m) = self.to_motion(Inst(param, cmd)) {
                        self.buffers.current_buffer_info_mut().scroll_y = m.1;
                        self.goto(m);
                    },
                    Parameter::Int(n) => {
                        self.buffers.current_buffer_info_mut().scroll_y = n;
                    }
                }
                self.redraw_task = RedrawTask::Full;
            }
            (Command(Normal), Char('Z')) => {
                self.buffers.current_buffer_info_mut().scroll_y = self.y() - 3;
                self.redraw_task = RedrawTask::Full;
            }
            (Command(Normal), Char('~')) => {
                self.invert_chars(n);
            }
            (Command(Normal), Char('.')) => if let Some(inst) = self.previous_instruction {
                self.exec(inst);
            } else {
                self.status_bar.msg = "No previous command".into();
                self.redraw_task = RedrawTask::StatusBar;
            },
            (Command(Normal), Char(c)) => {
                self.status_bar.msg = format!("Unknown command: {}", c);
                self.redraw_task = RedrawTask::StatusBar;
            }
            (Primitive(Insert(opt)), k) => self.insert(k, opt),
            (Primitive(Prompt), Char('\n')) => {
                self.cursor_mut().mode = Command(Normal);
                if let Some(cmd) = PromptCommand::parse(&self.prompt.clone()) {
                    self.invoke(cmd);
                    self.redraw_task = RedrawTask::StatusBar;
                } else {
                    self.status_bar.msg = format!("Unknown command: {}", self.prompt);
                }
                self.prompt = String::new();
            }
            (Primitive(Prompt), Backspace) => {
                self.prompt.pop();
                self.redraw_task = RedrawTask::StatusBar;
            }
            (Primitive(Prompt), Char(c)) => {
                self.prompt.push(c);
                self.redraw_task = RedrawTask::StatusBar;
            }
            _ => {
                self.status_bar.msg = format!("Unknown command");
                self.redraw_task = RedrawTask::StatusBar;
            }
        }
        if mov {
            self.redraw_task = RedrawTask::Cursor(bef, self.pos());
        }

        if !(self.cursor().mode == Command(Normal) && cmd.key == Char('.')) {
            self.previous_instruction = Some(Inst(para, cmd));
        }
    }
}
<|endoftext|>


<commit_before>#![allow(float_cmp)]

use std;
use rustc_front::hir::*;
use syntax::ast::Lit_::*;
use syntax::ast::FloatTy;
use rustc_front::util::{binop_to_string, unop_to_string};
use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub enum LispExpr {
    Binary(BinOp_, Box<LispExpr>, Box<LispExpr>),
    Fun(String, Vec<LispExpr>),
    Ident(u64),
    Lit(f64),
    Unary(UnOp, Box<LispExpr>),
}

#[derive(Debug)]
pub enum LispExprError {
    UnknownType,
    UnknownKind,
    WrongFloat,
}

impl std::fmt::Debug for LispExpr {

    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.pad(&self.to_lisp())
    }

}

/// List (herbie_name, rust_name).
/// Warning: *MUST* be alphabetized on Herbie name.
/// Herbie also supports the following:
///   * cot (cotangent),
///   * expt (expi, expf),
///   * mod
///   * sqt (square),
const KNOW_FUNS : &'static [(&'static str, &'static str, usize)] = &[
    ("abs",   "abs",    1),
    ("acos",  "acos",   1),
    ("asin",  "asin",   1),
    ("atan",  "atan",   1),
    ("atan2", "atan2",  2),
    ("cos",   "cos",    1),
    ("cosh",  "cosh",   1),
    ("exp",   "exp",    1),
    ("expm1", "exp_m1", 1),
    ("hypot", "hypot",  2),
    ("log",   "ln",     1),
    ("log1p", "ln_1p",  1),
    ("sin",   "sin",    1),
    ("sinh",  "sinh",   1),
    ("sqrt",  "sqrt",   1),
    ("tan",   "tan",    1),
    ("tanh",  "tanh",   1),
];

impl LispExpr {

    pub fn is_form_of(&self, other: &LispExpr) -> bool {
        #[derive(PartialEq)]
        enum Binded {
            Ident(u64),
            Lit(f64),
        }

        fn is_form_of_impl(lhs: &LispExpr, rhs: &LispExpr, ids: &mut HashMap<u64, Binded>) -> bool {
            match (lhs, rhs) {
                (&LispExpr::Binary(lop, ref lp1, ref lp2), &LispExpr::Binary(rop, ref rp1, ref rp2)) => {
                    lop == rop && is_form_of_impl(lp1, rp1, ids) && is_form_of_impl(lp2, rp2, ids)
                },
                (&LispExpr::Fun(ref lfun, ref lp), &LispExpr::Fun(ref rfun, ref rp)) => {
                    lfun == rfun && lp.len() == rp.len() && lp.iter().zip(rp).all(|(lp, rp)| is_form_of_impl(lp, rp, ids))
                },
                (&LispExpr::Ident(lid), &LispExpr::Ident(rid)) => {
                    match ids.entry(rid) {
                        Entry::Occupied(entry) => {
                            if let Binded::Ident(binded) = *entry.get() {
                                binded == lid
                            }
                            else {
                                false
                            }
                        },
                        Entry::Vacant(vacant) => {
                            vacant.insert(Binded::Ident(lid));
                            true
                        }
                    }
                },
                (&LispExpr::Lit(l), &LispExpr::Lit(r)) => {
                    l == r
                },
                (&LispExpr::Lit(l), &LispExpr::Ident(rid)) => {
                    match ids.entry(rid) {
                        Entry::Occupied(entry) => {
                            if let Binded::Lit(binded) = *entry.get() {
                                binded == l
                            }
                            else {
                                false
                            }
                        },
                        Entry::Vacant(vacant) => {
                            vacant.insert(Binded::Lit(l));
                            true
                        }
                    }
                },
                (&LispExpr::Unary(lop, ref lp), &LispExpr::Unary(rop, ref rp)) => {
                    lop == rop && is_form_of_impl(lp, rp, ids)
                },
                _ => false,
            }
        }

        let mut ids = HashMap::new();
        is_form_of_impl(self, other, &mut ids)
    }

    pub fn from_expr(expr: &Expr) -> Result<LispExpr, LispExprError> {
        #[derive(PartialEq, Eq, Hash)]
        enum Binded {
            Path(Option<QSelf>, bool, HirVec<PathSegment>),
        }

        fn from_expr_impl(expr: &Expr, curr_id: &mut u64, ids: &mut HashMap<Binded, u64>) -> Result<LispExpr, LispExprError> {
            match expr.node {
                ExprBinary(op, ref lhs, ref rhs) => {
                    Ok(LispExpr::Binary(op.node, box try!(from_expr_impl(lhs, curr_id, ids)), box try!(from_expr_impl(rhs, curr_id, ids))))
                },
                ExprLit(ref lit) => {
                    match lit.node {
                        LitFloat(ref f, FloatTy::TyF64) => LispExpr::from_lit_float(&f),
                        LitFloatUnsuffixed(ref f) => LispExpr::from_lit_float(&f),
                        _ => Err(LispExprError::UnknownType)
                    }
                },
                ExprUnary(op, ref expr) => {
                    Ok(LispExpr::Unary(op, box try!(from_expr_impl(&expr, curr_id, ids))))
                },
                ExprPath(ref qualif, ref path) => {
                    match ids.entry(Binded::Path(qualif.clone(), path.global, path.segments.clone())) {
                        Entry::Occupied(entry) => {
                            Ok(LispExpr::Ident(*entry.get()))
                        },
                        Entry::Vacant(vacant) => {
                            let id = *curr_id;
                            *curr_id += 1;
                            vacant.insert(id);
                            Ok(LispExpr::Ident(id))
                        }
                    }
                },
                ExprCall(..) | ExprCast(..) | ExprBlock(..) => {
                    let id = *curr_id;
                    *curr_id += 1;
                    Ok(LispExpr::Ident(id))
                },
                ExprMethodCall(ref name, ref ascripted_type, ref params) => {
                    if ascripted_type.is_empty() {
                        let name = name.node.as_str();

                        if let Some(&(herbie_name, _, _)) = KNOW_FUNS.iter().find(
                            |&&(_, rust_name, num_params)| {
                                rust_name == name && params.len() == num_params
                            }
                        ) {
                            let mut conv_params = vec![];
                            for p in params {
                                let p = from_expr_impl(p, curr_id, ids);
                                if let Ok(p) = p {
                                    conv_params.push(p);
                                }
                                else {
                                    return p;
                                }
                            }
                            return Ok(LispExpr::Fun(herbie_name.into(), conv_params))
                        }
                    }

                    let id = *curr_id;
                    *curr_id += 1;
                    Ok(LispExpr::Ident(id))
                },
                // TODO:
                // ExprAssignOp,
                // ExprField,
                // ExprTupField,
                // ExprIndex,
                _ => Err(LispExprError::UnknownKind)
            }
        }

        let mut ids = HashMap::new();
        from_expr_impl(expr, &mut 0, &mut ids)
    }

    fn from_lit_float(f: &str) -> Result<LispExpr, LispExprError> {
        if let Ok(f) = f.parse() {
            Ok(LispExpr::Lit(f))
        }
        else {
            Err(LispExprError::WrongFloat)
        }
    }

    // TODO: should probably not be pub
    pub fn to_lisp(&self) -> String {
        match *self {
            LispExpr::Binary(op, ref lhs, ref rhs) => {
                format!("({} {} {})", binop_to_string(op), lhs.to_lisp(), rhs.to_lisp())
            },
            LispExpr::Fun(ref name, ref params) => {
                let mut buf = String::new();
                buf.push('(');
                buf.push_str(name);

                for p in params {
                    buf.push(' ');
                    buf.push_str(&p.to_lisp());
                }

                buf.push(')');
                buf
            }
            LispExpr::Lit(f) => {
                format!("{}", f)
            },
            LispExpr::Unary(op, ref expr) => {
                format!("({} {})", unop_to_string(op), expr.to_lisp())
            },
            LispExpr::Ident(id) => {
                format!("${}", id)
            }
        }
    }

}

#[derive(Debug)]
pub enum ParseError {
    Arity,
    Expected(char),
    Ident,
    Float,
    Unexpected(char),
    EOE,
}

struct Parser {
    stack: Vec<char>,
}

pub fn parse(s: &str) -> Result<LispExpr, ParseError> {
    let mut parser = Parser { stack: Vec::new() };
    let mut it = s.chars();

    match parser.parse_impl(&mut it) {
        Ok(result) => {
            if it.next().is_some() {
                Err(ParseError::EOE)
            }
            else  {
                Ok(result)
            }
        },
        err @ Err(..) => err,
    }
}

impl Parser {

    fn parse_impl<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        match self.get_char(it, true) {
            Some('(') => {
                match self.get_char(it, true) {
                    Some('+') => self.parse_op(it, BinOp_::BiAdd),
                    Some('-') => self.parse_op(it, BinOp_::BiSub),
                    Some('*') => self.parse_op(it, BinOp_::BiMul),
                    Some('/') => self.parse_op(it, BinOp_::BiDiv),
                    Some(c) if c.is_digit(10) => {
                        self.put_back(c);
                        let r = self.parse_float(it);
                        try!(self.expect(it, ')', true));
                        r
                    },
                    Some(c) => {
                        self.put_back(c);
                        self.parse_fun(it)
                    },
                    None => Err(ParseError::EOE),
                }
            },
            Some(c) if c.is_digit(10) => {
                self.put_back(c);
                self.parse_float(it)
            },
            Some('h') => self.parse_ident(it),
            Some(c) => {
                self.put_back(c);
                Err(ParseError::Unexpected(c))
            }
            None => Err(ParseError::EOE),
        }
    }

    fn expect<It: Iterator<Item=char>>(&mut self, it: &mut It, c: char, skip_whitespace: bool) -> Result<(), ParseError> {
        if self.get_char(it, skip_whitespace) == Some(c) {
            Ok(())
        }
        else {
            Err(ParseError::Expected(c))
        }
    }

    fn parse_float<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        let mut buf = String::new();
        loop {
            let c = self.get_char(it, false);
            if let Some(c) = c {
                if c.is_digit(10) || ['.', 'e', '+', '-'].contains(&c) {
                    buf.push(c);
                    continue;
                }

                self.put_back(c);
            }

            break;
        }

        match buf.parse() {
            Ok(f) => Ok(LispExpr::Lit(f)),
            Err(..) => Err(ParseError::Float),
        }
    }

    fn parse_ident<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        // TODO: Herbie also supports ‘pi’ and ‘e’ as native constants.
        let mut buf = String::new();
        loop {
            let c = self.get_char(it, false);
            if let Some(c) = c {
                if buf.is_empty() && 'a' <= c && c <= 'z' {
                    continue;
                }
                else if c.is_digit(10)  {
                    buf.push(c);
                    continue;
                }
                else {
                    self.put_back(c);
                }
            }

            break;
        }

        match buf.parse() {
            Ok(id) => Ok(LispExpr::Ident(id)),
            Err(..) => Err(ParseError::Ident),
        }
    }

    fn parse_fun<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        let mut buf = String::new();
        loop {
            let c = self.get_char(it, false);
            if let Some(c) = c {
                if 'a' <= c && c <= 'z' {
                    buf.push(c);
                    continue;
                }
                else {
                    self.put_back(c);
                }
            }

            break;
        }

        if !buf.is_empty() {
            let mut params = vec![];

            while let Ok(param) = self.parse_impl(it) {
                params.push(param);
            }

            try!(self.expect(it, ')', true));
            Ok(LispExpr::Fun(buf, params))
        }
        else {
            Err(ParseError::Ident)
        }
    }

    fn parse_op<It: Iterator<Item=char>>(&mut self, it: &mut It, op: BinOp_) -> Result<LispExpr, ParseError> {
        // TODO: Herbie seems to also support the following for the repip of a float: (/ 42) and
        // rust has a function recip for that
        let lhs = try!(self.parse_impl(it));
        let r = if let Ok(rhs) = self.parse_impl(it) {
            Ok(LispExpr::Binary(op, box lhs, box rhs))
        }
        else if op == BinOp_::BiSub {
            Ok(LispExpr::Unary(UnOp::UnNeg, box lhs))
        }
        else {
            return Err(ParseError::Arity);
        };
        try!(self.expect(it, ')', true));
        r
    }

    fn get_char<It: Iterator<Item=char>>(&mut self, it: &mut It, skip_whitespace: bool) -> Option<char> {
        loop {
            match self.stack.pop() {
                Some(e) if skip_whitespace && e.is_whitespace() => continue,
                Some(e) => return Some(e),
                None => break,
            }
        }

        loop {
            match it.next() {
                Some(e) if skip_whitespace && e.is_whitespace() => continue,
                Some(e) => return Some(e),
                None => return None,
            }
        }
    }

    fn put_back(&mut self, c: char) {
        self.stack.push(c);
    }
}
<commit_msg>Fix warnings when not using clippy<commit_after>#![cfg_attr(feature="clippy", allow(float_cmp))]

use std;
use rustc_front::hir::*;
use syntax::ast::Lit_::*;
use syntax::ast::FloatTy;
use rustc_front::util::{binop_to_string, unop_to_string};
use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub enum LispExpr {
    Binary(BinOp_, Box<LispExpr>, Box<LispExpr>),
    Fun(String, Vec<LispExpr>),
    Ident(u64),
    Lit(f64),
    Unary(UnOp, Box<LispExpr>),
}

#[derive(Debug)]
pub enum LispExprError {
    UnknownType,
    UnknownKind,
    WrongFloat,
}

impl std::fmt::Debug for LispExpr {

    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.pad(&self.to_lisp())
    }

}

/// List (herbie_name, rust_name).
/// Warning: *MUST* be alphabetized on Herbie name.
/// Herbie also supports the following:
///   * cot (cotangent),
///   * expt (expi, expf),
///   * mod
///   * sqt (square),
const KNOW_FUNS : &'static [(&'static str, &'static str, usize)] = &[
    ("abs",   "abs",    1),
    ("acos",  "acos",   1),
    ("asin",  "asin",   1),
    ("atan",  "atan",   1),
    ("atan2", "atan2",  2),
    ("cos",   "cos",    1),
    ("cosh",  "cosh",   1),
    ("exp",   "exp",    1),
    ("expm1", "exp_m1", 1),
    ("hypot", "hypot",  2),
    ("log",   "ln",     1),
    ("log1p", "ln_1p",  1),
    ("sin",   "sin",    1),
    ("sinh",  "sinh",   1),
    ("sqrt",  "sqrt",   1),
    ("tan",   "tan",    1),
    ("tanh",  "tanh",   1),
];

impl LispExpr {

    pub fn is_form_of(&self, other: &LispExpr) -> bool {
        #[derive(PartialEq)]
        enum Binded {
            Ident(u64),
            Lit(f64),
        }

        fn is_form_of_impl(lhs: &LispExpr, rhs: &LispExpr, ids: &mut HashMap<u64, Binded>) -> bool {
            match (lhs, rhs) {
                (&LispExpr::Binary(lop, ref lp1, ref lp2), &LispExpr::Binary(rop, ref rp1, ref rp2)) => {
                    lop == rop && is_form_of_impl(lp1, rp1, ids) && is_form_of_impl(lp2, rp2, ids)
                },
                (&LispExpr::Fun(ref lfun, ref lp), &LispExpr::Fun(ref rfun, ref rp)) => {
                    lfun == rfun && lp.len() == rp.len() && lp.iter().zip(rp).all(|(lp, rp)| is_form_of_impl(lp, rp, ids))
                },
                (&LispExpr::Ident(lid), &LispExpr::Ident(rid)) => {
                    match ids.entry(rid) {
                        Entry::Occupied(entry) => {
                            if let Binded::Ident(binded) = *entry.get() {
                                binded == lid
                            }
                            else {
                                false
                            }
                        },
                        Entry::Vacant(vacant) => {
                            vacant.insert(Binded::Ident(lid));
                            true
                        }
                    }
                },
                (&LispExpr::Lit(l), &LispExpr::Lit(r)) => {
                    l == r
                },
                (&LispExpr::Lit(l), &LispExpr::Ident(rid)) => {
                    match ids.entry(rid) {
                        Entry::Occupied(entry) => {
                            if let Binded::Lit(binded) = *entry.get() {
                                binded == l
                            }
                            else {
                                false
                            }
                        },
                        Entry::Vacant(vacant) => {
                            vacant.insert(Binded::Lit(l));
                            true
                        }
                    }
                },
                (&LispExpr::Unary(lop, ref lp), &LispExpr::Unary(rop, ref rp)) => {
                    lop == rop && is_form_of_impl(lp, rp, ids)
                },
                _ => false,
            }
        }

        let mut ids = HashMap::new();
        is_form_of_impl(self, other, &mut ids)
    }

    pub fn from_expr(expr: &Expr) -> Result<LispExpr, LispExprError> {
        #[derive(PartialEq, Eq, Hash)]
        enum Binded {
            Path(Option<QSelf>, bool, HirVec<PathSegment>),
        }

        fn from_expr_impl(expr: &Expr, curr_id: &mut u64, ids: &mut HashMap<Binded, u64>) -> Result<LispExpr, LispExprError> {
            match expr.node {
                ExprBinary(op, ref lhs, ref rhs) => {
                    Ok(LispExpr::Binary(op.node, box try!(from_expr_impl(lhs, curr_id, ids)), box try!(from_expr_impl(rhs, curr_id, ids))))
                },
                ExprLit(ref lit) => {
                    match lit.node {
                        LitFloat(ref f, FloatTy::TyF64) => LispExpr::from_lit_float(&f),
                        LitFloatUnsuffixed(ref f) => LispExpr::from_lit_float(&f),
                        _ => Err(LispExprError::UnknownType)
                    }
                },
                ExprUnary(op, ref expr) => {
                    Ok(LispExpr::Unary(op, box try!(from_expr_impl(&expr, curr_id, ids))))
                },
                ExprPath(ref qualif, ref path) => {
                    match ids.entry(Binded::Path(qualif.clone(), path.global, path.segments.clone())) {
                        Entry::Occupied(entry) => {
                            Ok(LispExpr::Ident(*entry.get()))
                        },
                        Entry::Vacant(vacant) => {
                            let id = *curr_id;
                            *curr_id += 1;
                            vacant.insert(id);
                            Ok(LispExpr::Ident(id))
                        }
                    }
                },
                ExprCall(..) | ExprCast(..) | ExprBlock(..) => {
                    let id = *curr_id;
                    *curr_id += 1;
                    Ok(LispExpr::Ident(id))
                },
                ExprMethodCall(ref name, ref ascripted_type, ref params) => {
                    if ascripted_type.is_empty() {
                        let name = name.node.as_str();

                        if let Some(&(herbie_name, _, _)) = KNOW_FUNS.iter().find(
                            |&&(_, rust_name, num_params)| {
                                rust_name == name && params.len() == num_params
                            }
                        ) {
                            let mut conv_params = vec![];
                            for p in params {
                                let p = from_expr_impl(p, curr_id, ids);
                                if let Ok(p) = p {
                                    conv_params.push(p);
                                }
                                else {
                                    return p;
                                }
                            }
                            return Ok(LispExpr::Fun(herbie_name.into(), conv_params))
                        }
                    }

                    let id = *curr_id;
                    *curr_id += 1;
                    Ok(LispExpr::Ident(id))
                },
                // TODO:
                // ExprAssignOp,
                // ExprField,
                // ExprTupField,
                // ExprIndex,
                _ => Err(LispExprError::UnknownKind)
            }
        }

        let mut ids = HashMap::new();
        from_expr_impl(expr, &mut 0, &mut ids)
    }

    fn from_lit_float(f: &str) -> Result<LispExpr, LispExprError> {
        if let Ok(f) = f.parse() {
            Ok(LispExpr::Lit(f))
        }
        else {
            Err(LispExprError::WrongFloat)
        }
    }

    // TODO: should probably not be pub
    pub fn to_lisp(&self) -> String {
        match *self {
            LispExpr::Binary(op, ref lhs, ref rhs) => {
                format!("({} {} {})", binop_to_string(op), lhs.to_lisp(), rhs.to_lisp())
            },
            LispExpr::Fun(ref name, ref params) => {
                let mut buf = String::new();
                buf.push('(');
                buf.push_str(name);

                for p in params {
                    buf.push(' ');
                    buf.push_str(&p.to_lisp());
                }

                buf.push(')');
                buf
            }
            LispExpr::Lit(f) => {
                format!("{}", f)
            },
            LispExpr::Unary(op, ref expr) => {
                format!("({} {})", unop_to_string(op), expr.to_lisp())
            },
            LispExpr::Ident(id) => {
                format!("${}", id)
            }
        }
    }

}

#[derive(Debug)]
pub enum ParseError {
    Arity,
    Expected(char),
    Ident,
    Float,
    Unexpected(char),
    EOE,
}

struct Parser {
    stack: Vec<char>,
}

pub fn parse(s: &str) -> Result<LispExpr, ParseError> {
    let mut parser = Parser { stack: Vec::new() };
    let mut it = s.chars();

    match parser.parse_impl(&mut it) {
        Ok(result) => {
            if it.next().is_some() {
                Err(ParseError::EOE)
            }
            else  {
                Ok(result)
            }
        },
        err @ Err(..) => err,
    }
}

impl Parser {

    fn parse_impl<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        match self.get_char(it, true) {
            Some('(') => {
                match self.get_char(it, true) {
                    Some('+') => self.parse_op(it, BinOp_::BiAdd),
                    Some('-') => self.parse_op(it, BinOp_::BiSub),
                    Some('*') => self.parse_op(it, BinOp_::BiMul),
                    Some('/') => self.parse_op(it, BinOp_::BiDiv),
                    Some(c) if c.is_digit(10) => {
                        self.put_back(c);
                        let r = self.parse_float(it);
                        try!(self.expect(it, ')', true));
                        r
                    },
                    Some(c) => {
                        self.put_back(c);
                        self.parse_fun(it)
                    },
                    None => Err(ParseError::EOE),
                }
            },
            Some(c) if c.is_digit(10) => {
                self.put_back(c);
                self.parse_float(it)
            },
            Some('h') => self.parse_ident(it),
            Some(c) => {
                self.put_back(c);
                Err(ParseError::Unexpected(c))
            }
            None => Err(ParseError::EOE),
        }
    }

    fn expect<It: Iterator<Item=char>>(&mut self, it: &mut It, c: char, skip_whitespace: bool) -> Result<(), ParseError> {
        if self.get_char(it, skip_whitespace) == Some(c) {
            Ok(())
        }
        else {
            Err(ParseError::Expected(c))
        }
    }

    fn parse_float<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        let mut buf = String::new();
        loop {
            let c = self.get_char(it, false);
            if let Some(c) = c {
                if c.is_digit(10) || ['.', 'e', '+', '-'].contains(&c) {
                    buf.push(c);
                    continue;
                }

                self.put_back(c);
            }

            break;
        }

        match buf.parse() {
            Ok(f) => Ok(LispExpr::Lit(f)),
            Err(..) => Err(ParseError::Float),
        }
    }

    fn parse_ident<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        // TODO: Herbie also supports ‘pi’ and ‘e’ as native constants.
        let mut buf = String::new();
        loop {
            let c = self.get_char(it, false);
            if let Some(c) = c {
                if buf.is_empty() && 'a' <= c && c <= 'z' {
                    continue;
                }
                else if c.is_digit(10)  {
                    buf.push(c);
                    continue;
                }
                else {
                    self.put_back(c);
                }
            }

            break;
        }

        match buf.parse() {
            Ok(id) => Ok(LispExpr::Ident(id)),
            Err(..) => Err(ParseError::Ident),
        }
    }

    fn parse_fun<It: Iterator<Item=char>>(&mut self, it: &mut It) -> Result<LispExpr, ParseError> {
        let mut buf = String::new();
        loop {
            let c = self.get_char(it, false);
            if let Some(c) = c {
                if 'a' <= c && c <= 'z' {
                    buf.push(c);
                    continue;
                }
                else {
                    self.put_back(c);
                }
            }

            break;
        }

        if !buf.is_empty() {
            let mut params = vec![];

            while let Ok(param) = self.parse_impl(it) {
                params.push(param);
            }

            try!(self.expect(it, ')', true));
            Ok(LispExpr::Fun(buf, params))
        }
        else {
            Err(ParseError::Ident)
        }
    }

    fn parse_op<It: Iterator<Item=char>>(&mut self, it: &mut It, op: BinOp_) -> Result<LispExpr, ParseError> {
        // TODO: Herbie seems to also support the following for the repip of a float: (/ 42) and
        // rust has a function recip for that
        let lhs = try!(self.parse_impl(it));
        let r = if let Ok(rhs) = self.parse_impl(it) {
            Ok(LispExpr::Binary(op, box lhs, box rhs))
        }
        else if op == BinOp_::BiSub {
            Ok(LispExpr::Unary(UnOp::UnNeg, box lhs))
        }
        else {
            return Err(ParseError::Arity);
        };
        try!(self.expect(it, ')', true));
        r
    }

    fn get_char<It: Iterator<Item=char>>(&mut self, it: &mut It, skip_whitespace: bool) -> Option<char> {
        loop {
            match self.stack.pop() {
                Some(e) if skip_whitespace && e.is_whitespace() => continue,
                Some(e) => return Some(e),
                None => break,
            }
        }

        loop {
            match it.next() {
                Some(e) if skip_whitespace && e.is_whitespace() => continue,
                Some(e) => return Some(e),
                None => return None,
            }
        }
    }

    fn put_back(&mut self, c: char) {
        self.stack.push(c);
    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;

pub struct DecodeRegister {
    addr_init: u16,
    addr_intermediate: u16,
    addr_final: u16,

    value_init: u8,
    value_intermediate: u8,
    value_final: u8,

    info: OpcodeExecInfo,
}

#[allow(non_snake_case)]
pub struct CpuState {
    pc: u16,
    sp: u8,
    a:  u8,
    x:  u8,
    y:  u8,

    // flags
    C: bool, // carry
    Z: bool, // zero
    I: bool, // interrupt
    D: bool, // decimal
    B: bool, // break
             // bit 5 is not used by the nes and is always 1
    V: bool, // overflow
    S: bool, // sign/negative

    // these are not strictly 6502 registers, but are useful for modeling the cpu
    instruction_register: u16,
    decode_register:DecodeRegister,
}

impl CpuState {
  fn unpack_flags(self: &CpuState) -> u8 {
        ( (self.C as u8) << 0)
      | ( (self.Z as u8) << 1)
      | ( (self.I as u8) << 2)
      | ( (self.D as u8) << 3)
      | ( (self.B as u8) << 4)
      | ( (1           ) << 5) // flag 5 is unused
      | ( (self.V as u8) << 6)
      | ( (self.S as u8) << 7)
  }
  fn pack_flags(self: &mut CpuState,flags:u8) {
    self.C        = ( (flags >> 0) & 1) == 1;
    self.Z        = ( (flags >> 1) & 1) == 1;
    self.I        = ( (flags >> 2) & 1) == 1;
    self.D        = ( (flags >> 3) & 1) == 1;
    self.B        = ( (flags >> 4) & 1) == 1;
    // flags 5 is unused
    self.V        = ( (flags >> 6) & 1) == 1;
    self.S        = ( (flags >> 7) & 1) == 1;
  }
}
<commit_msg>added default trait and fixed style issue<commit_after>use cpu::common_defs::OpcodeExecInfo;

#[derive(Default)]
pub struct DecodeRegister {
    addr_init: u16,
    addr_intermediate: u16,
    addr_final: u16,

    value_init: u8,
    value_intermediate: u8,
    value_final: u8,

    info: OpcodeExecInfo,
}

#[allow(non_snake_case)]
#[derive(Default)]
pub struct CpuState {
    pc: u16,
    sp: u8,
    a:  u8,
    x:  u8,
    y:  u8,

    // flags
    C: bool, // carry
    Z: bool, // zero
    I: bool, // interrupt
    D: bool, // decimal
    B: bool, // break
             // bit 5 is not used by the nes and is always 1
    V: bool, // overflow
    S: bool, // sign/negative

    // these are not strictly 6502 registers, but are useful for modeling the cpu
    instruction_register: u16,
    decode_register:DecodeRegister,
}

impl CpuState {
    fn unpack_flags(self: &CpuState) -> u8 {
        ( (self.C as u8) << 0)
      | ( (self.Z as u8) << 1)
      | ( (self.I as u8) << 2)
      | ( (self.D as u8) << 3)
      | ( (self.B as u8) << 4)
      | ( (1           ) << 5) // flag 5 is unused
      | ( (self.V as u8) << 6)
      | ( (self.S as u8) << 7)
    }
    fn pack_flags(self: &mut CpuState,flags:u8) {
        self.C        = ( (flags >> 0) & 1) == 1;
        self.Z        = ( (flags >> 1) & 1) == 1;
        self.I        = ( (flags >> 2) & 1) == 1;
        self.D        = ( (flags >> 3) & 1) == 1;
        self.B        = ( (flags >> 4) & 1) == 1;
        // flags 5 is unused
        self.V        = ( (flags >> 6) & 1) == 1;
        self.S        = ( (flags >> 7) & 1) == 1;
    }
}
<|endoftext|>