<commit_before>use core::mapped_file::FileHandle;
use core::mapped_file::MappedFile;

//
pub type Id = u64;
pub type Offset = u64;
pub type PageSize = usize;

//
#[derive(Debug)]
pub enum OpenMode {
    ReadOnly = 0,
    ReadWrite = 1,
}

/// The **Buffer** represents a linear array of bytes.

/// it can be in memory only or backed by an on disk file.

/// The editor will **Modes** use this api to read/modify the content
/// of the file at the byte level
#[derive(Debug)]
pub struct Buffer<'a> {
    pub id: Id,
    /// the name of the file where the data will be synced
    pub file_name: String,
    /// the current size of the buffer
    pub size: usize,
    /// the number of changes (since last save TODO)
    pub nr_changes: u64,
    mode: OpenMode,
    pub data: FileHandle<'a>,
}

impl<'a> Buffer<'a> {
    /// Creates a new `Buffer`.
    ///
    /// file_name param[in] path to the file we want to load in the buffer,
    /// use "/dev/null" to create empty buffer
    /// this function allocate a buffer
    /// if file_name is null the content will be stored in heap
    /// if file_name is non null the the content will be read from the file
    /// if document_name is null , file_name will be used to give a name to the buffer
    /// mode = 0 : read only , mode 1 : read_write
    /// the allocated_bid pointer will be filled on successfull open operation
    pub fn new(file_name: String, mode: OpenMode) -> Option<Buffer<'a>> {
        // TODO: check permission
        // TODO: check file's type => ignore directory (for now)
        // println!("-- mapping file {}", file_name);

        let page_size = 4096 * 256 * 2;
        let file = match MappedFile::new(file_name.clone(), page_size) {
            Some(file) => file,
            None => {
                eprintln!("cannot map file '{}'", file_name);
                return None;
            }
        };

        let size = file.as_ref().borrow().size() as usize;

        // println!("'{}' opened size '{}'", file_name, size);

        Some(Buffer {
            id: 0,
            file_name: file_name.clone(),
            mode,
            size,
            nr_changes: 0,
            data: file,
        })
    }

    /// not implemented: close a previously opened buffer see buffer_open
    pub fn close(&mut self) -> bool {
        unimplemented!();
        // false
    }

    /// returns the name of the file associated to the buffer
    pub fn get_file_name(&self) -> String {
        self.file_name.clone()
    }

    /// change the on disk target file
    pub fn set_file_name(&mut self, name: String) -> bool {
        self.file_name = name;
        true
    }

    /// returns the number of bytes a given buffer contains
    pub fn size(&self) -> usize {
        self.size
    }

    /// returns the number of changes sine the last save

    ///     0  => the no change since last save

    ///     >0 => the number of changes since last save

    pub fn nr_changes(&self) -> u64 {
        self.nr_changes
    }

    /// copy the content of the buffer up to 'nr_bytes' into the data Vec
    /// the read bytes are appended to the data Vec
    /// return XXX on error (use ioresult)
    pub fn read(&self, offset: u64, nr_bytes: usize, mut data: &mut Vec<u8>) -> usize {
        let mut it = MappedFile::iter_from(&self.data, offset);
        MappedFile::read(&mut it, nr_bytes, &mut data)
    }

    /// insert the 'data' Vec content in the buffer up to 'nr_bytes'
    /// return the number of written bytes (TODO: use io::Result)
    pub fn insert(&mut self, offset: u64, nr_bytes: usize, data: &[u8]) -> usize {
        let mut it = MappedFile::iter_from(&self.data, offset);
        MappedFile::insert(&mut it, &data);

        self.size += nr_bytes;
        self.nr_changes += 1;

        nr_bytes
    }

    /// remove up to 'nr_bytes' from the buffer starting at offset
    /// if removed_data is provided will call self.read(offset, nr_bytes, data)
    /// before remove the bytes
    pub fn remove(
        &mut self,
        offset: u64,
        nr_bytes: usize,
        removed_data: Option<&mut Vec<u8>>,
    ) -> usize {
        let start_offset = ::std::cmp::min(offset as usize, self.size);
        let end_offset = ::std::cmp::min(start_offset + nr_bytes, self.size);
        let nr_bytes_removed = (end_offset - start_offset) as usize;

        // copy removed data
        if let Some(v) = removed_data {
            self.read(offset, nr_bytes_removed, v);
        }

        let mut it = MappedFile::iter_from(&self.data, start_offset as u64);
        MappedFile::remove(&mut it, nr_bytes_removed);

        self.size -= nr_bytes_removed;
        self.nr_changes += 1;

        nr_bytes_removed
    }

    /// can be used to know the number of blocks that compose the buffer,
    /// api to be used by indexer etc...
    pub fn nr_pages(&self) -> u64 {
        1
    }

    /*
    /// returns the position and size of a given page
    pub fn get_page_info(&self, page_index: u64) -> (Offset, PageSize) {
        // if page_index > 0 {
        //    (0, self.size)
        // } else {
        //    (0, self.size)
        // }
        (0, self.size)
    }
*/

    pub fn sync_to_disk(&self, tmp_file_name: &str) -> ::std::io::Result<()> {
        let metadata = ::std::fs::metadata(&self.file_name).unwrap();
        let perms = metadata.permissions();

        let res = MappedFile::sync_to_disk(
            &mut self.data.as_ref().borrow_mut(),
            &tmp_file_name,
            &self.file_name,
        );

        // TODO: check result, handle io results properly
        ::std::fs::set_permissions(&self.file_name, perms).unwrap();

        res
    }
}

#[test]
fn test_buffer() {
    let mut bb = Buffer::new("/dev/null".to_owned(), OpenMode::ReadWrite).unwrap();

    let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    bb.insert(0, 10, &data);
    let mut rdata = Vec::new();
    let nread = bb.read(0, bb.size(), &mut rdata);
    assert_eq!(rdata, data);
    assert_eq!(nread, bb.size());

    let data = vec![0, 1, 2, 6, 7, 8, 9];
    let rm_expect = vec![3, 4, 5];

    let mut rm = vec![];
    let n = bb.remove(3, 3, Some(&mut rm));
    assert_eq!(n, 3);
    assert_eq!(rm, rm_expect);

    rdata.clear();
    let nread = bb.read(0, bb.size(), &mut rdata);
    assert_eq!(rdata, data);
    assert_eq!(nread, bb.size());

    println!("rm {:?}", rm);
    println!("rm_expect {:?}", rm_expect);
}
<commit_msg>ignore permissions error<commit_after>use core::mapped_file::FileHandle;
use core::mapped_file::MappedFile;

//
pub type Id = u64;
pub type Offset = u64;
pub type PageSize = usize;

//
#[derive(Debug)]
pub enum OpenMode {
    ReadOnly = 0,
    ReadWrite = 1,
}

/// The **Buffer** represents a linear array of bytes.

/// it can be in memory only or backed by an on disk file.

/// The editor will **Modes** use this api to read/modify the content
/// of the file at the byte level
#[derive(Debug)]
pub struct Buffer<'a> {
    pub id: Id,
    /// the name of the file where the data will be synced
    pub file_name: String,
    /// the current size of the buffer
    pub size: usize,
    /// the number of changes (since last save TODO)
    pub nr_changes: u64,
    mode: OpenMode,
    pub data: FileHandle<'a>,
}

impl<'a> Buffer<'a> {
    /// Creates a new `Buffer`.
    ///
    /// file_name param[in] path to the file we want to load in the buffer,
    /// use "/dev/null" to create empty buffer
    /// this function allocate a buffer
    /// if file_name is null the content will be stored in heap
    /// if file_name is non null the the content will be read from the file
    /// if document_name is null , file_name will be used to give a name to the buffer
    /// mode = 0 : read only , mode 1 : read_write
    /// the allocated_bid pointer will be filled on successfull open operation
    pub fn new(file_name: String, mode: OpenMode) -> Option<Buffer<'a>> {
        // TODO: check permission
        // TODO: check file's type => ignore directory (for now)
        // println!("-- mapping file {}", file_name);

        let page_size = 4096 * 256 * 2;
        let file = match MappedFile::new(file_name.clone(), page_size) {
            Some(file) => file,
            None => {
                eprintln!("cannot map file '{}'", file_name);
                return None;
            }
        };

        let size = file.as_ref().borrow().size() as usize;

        // println!("'{}' opened size '{}'", file_name, size);

        Some(Buffer {
            id: 0,
            file_name: file_name.clone(),
            mode,
            size,
            nr_changes: 0,
            data: file,
        })
    }

    /// not implemented: close a previously opened buffer see buffer_open
    pub fn close(&mut self) -> bool {
        unimplemented!();
        // false
    }

    /// returns the name of the file associated to the buffer
    pub fn get_file_name(&self) -> String {
        self.file_name.clone()
    }

    /// change the on disk target file
    pub fn set_file_name(&mut self, name: String) -> bool {
        self.file_name = name;
        true
    }

    /// returns the number of bytes a given buffer contains
    pub fn size(&self) -> usize {
        self.size
    }

    /// returns the number of changes sine the last save

    ///     0  => the no change since last save

    ///     >0 => the number of changes since last save

    pub fn nr_changes(&self) -> u64 {
        self.nr_changes
    }

    /// copy the content of the buffer up to 'nr_bytes' into the data Vec
    /// the read bytes are appended to the data Vec
    /// return XXX on error (use ioresult)
    pub fn read(&self, offset: u64, nr_bytes: usize, mut data: &mut Vec<u8>) -> usize {
        let mut it = MappedFile::iter_from(&self.data, offset);
        MappedFile::read(&mut it, nr_bytes, &mut data)
    }

    /// insert the 'data' Vec content in the buffer up to 'nr_bytes'
    /// return the number of written bytes (TODO: use io::Result)
    pub fn insert(&mut self, offset: u64, nr_bytes: usize, data: &[u8]) -> usize {
        let mut it = MappedFile::iter_from(&self.data, offset);
        MappedFile::insert(&mut it, &data);

        self.size += nr_bytes;
        self.nr_changes += 1;

        nr_bytes
    }

    /// remove up to 'nr_bytes' from the buffer starting at offset
    /// if removed_data is provided will call self.read(offset, nr_bytes, data)
    /// before remove the bytes
    pub fn remove(
        &mut self,
        offset: u64,
        nr_bytes: usize,
        removed_data: Option<&mut Vec<u8>>,
    ) -> usize {
        let start_offset = ::std::cmp::min(offset as usize, self.size);
        let end_offset = ::std::cmp::min(start_offset + nr_bytes, self.size);
        let nr_bytes_removed = (end_offset - start_offset) as usize;

        // copy removed data
        if let Some(v) = removed_data {
            self.read(offset, nr_bytes_removed, v);
        }

        let mut it = MappedFile::iter_from(&self.data, start_offset as u64);
        MappedFile::remove(&mut it, nr_bytes_removed);

        self.size -= nr_bytes_removed;
        self.nr_changes += 1;

        nr_bytes_removed
    }

    /// can be used to know the number of blocks that compose the buffer,
    /// api to be used by indexer etc...
    pub fn nr_pages(&self) -> u64 {
        1
    }

    /*
    /// returns the position and size of a given page
    pub fn get_page_info(&self, page_index: u64) -> (Offset, PageSize) {
        // if page_index > 0 {
        //    (0, self.size)
        // } else {
        //    (0, self.size)
        // }
        (0, self.size)
    }
*/

    pub fn sync_to_disk(&self, tmp_file_name: &str) -> ::std::io::Result<()> {
        let metadata = ::std::fs::metadata(&self.file_name).unwrap();
        let perms = metadata.permissions();

        let res = MappedFile::sync_to_disk(
            &mut self.data.as_ref().borrow_mut(),
            &tmp_file_name,
            &self.file_name,
        );

        // TODO: check result, handle io results properly
        // set buffer status to : permission denied etc
        let _ = ::std::fs::set_permissions(&self.file_name, perms);

        res
    }
}

#[test]
fn test_buffer() {
    let mut bb = Buffer::new("/dev/null".to_owned(), OpenMode::ReadWrite).unwrap();

    let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    bb.insert(0, 10, &data);
    let mut rdata = Vec::new();
    let nread = bb.read(0, bb.size(), &mut rdata);
    assert_eq!(rdata, data);
    assert_eq!(nread, bb.size());

    let data = vec![0, 1, 2, 6, 7, 8, 9];
    let rm_expect = vec![3, 4, 5];

    let mut rm = vec![];
    let n = bb.remove(3, 3, Some(&mut rm));
    assert_eq!(n, 3);
    assert_eq!(rm, rm_expect);

    rdata.clear();
    let nread = bb.read(0, bb.size(), &mut rdata);
    assert_eq!(rdata, data);
    assert_eq!(nread, bb.size());

    println!("rm {:?}", rm);
    println!("rm_expect {:?}", rm_expect);
}
<|endoftext|>


<commit_before>use std::treemap;
use std::treemap::TreeMap;

#[test]
fn test_environment_accepts_new_value_and_returns_it() {
    let env:Environment = Environment::new_global_environment();
    env.define( ~"monkey", Int(1) );
    env.define( ~"turkey", Int(2) );
    match env.lookup( ~"monkey" ) {
        Some(Int(1)) => (),
        _ => fail ~"Monkey wasn't an Int(1)"
    }
    match env.lookup( ~"turkey" ) {
        Some(Int(2)) => (),
        _ => fail ~"Turkey wasn't an Int(2)"
    }
}

#[test]
fn test_environment_allows_values_to_change() {
    let env:Environment = Environment::new_global_environment();
    env.define( ~"monkey", Int(1) );
    match env.lookup( ~"monkey" ) {
        Some(Int(1)) => (),
        _ => fail ~"Monkey wasn't an Int(1) before mutation"
    }
    env.define( ~"monkey", Int(2) );
    match env.lookup( ~"monkey" ) {
        Some(Int(2)) => (),
        _ => fail ~"Monkey wasn't an Int(2) after mutation"
    }
}

#[test]
fn test_environment_checks_enclosing_environment() {
    let enclosure:~Environment = ~Environment::new_global_environment();
    enclosure.define( ~"monkey", Int(1) );
    let env:Environment = Environment::new(enclosure);
    match env.lookup( ~"monkey" ) {
        Some(Int(1)) => (),
        _ => fail ~"monkey wasn't found in env or enclosure... he's escaped?"
    }
}

pub struct Environment {
    enclosure:Option<~Environment>,
    mappings:TreeMap<~str,Expression>
}

pub impl Environment {
    fn define(&self, key:~str, value:Expression) {
        treemap::insert(self.mappings, key, value);
    }

    fn check_enclosure(&self, key:~str) -> Option<Expression> {
        match copy self.enclosure {
            Some(environment) => environment.lookup(key),
            _ => None
        }
    }

    fn lookup(&self, key:~str) -> Option<Expression> {
        let local_definition = treemap::find(self.mappings, copy key);
        match local_definition {
            None => self.check_enclosure(key),
            _ => local_definition
        }
    }

    static fn new_global_environment() -> Environment {
        let mappings = TreeMap();
        let env = Environment {enclosure:None, mappings:mappings};
        env.define(~"+", Proc( |addends| {
            let mut sum = 0;
            for addends.each() |&expr| {
                match expr {
                    Int(addend) => sum += addend,
                    _ => fail ~"+ only accepts integers right now"
                }
            }
            Int(sum)
            } ));
        env
    }

    static fn new(enclosure:~Environment) -> Environment {
        let mappings = TreeMap();
        Environment {enclosure:Some(enclosure), mappings:mappings}
    }
}
<commit_msg>Change enclosed environment reference to a managed reference<commit_after>use std::treemap;
use std::treemap::TreeMap;

#[test]
fn test_environment_accepts_new_value_and_returns_it() {
    let env:Environment = Environment::new_global_environment();
    env.define( ~"monkey", Int(1) );
    env.define( ~"turkey", Int(2) );
    match env.lookup( ~"monkey" ) {
        Some(Int(1)) => (),
        _ => fail ~"Monkey wasn't an Int(1)"
    }
    match env.lookup( ~"turkey" ) {
        Some(Int(2)) => (),
        _ => fail ~"Turkey wasn't an Int(2)"
    }
}

#[test]
fn test_environment_allows_values_to_change() {
    let env:Environment = Environment::new_global_environment();
    env.define( ~"monkey", Int(1) );
    match env.lookup( ~"monkey" ) {
        Some(Int(1)) => (),
        _ => fail ~"Monkey wasn't an Int(1) before mutation"
    }
    env.define( ~"monkey", Int(2) );
    match env.lookup( ~"monkey" ) {
        Some(Int(2)) => (),
        _ => fail ~"Monkey wasn't an Int(2) after mutation"
    }
}

#[test]
fn test_environment_checks_enclosing_environment() {
    let enclosure:@Environment = @Environment::new_global_environment();
    enclosure.define( ~"monkey", Int(1) );
    let env:Environment = Environment::new(enclosure);
    match env.lookup( ~"monkey" ) {
        Some(Int(1)) => (),
        _ => fail ~"monkey wasn't found in env or enclosure... he's escaped?"
    }
}

pub struct Environment {
    enclosure:Option<@Environment>,
    mappings:TreeMap<~str,Expression>
}

pub impl Environment {
    fn define(&self, key:~str, value:Expression) {
        treemap::insert(self.mappings, key, value);
    }

    fn check_enclosure(&self, key:~str) -> Option<Expression> {
        match copy self.enclosure {
            Some(environment) => environment.lookup(key),
            _ => None
        }
    }

    fn lookup(&self, key:~str) -> Option<Expression> {
        let local_definition = treemap::find(self.mappings, copy key);
        match local_definition {
            None => self.check_enclosure(key),
            _ => local_definition
        }
    }

    static fn new_global_environment() -> Environment {
        let mappings = TreeMap();
        let env = Environment {enclosure:None, mappings:mappings};
        env.define(~"+", Proc( |addends| {
            let mut sum = 0;
            for addends.each() |&expr| {
                match expr {
                    Int(addend) => sum += addend,
                    _ => fail ~"+ only accepts integers right now"
                }
            }
            Int(sum)
            } ));
        env
    }

    static fn new(enclosure:@Environment) -> Environment {
        let mappings = TreeMap();
        Environment {enclosure:Some(enclosure), mappings:mappings}
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::fs;
use std::io;
use std::iter;
use std::path::PathBuf;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};

use threadpool;

pub trait HasPath {
    fn path(&self) -> PathBuf;
}

impl HasPath for fs::DirEntry {
    fn path(&self) -> PathBuf {
        fs::DirEntry::path(self)
    }
}

pub trait PathHandler<D> {
    type DirIter;

    fn read_dir(&self, &PathBuf) -> io::Result<Self::DirIter>;
    fn handle_path(&self, D, PathBuf) -> Option<D>;
}

pub fn iterate_recursively<P: 'static + Send + Clone,
                           W: 'static + PathHandler<P> + Send + Clone,
                           I: 'static + HasPath>
    (first: (PathBuf, P),
     worker: &mut W)
    where W::DirIter: iter::Iterator<Item = io::Result<I>>
{
    let threads = 10;
    let (push_ch, work_ch) = mpsc::sync_channel(threads);
    let pool = threadpool::ThreadPool::new(threads);

    enum Work<P> {
        Done,
        More(PathBuf, P),
    }

    // Insert the first task into the queue:
    let (root, payload) = first;
    push_ch.send(Work::More(root, payload)).unwrap();
    let idle_workers = Arc::new(Mutex::new(vec![worker.clone(); threads]));
    let mut active_workers = 0;

    // Master thread:
    loop {
        match work_ch.recv() {
            Err(_) => unreachable!(),
            Ok(Work::Done) => {
                // A worker has completed a task.
                // We are done when no more workers are active (i.e. all tasks are done):
                active_workers -= 1;
                if active_workers == 0 {
                    break;
                }
            }
            Ok(Work::More(root, payload)) => {
                // Execute the task in a pool thread:
                active_workers += 1;

                let idle_workers_ = idle_workers.clone();
                let push_ch_ = push_ch.clone();
                pool.execute(move || {
                    let worker = {
                        let mut lock = idle_workers_.lock().unwrap();
                        lock.pop().expect("not enough workers")
                    };
                    match worker.read_dir(&root) {
                        Ok(dir) => {
                            for entry_res in dir {
                                match entry_res {
                                    Ok(entry) => {
                                        let file = entry.path();
                                        let path = PathBuf::from(file.to_str().unwrap());
                                        let dir_opt = worker.handle_path(payload.clone(), path);
                                        if let Some(dir) = dir_opt {
                                            push_ch_.send(Work::More(file, dir)).unwrap();
                                        }
                                    }
                                    Err(err) => {
                                        // For some reason, we failed to read this entry.
                                        // Just skip it and continue with the next.
                                        warn!("Could not read directory entry: {}", err);
                                    }
                                }
                            }
                        }
                        Err(err) => {
                            // Cannot read this directory.
                            warn!("Skipping unreadable directory {:?}: {}", root, err);
                        }
                    }
                    // Return our worker.
                    idle_workers_.lock().unwrap().push(worker);
                    // Count this pool thread as idle:
                    push_ch_.send(Work::Done).unwrap();
                });
            }
        }
    }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
    fn clone(&self) -> PrintPathHandler {
        PrintPathHandler
    }
}

impl PathHandler<()> for PrintPathHandler {
    type DirIter = fs::ReadDir;

    fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
        fs::read_dir(path)
    }

    fn handle_path(&self, _: (), path: PathBuf) -> Option<()> {
        println!("{}", path.display());
        match fs::metadata(&path) {
            Ok(ref m) if m.is_dir() => Some(()),
            _ => None,
        }
    }
}
<commit_msg>Add basic test for iterate_recursively.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::fs;
use std::io;
use std::iter;
use std::path::PathBuf;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};

use threadpool;

pub trait HasPath {
    fn path(&self) -> PathBuf;
}

impl HasPath for fs::DirEntry {
    fn path(&self) -> PathBuf {
        fs::DirEntry::path(self)
    }
}

pub trait PathHandler<D> {
    type DirIter;

    fn read_dir(&self, &PathBuf) -> io::Result<Self::DirIter>;
    fn handle_path(&self, D, PathBuf) -> Option<D>;
}

pub fn iterate_recursively<P: 'static + Send + Clone,
                           W: 'static + PathHandler<P> + Send + Clone,
                           I: 'static + HasPath>
    (first: (PathBuf, P),
     worker: &mut W)
    where W::DirIter: iter::Iterator<Item = io::Result<I>>
{
    let threads = 10;
    let (push_ch, work_ch) = mpsc::sync_channel(threads);
    let pool = threadpool::ThreadPool::new(threads);

    enum Work<P> {
        Done,
        More(PathBuf, P),
    }

    // Insert the first task into the queue:
    let (root, payload) = first;
    push_ch.send(Work::More(root, payload)).unwrap();
    let idle_workers = Arc::new(Mutex::new(vec![worker.clone(); threads]));
    let mut active_workers = 0;

    // Master thread:
    loop {
        match work_ch.recv() {
            Err(_) => unreachable!(),
            Ok(Work::Done) => {
                // A worker has completed a task.
                // We are done when no more workers are active (i.e. all tasks are done):
                active_workers -= 1;
                if active_workers == 0 {
                    break;
                }
            }
            Ok(Work::More(root, payload)) => {
                // Execute the task in a pool thread:
                active_workers += 1;

                let idle_workers_ = idle_workers.clone();
                let push_ch_ = push_ch.clone();
                pool.execute(move || {
                    let worker = {
                        let mut lock = idle_workers_.lock().unwrap();
                        lock.pop().expect("not enough workers")
                    };
                    match worker.read_dir(&root) {
                        Ok(dir) => {
                            for entry_res in dir {
                                match entry_res {
                                    Ok(entry) => {
                                        let file = entry.path();
                                        let path = PathBuf::from(file.to_str().unwrap());
                                        let dir_opt = worker.handle_path(payload.clone(), path);
                                        if let Some(dir) = dir_opt {
                                            push_ch_.send(Work::More(file, dir)).unwrap();
                                        }
                                    }
                                    Err(err) => {
                                        // For some reason, we failed to read this entry.
                                        // Just skip it and continue with the next.
                                        warn!("Could not read directory entry: {}", err);
                                    }
                                }
                            }
                        }
                        Err(err) => {
                            // Cannot read this directory.
                            warn!("Skipping unreadable directory {:?}: {}", root, err);
                        }
                    }
                    // Return our worker.
                    idle_workers_.lock().unwrap().push(worker);
                    // Count this pool thread as idle:
                    push_ch_.send(Work::Done).unwrap();
                });
            }
        }
    }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
    fn clone(&self) -> PrintPathHandler {
        PrintPathHandler
    }
}

impl PathHandler<()> for PrintPathHandler {
    type DirIter = fs::ReadDir;

    fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
        fs::read_dir(path)
    }

    fn handle_path(&self, _: (), path: PathBuf) -> Option<()> {
        println!("{}", path.display());
        match fs::metadata(&path) {
            Ok(ref m) if m.is_dir() => Some(()),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {

    use std::collections::btree_map;
    use std::io;
    use std::path::PathBuf;
    use std::sync::{Arc, Mutex};
    use std::vec;

    use super::*;

    type ParentOpt = Option<PathBuf>;
    type VisitedPaths = btree_map::BTreeMap<PathBuf, bool>;

    impl HasPath for PathBuf {
        fn path(&self) -> PathBuf {
            self.to_owned()
        }
    }

    #[derive(Clone)]
    struct StubPathHandler {
        paths: Arc<Mutex<VisitedPaths>>,
    }

    impl StubPathHandler {
        fn new(paths: Vec<PathBuf>) -> StubPathHandler {
            let mut tree = btree_map::BTreeMap::new();
            for path in paths {
                tree.insert(path, false);
            }
            StubPathHandler { paths: Arc::new(Mutex::new(tree)) }
        }

        fn visit(&self, path: PathBuf) -> Option<bool> {
            let mut paths = self.paths.lock().unwrap();
            paths.insert(path, true)
        }

        fn list(&self, dir: &PathBuf) -> vec::IntoIter<io::Result<PathBuf>> {
            let paths = self.paths.lock().unwrap();
            let mut contents = vec![];
            for k in paths.keys() {
                if k.parent() == Some(dir) {
                    contents.push(Ok(k.clone()));
                }
            }
            contents.into_iter()
        }

        fn not_visited(&self) -> Vec<PathBuf> {
            let paths = self.paths.lock().unwrap();
            let mut contents = vec![];
            for (path, visited) in paths.iter() {
                if !visited {
                    contents.push(path.clone());
                }
            }
            contents
        }
    }

    impl PathHandler<ParentOpt> for StubPathHandler {
        type DirIter = vec::IntoIter<io::Result<PathBuf>>;

        fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
            Ok(self.list(path))
        }

        fn handle_path(&self, p_opt: ParentOpt, path: PathBuf) -> Option<ParentOpt> {
            assert_eq!(self.visit(path.clone()), Some(false));

            if let Some(p) = p_opt {
                assert!(path.parent() == Some(&p));
            }

            self.list(&path).next().map(|_| Some(path))
        }
    }

    #[test]
    fn can_visit_all() {
        let paths: [&str; 20] = ["/",
                                 "/foo",
                                 "/bar/",
                                 "/bar/baz/",
                                 "/bar/baz/qux",
                                 "/bar/baz/foo",
                                 "/bar/baz/bar/",
                                 "/bar/baz/bar/foo",
                                 "/bar/baz/bar/bar/",
                                 "/bar/baz/bar/bar/bar",
                                 "/empty/",
                                 "/empty/1/",
                                 "/empty/2/",
                                 "/empty/3/",
                                 "/empty/4/",
                                 "/empty/5/",
                                 "/empty/6/",
                                 "/empty/7/",
                                 "/empty/8/",
                                 "/empty/9/",
                                 ];

        let mut handler = StubPathHandler::new(paths.iter().map(PathBuf::from).collect());
        iterate_recursively((PathBuf::from("/"), None), &mut handler);

        assert_eq!(handler.not_visited(), vec![PathBuf::from("/")]);
    }

}
<|endoftext|>


<commit_before>use std::{
    cell::RefCell,
    fmt,
    io::{self, Write as _}
};

pub use {
    wayland_client::{
        protocol::{
            wl_buffer::WlBuffer, wl_output::WlOutput, wl_surface::WlSurface
        },
        NewProxy, Proxy
    },
    wayland_protocols::wlr::unstable::layer_shell::v1::client::{
        zwlr_layer_shell_v1::{
            self as layer_shell, Layer, ZwlrLayerShellV1 as LayerShell
        },
        zwlr_layer_surface_v1::{
            self as layer_surface, ZwlrLayerSurfaceV1 as WlrLayerSurface
        }
    }
};

use crate::{
    area::{Margin, Size},
    wayland::{self, Buffer}
};

/// The minimum version of the wl_layer_shell protocol to bind to.
pub const LAYER_SHELL_VERSION: u32 = 1;

thread_local! {
    /// The layer shell surface creator.
    ///
    /// This should remain local to just this module.
    static LAYER_SHELL_CREATOR: RefCell<Option<LayerShell>> =
        RefCell::new(None);
}

#[derive(Eq, PartialEq)]
pub struct LayerSurfaceState {
    pub wl_surface: WlSurface,
    pub buffer: Option<Buffer>,
    pub configuration_serial: Option<u32>
}

pub struct LayerSurface {
    proxy: WlrLayerSurface
}

impl fmt::Debug for LayerSurface {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.proxy.as_ref().c_ptr())
    }
}

impl LayerSurface {
    pub fn set_size(&self, size: Size) {
        self.proxy.set_size(size.width, size.height);
    }

    pub fn set_margin(&self, margin: Margin) {
        self.proxy.set_margin(
            margin.top,
            margin.right,
            margin.bottom,
            margin.left
        );
    }

    pub fn set_surface(&mut self, size: Size) -> Result<(), ()> {
        let buffer = wayland::create_buffer(size)?;
        let mut state = unwrap_state(self.proxy.as_ref()).borrow_mut();
        state.wl_surface.attach(Some(&buffer.buffer), 0, 0);
        state.buffer = Some(buffer);
        Ok(())
    }

    pub fn write_to_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> {
        let mut state = unwrap_state(self.proxy.as_ref()).borrow_mut();
        let buffer = state.buffer.as_mut().expect("buffer was none");

        buffer.shared_memory.write(data)?;
        buffer.shared_memory.flush()?;
        Ok(())
    }

    pub fn commit(&self) {
        let state = unwrap_state(self.proxy.as_ref()).borrow_mut();
        state.wl_surface.commit();
    }
}

struct LayerShellHandler;

struct LayerSurfaceHandler {
    wl_surface: WlSurface,
    buffer: Option<WlBuffer>,
    configuration_serial: Option<u32>
}

impl LayerSurfaceHandler {
    fn new(wl_surface: WlSurface) -> Self {
        LayerSurfaceHandler {
            wl_surface,
            buffer: None,
            configuration_serial: None
        }
    }
}

impl layer_shell::EventHandler for LayerShellHandler {}

impl layer_surface::EventHandler for LayerSurfaceHandler {
    fn configure(
        &mut self,
        layer_surface: WlrLayerSurface,
        serial: u32,
        _width: u32,
        _height: u32
    ) {
        if self.buffer.is_some() {
            self.wl_surface.attach(self.buffer.as_ref(), 0, 0);
            self.wl_surface.commit();
        }

        self.configuration_serial = Some(serial);
        layer_surface.ack_configure(serial);

        let mut state = unwrap_state(layer_surface.as_ref()).borrow_mut();
        state.configuration_serial = Some(serial);

        if let Some(buffer) = state.buffer.as_ref() {
            state.wl_surface.attach(Some(&buffer.buffer), 0, 0);
            state.wl_surface.commit();
        }
    }

    fn closed(&mut self, _: WlrLayerSurface) {}
}

pub fn layer_shell_init(new_proxy: NewProxy<LayerShell>) -> LayerShell {
    let layer_shell = new_proxy.implement(LayerShellHandler, ());

    LAYER_SHELL_CREATOR.with(|shell_creator| {
        *shell_creator.borrow_mut() = Some(layer_shell.clone());
    });

    layer_shell
}

pub fn create_layer_surface(
    output: Option<&WlOutput>,
    layer: Layer,
    namespace: String
) -> Result<LayerSurface, ()> {
    let surface = crate::wayland::create_surface()?;

    let layer_surface = LAYER_SHELL_CREATOR.with(|creator| {
        let creator = creator.borrow();
        let creator = creator
            .as_ref()
            .expect("Layer shell creator not initilized");
        creator
            .get_layer_surface(
                &surface,
                output,
                layer,
                namespace,
                |new_proxy| {
                    let state = LayerSurfaceState {
                        wl_surface: surface.clone(),
                        buffer: None,
                        configuration_serial: None
                    };
                    let proxy = new_proxy.implement(
                        LayerSurfaceHandler::new(surface.clone()),
                        RefCell::new(state)
                    );

                    proxy
                }
            )
            .map(|proxy| LayerSurface { proxy })
    })?;

    layer_surface.commit();

    Ok(layer_surface)
}

fn unwrap_state(proxy: &Proxy<WlrLayerSurface>) -> &RefCell<LayerSurfaceState> {
    proxy
        .user_data::<RefCell<LayerSurfaceState>>()
        .expect("User data has not been set yet")
}
<commit_msg>Anchor all layer shells to top left<commit_after>use std::{
    cell::RefCell,
    fmt,
    io::{self, Write as _}
};

pub use {
    wayland_client::{
        protocol::{
            wl_buffer::WlBuffer, wl_output::WlOutput, wl_surface::WlSurface
        },
        NewProxy, Proxy
    },
    wayland_protocols::wlr::unstable::layer_shell::v1::client::{
        zwlr_layer_shell_v1::{
            self as layer_shell, Layer, ZwlrLayerShellV1 as LayerShell
        },
        zwlr_layer_surface_v1::{
            self as layer_surface, Anchor,
            ZwlrLayerSurfaceV1 as WlrLayerSurface
        }
    }
};

use crate::{
    area::{Margin, Size},
    wayland::{self, Buffer}
};

/// The minimum version of the wl_layer_shell protocol to bind to.
pub const LAYER_SHELL_VERSION: u32 = 1;

thread_local! {
    /// The layer shell surface creator.
    ///
    /// This should remain local to just this module.
    static LAYER_SHELL_CREATOR: RefCell<Option<LayerShell>> =
        RefCell::new(None);
}

#[derive(Eq, PartialEq)]
pub struct LayerSurfaceState {
    pub wl_surface: WlSurface,
    pub buffer: Option<Buffer>,
    pub configuration_serial: Option<u32>
}

pub struct LayerSurface {
    proxy: WlrLayerSurface
}

impl fmt::Debug for LayerSurface {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.proxy.as_ref().c_ptr())
    }
}

impl LayerSurface {
    pub fn set_size(&self, size: Size) {
        self.proxy.set_size(size.width, size.height);
    }

    pub fn set_margin(&self, margin: Margin) {
        self.proxy.set_margin(
            margin.top,
            margin.right,
            margin.bottom,
            margin.left
        );
    }

    pub fn set_surface(&mut self, size: Size) -> Result<(), ()> {
        let buffer = wayland::create_buffer(size)?;
        let mut state = unwrap_state(self.proxy.as_ref()).borrow_mut();
        state.wl_surface.attach(Some(&buffer.buffer), 0, 0);
        state.buffer = Some(buffer);
        Ok(())
    }

    pub fn write_to_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> {
        let mut state = unwrap_state(self.proxy.as_ref()).borrow_mut();
        let buffer = state.buffer.as_mut().expect("buffer was none");

        buffer.shared_memory.write(data)?;
        buffer.shared_memory.flush()?;
        Ok(())
    }

    pub fn commit(&self) {
        let state = unwrap_state(self.proxy.as_ref()).borrow_mut();
        state.wl_surface.commit();
    }
}

struct LayerShellHandler;

struct LayerSurfaceHandler {
    wl_surface: WlSurface,
    buffer: Option<WlBuffer>,
    configuration_serial: Option<u32>
}

impl LayerSurfaceHandler {
    fn new(wl_surface: WlSurface) -> Self {
        LayerSurfaceHandler {
            wl_surface,
            buffer: None,
            configuration_serial: None
        }
    }
}

impl layer_shell::EventHandler for LayerShellHandler {}

impl layer_surface::EventHandler for LayerSurfaceHandler {
    fn configure(
        &mut self,
        layer_surface: WlrLayerSurface,
        serial: u32,
        _width: u32,
        _height: u32
    ) {
        if self.buffer.is_some() {
            self.wl_surface.attach(self.buffer.as_ref(), 0, 0);
            self.wl_surface.commit();
        }

        self.configuration_serial = Some(serial);
        layer_surface.ack_configure(serial);

        let mut state = unwrap_state(layer_surface.as_ref()).borrow_mut();
        state.configuration_serial = Some(serial);

        if let Some(buffer) = state.buffer.as_ref() {
            state.wl_surface.attach(Some(&buffer.buffer), 0, 0);
            state.wl_surface.commit();
        }
    }

    fn closed(&mut self, _: WlrLayerSurface) {}
}

pub fn layer_shell_init(new_proxy: NewProxy<LayerShell>) -> LayerShell {
    let layer_shell = new_proxy.implement(LayerShellHandler, ());

    LAYER_SHELL_CREATOR.with(|shell_creator| {
        *shell_creator.borrow_mut() = Some(layer_shell.clone());
    });

    layer_shell
}

pub fn create_layer_surface(
    output: Option<&WlOutput>,
    layer: Layer,
    namespace: String
) -> Result<LayerSurface, ()> {
    let surface = crate::wayland::create_surface()?;

    let layer_surface = LAYER_SHELL_CREATOR.with(|creator| {
        let creator = creator.borrow();
        let creator = creator
            .as_ref()
            .expect("Layer shell creator not initilized");
        creator
            .get_layer_surface(
                &surface,
                output,
                layer,
                namespace,
                |new_proxy| {
                    let state = LayerSurfaceState {
                        wl_surface: surface.clone(),
                        buffer: None,
                        configuration_serial: None
                    };
                    let proxy = new_proxy.implement(
                        LayerSurfaceHandler::new(surface.clone()),
                        RefCell::new(state)
                    );

                    proxy.set_anchor(Anchor::Top | Anchor::Left);
                    proxy
                }
            )
            .map(|proxy| LayerSurface { proxy })
    })?;

    layer_surface.commit();

    Ok(layer_surface)
}

fn unwrap_state(proxy: &Proxy<WlrLayerSurface>) -> &RefCell<LayerSurfaceState> {
    proxy
        .user_data::<RefCell<LayerSurfaceState>>()
        .expect("User data has not been set yet")
}
<|endoftext|>


<commit_before>use parser::parser::{parse};
use expr::Expr;
use expr::Expr::*;
use expr::Val::*;
use expr::UnOp::*;
use expr::BinOp::*;
use expr::Dec::*;
use state::State;
use runtime_error::RuntimeError;
use std::result;

pub type Result<T> = result::Result<T, RuntimeError>;

pub struct Interpreter {
  pub state: State,
}

impl Interpreter {
  pub fn new() -> Interpreter {
    Interpreter {
      state: State::new(),
    }
  }

  pub fn step(&mut self, e: Expr) -> Result<Expr> {
    debug!("step(e) : {:?}", e);
    debug!("step(self.state) : {:?}", self.state.mem);

    let e1 = match e {
      Var(x) => {
        match self.state.get(x.clone()) {
          Some(e) => e,
          None => return Err(RuntimeError::VariableNotFound(x)),
        }
      },
      /**
       * Values are ineligible for step
       */
      Val(_) => {
        debug!("stepping on a value {:?}", e);
        return Err(RuntimeError::SteppingOnValue(e));
      },
      /**
       * Base cases
       */
      Uop(Not, box Val(Bool(b))) => {
        Val(Bool(!b))
      },
      Uop(Neg, box Val(Int(n))) => {
        Val(Int(-1 * n))
      },
      Bop(And, box Val(Bool(b1)), box Val(Bool(b2))) => {
        Val(Bool(b1 && b2))
      },
      Bop(Or, box Val(Bool(b1)), box Val(Bool(b2))) => {
        Val(Bool(b1 || b2))
      },
      Bop(Eq, box Val(v1), box Val(v2)) => {
        Val(Bool(v1 == v2))
      },
      Bop(Ne, box Val(v1), box Val(v2)) => {
        Val(Bool(v1 != v2))
      },
      Bop(Mod, box Val(Int(n1)), box Val(Int(n2))) => {
        // rust % gives the remainder, not modulus
        // let result = ((n1 % n2) + n2) % n2;
        let result = n1.checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?
          .checked_add(n2)
          .ok_or(RuntimeError::IntegerOverflow)?
          .checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?;

        Val(Int(result))
      },
      Bop(Lt, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 < n2))
      },
      Bop(Gt, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 > n2))
      },
      Bop(Leq, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 <= n2))
      },
      Bop(Geq, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 >= n2))
      },
      Bop(Plus, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_add(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Minus, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_sub(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Times, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_mul(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Div, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_div(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Seq, box Val(_), box e1) => {
        e1
      },
      Bop(Assign, box Var(x), box v @ Val(_)) => {
        self.state.assign(x, v.clone())?;
        debug!("done assigning {:?}", self.state.mem);
        v
      },
      Ternary(box Val(Bool(b)), box e1, box e2) => {
        match b {
          true => e1,
          false => e2,
        }
      },
      Decl(DConst, box Var(x), box v1 @ Val(_), box e1) => {
        self.state.alloc_const(x, v1)?;
        e1
      },
      Decl(DVar, box Var(x), box v1 @ Val(_), box e1) => {
        debug!("allocing {:?}", v1);
        self.state.alloc(x, v1)?;
        e1
      },
      // lambda lift so we can use iter() in guard
      // https://github.com/rust-lang/rfcs/issues/1006
      FnCall(ref v1, ref es) if v1.is_func() && (|| es.iter().all(|v| v.is_value()))() => {
        if let box Val(Func(name, e1, xs)) = v1.clone() {
          self.state.begin_scope();

          // alloc the params
          for (xn, en) in xs.iter().zip(es.iter()) {
            self.state.alloc(xn.to_var()?, en.clone())?;
          }

          // alloc the fn body for named functions
          if let Some(s) = name {
            self.state.alloc(s.to_var()?, *v1.clone())?;
          }

          Scope(e1)
        } else {
          return Err(RuntimeError::UnexpectedExpr("expected Func".to_string(), *v1.clone()))
        }
      },
      Scope(box v @ Val(_)) => {
        self.state.end_scope();
        v
      },
      While(box Val(Bool(b)), e1o, _, e2o, e3) => {
        match b {
          true => While(e1o.clone(), e1o, e2o.clone(), e2o, e3),
          false => *e3,
        }
      },
      Print(box Val(v)) => {
        println!("{}", v);
        Val(Undefined)
      },
      /**
       * Search Cases
       */
      Bop(op, v1 @ box Val(_), box e2) => {
        Bop(
          op,
          v1,
          Box::new(self.step(e2)?)
        )
      },
      Bop(Assign, v1 @ box Var(_), box e2) => {
        Bop(
          Assign,
          v1,
          Box::new(self.step(e2)?)
        )
      },
      Bop(op, box e1, e2) => {
        Bop(op, Box::new(self.step(e1)?), e2)
      },
      Uop(op, box e1) => {
        Uop(op, Box::new(self.step(e1)?))
      },
      Ternary(box e1, e2, e3) => {
        Ternary(Box::new(self.step(e1)?), e2, e3)
      },
      While(box e1, e1o, v @ box Val(_), e2o, e3) => {
        While(Box::new(self.step(e1)?), e1o, v, e2o, e3)
      },
      While(e1, e1o, box e2, e2o, e3) => {
        While(e1, e1o, Box::new(self.step(e2)?), e2o, e3)
      },
      Decl(dt, box addr, box e1, e2) => {
        Decl(dt, Box::new(addr.clone()), Box::new(self.step(e1)?), e2)
      },
      FnCall(f @ box Val(Func(_, _, _)), mut args) => {
        // find the first nonvalue arg and call step() on it
        if let Some(index) = args.iter().position(|e| {
          match e {
            &Val(_) => false,
            _ => true,
          }
        }) {
          args[index] = self.step(args[index].clone())?
        }

        FnCall(f, args)
      },
      FnCall(box e1, args) => {
        FnCall(Box::new(self.step(e1)?), args)
      },
      Scope(box e1) => {
        Scope(Box::new(self.step(e1)?))
      },
      Print(box e1) => {
        Print(Box::new(self.step(e1)?))
      },
    };

    debug!("returning with mem {:?}" , self.state.mem);
    debug!("returning with e {:?}" , e1);
    Ok(e1)
  }

  pub fn eval(&mut self, input: &str) -> Result<Expr> {
    let mut e = parse(input)?;

    let mut num_iterations = 0;

    loop {
      if num_iterations > 1000000000 {
        return Err(RuntimeError::TooManyIterations(num_iterations))
      }

      debug!("-----------------");
      debug!("--- iterating on e {:?} ", e);
      debug!("--- iterating on m {:?} ", self.state.mem);
      num_iterations += 1;
      if e.is_value() {
        debug!("--- iterations: {}", num_iterations);
        return Ok(e.clone());
      } else {
        e = self.step(e.clone())?;
      }
    }
  }
}
<commit_msg>avoid cloning whole function at each call<commit_after>use parser::parser::{parse};
use expr::Expr;
use expr::Expr::*;
use expr::Val::*;
use expr::UnOp::*;
use expr::BinOp::*;
use expr::Dec::*;
use state::State;
use runtime_error::RuntimeError;
use std::result;

pub type Result<T> = result::Result<T, RuntimeError>;

pub struct Interpreter {
  pub state: State,
}

impl Interpreter {
  pub fn new() -> Interpreter {
    Interpreter {
      state: State::new(),
    }
  }

  pub fn step(&mut self, e: Expr) -> Result<Expr> {
    debug!("step(e) : {:?}", e);
    debug!("step(self.state) : {:?}", self.state.mem);

    let e1 = match e {
      Var(x) => {
        match self.state.get(x.clone()) {
          Some(e) => e,
          None => return Err(RuntimeError::VariableNotFound(x)),
        }
      },
      /**
       * Values are ineligible for step
       */
      Val(_) => {
        debug!("stepping on a value {:?}", e);
        return Err(RuntimeError::SteppingOnValue(e));
      },
      /**
       * Base cases
       */
      Uop(Not, box Val(Bool(b))) => {
        Val(Bool(!b))
      },
      Uop(Neg, box Val(Int(n))) => {
        Val(Int(-1 * n))
      },
      Bop(And, box Val(Bool(b1)), box Val(Bool(b2))) => {
        Val(Bool(b1 && b2))
      },
      Bop(Or, box Val(Bool(b1)), box Val(Bool(b2))) => {
        Val(Bool(b1 || b2))
      },
      Bop(Eq, box Val(v1), box Val(v2)) => {
        Val(Bool(v1 == v2))
      },
      Bop(Ne, box Val(v1), box Val(v2)) => {
        Val(Bool(v1 != v2))
      },
      Bop(Mod, box Val(Int(n1)), box Val(Int(n2))) => {
        // rust % gives the remainder, not modulus
        // let result = ((n1 % n2) + n2) % n2;
        let result = n1.checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?
          .checked_add(n2)
          .ok_or(RuntimeError::IntegerOverflow)?
          .checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?;

        Val(Int(result))
      },
      Bop(Lt, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 < n2))
      },
      Bop(Gt, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 > n2))
      },
      Bop(Leq, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 <= n2))
      },
      Bop(Geq, box Val(Int(n1)), box Val(Int(n2))) => {
        Val(Bool(n1 >= n2))
      },
      Bop(Plus, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_add(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Minus, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_sub(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Times, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_mul(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Div, box Val(Int(n1)), box Val(Int(n2))) => {
        match n1.checked_div(n2) {
          Some(n) => Val(Int(n)),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Seq, box Val(_), box e1) => {
        e1
      },
      Bop(Assign, box Var(x), box v @ Val(_)) => {
        self.state.assign(x, v.clone())?;
        debug!("done assigning {:?}", self.state.mem);
        v
      },
      Ternary(box Val(Bool(b)), box e1, box e2) => {
        match b {
          true => e1,
          false => e2,
        }
      },
      Decl(DConst, box Var(x), box v1 @ Val(_), box e1) => {
        self.state.alloc_const(x, v1)?;
        e1
      },
      Decl(DVar, box Var(x), box v1 @ Val(_), box e1) => {
        debug!("allocing {:?}", v1);
        self.state.alloc(x, v1)?;
        e1
      },
      // lambda lift so we can use iter() in guard
      // https://github.com/rust-lang/rfcs/issues/1006
      FnCall(ref v1, ref es) if v1.is_func() && (|| es.iter().all(|v| v.is_value()))() => {
        if let box Val(Func(ref name, ref e1, ref xs)) = *v1 {
          self.state.begin_scope();

          // alloc the params
          for (xn, en) in xs.iter().zip(es.iter()) {
            self.state.alloc(xn.to_var()?, en.clone())?;
          }

          // alloc the fn body for named functions
          if let Some(ref s) = *name {
            self.state.alloc(s.to_var()?, *v1.clone())?;
          }

          Scope(e1.clone())
        } else {
          return Err(RuntimeError::UnexpectedExpr("expected Func".to_string(), *v1.clone()))
        }
      },
      Scope(box v @ Val(_)) => {
        self.state.end_scope();
        v
      },
      While(box Val(Bool(b)), e1o, _, e2o, e3) => {
        match b {
          true => While(e1o.clone(), e1o, e2o.clone(), e2o, e3),
          false => *e3,
        }
      },
      Print(box Val(v)) => {
        println!("{}", v);
        Val(Undefined)
      },
      /**
       * Search Cases
       */
      Bop(op, v1 @ box Val(_), box e2) => {
        Bop(
          op,
          v1,
          Box::new(self.step(e2)?)
        )
      },
      Bop(Assign, v1 @ box Var(_), box e2) => {
        Bop(
          Assign,
          v1,
          Box::new(self.step(e2)?)
        )
      },
      Bop(op, box e1, e2) => {
        Bop(op, Box::new(self.step(e1)?), e2)
      },
      Uop(op, box e1) => {
        Uop(op, Box::new(self.step(e1)?))
      },
      Ternary(box e1, e2, e3) => {
        Ternary(Box::new(self.step(e1)?), e2, e3)
      },
      While(box e1, e1o, v @ box Val(_), e2o, e3) => {
        While(Box::new(self.step(e1)?), e1o, v, e2o, e3)
      },
      While(e1, e1o, box e2, e2o, e3) => {
        While(e1, e1o, Box::new(self.step(e2)?), e2o, e3)
      },
      Decl(dt, box addr, box e1, e2) => {
        Decl(dt, Box::new(addr.clone()), Box::new(self.step(e1)?), e2)
      },
      FnCall(f @ box Val(Func(_, _, _)), mut args) => {
        // find the first nonvalue arg and call step() on it
        if let Some(index) = args.iter().position(|e| {
          match e {
            &Val(_) => false,
            _ => true,
          }
        }) {
          args[index] = self.step(args[index].clone())?
        }

        FnCall(f, args)
      },
      FnCall(box e1, args) => {
        FnCall(Box::new(self.step(e1)?), args)
      },
      Scope(box e1) => {
        Scope(Box::new(self.step(e1)?))
      },
      Print(box e1) => {
        Print(Box::new(self.step(e1)?))
      },
    };

    debug!("returning with mem {:?}" , self.state.mem);
    debug!("returning with e {:?}" , e1);
    Ok(e1)
  }

  pub fn eval(&mut self, input: &str) -> Result<Expr> {
    let mut e = parse(input)?;

    let mut num_iterations = 0;

    loop {
      if num_iterations > 1000000000 {
        return Err(RuntimeError::TooManyIterations(num_iterations))
      }

      debug!("-----------------");
      debug!("--- iterating on e {:?} ", e);
      debug!("--- iterating on m {:?} ", self.state.mem);
      num_iterations += 1;
      if e.is_value() {
        debug!("--- iterations: {}", num_iterations);
        return Ok(e.clone());
      } else {
        e = self.step(e.clone())?;
      }
    }
  }
}
<|endoftext|>


<commit_before>use parser::parser::{parse};
use expr::Expr;
use expr::Expr::*;
use expr::UnOp::*;
use expr::BinOp::*;
use expr::Dec::*;
use state::State;
use runtime_error::RuntimeError;
use std::result;

pub type Result<T> = result::Result<T, RuntimeError>;

pub struct Interpreter {
  pub state: State,
}

impl Interpreter {
  pub fn new() -> Interpreter {
    Interpreter {
      state: State::new(),
    }
  }

  pub fn step(&mut self, e: Expr) -> Result<Expr> {
    debug!("step(e) : {:?}", e);
    debug!("step(self.state) : {:?}", self.state.mem);

    let e1 = match e.clone() {
      Var(x) => {
        match self.state.get(x.clone()) {
          Some(e) => e,
          None => return Err(RuntimeError::VariableNotFound(x)),
        }
      },
      /**
       * Values are ineligible for step
       */
      Int(_) | Bool(_) | Func(_, _, _) | Undefined => {
        debug!("stepping on a value {:?}", e);
        return Err(RuntimeError::SteppingOnValue(e));
      },
      /**
       * Base cases
       */
      Uop(Not, ref e1) if e1.is_value() => {
        Bool(!e1.to_bool()?)
      },
      Uop(Neg, ref e1) if e1.is_value() => {
        Int(-1 * e1.to_int()?)
      },
      Bop(And, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_bool()? && e2.to_bool()?)
      },
      Bop(Or, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_bool()? || e2.to_bool()?)
      },
      Bop(Eq, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(*e1 == *e2)
      },
      Bop(Ne, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(*e1 != *e2)
      },
      Bop(Mod, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        let n1 = e1.to_int()?;
        let n2 = e2.to_int()?;

        // rust % gives the remainder, not modulus
        // let result = ((n1 % n2) + n2) % n2;
        let result = n1.checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?
          .checked_add(n2)
          .ok_or(RuntimeError::IntegerOverflow)?
          .checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?;

        Int(result)
      },
      Bop(Lt, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? < e2.to_int()?)
      },
      Bop(Gt, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? > e2.to_int()?)
      },
      Bop(Leq, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? <= e2.to_int()?)
      },
      Bop(Geq, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? >= e2.to_int()?)
      },
      Bop(Plus, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_add(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Minus, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_sub(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Times, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_mul(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Div, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_div(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Seq, ref v1, ref e2) if v1.is_value() => {
        *e2.clone()
      },
      Bop(Assign, ref v1, ref v2) if v1.is_var() && v2.is_value() => {
        let x = v1.to_var()?;
        self.state.assign(x, *v2.clone())?;
        debug!("done assigning {:?}", self.state.mem);
        *v2.clone()
      },
      Ternary(ref v1, ref e2, ref e3) if v1.is_value() => {
        match v1.to_bool()? {
          true => *e2.clone(),
          false => *e3.clone(),
        }
      },
      Decl(DConst, ref x, ref v1, ref e2) if v1.is_value() => {
        self.state.alloc_const(x.to_var()?, *v1.clone())?;
        *e2.clone()
      },
      Decl(DVar, ref x, ref v1, ref e2) if x.is_var() && v1.is_value() => {
        debug!("allocing {:?}", v1);
        self.state.alloc(x.to_var()?, *v1.clone())?;
        *e2.clone()
      },
      // lambda lift so we can use iter() in guard
      // https://github.com/rust-lang/rfcs/issues/1006
      FnCall(ref v1, ref es) if v1.is_func() && (|| es.iter().all(|v| v.is_value()))() => {
        match **v1 {
          Func(ref name, ref e1, ref xs) => {
            self.state.begin_scope();

            // alloc the params
            for (xn, en) in xs.iter().zip(es.iter()) {
              self.state.alloc(xn.to_var()?, en.clone())?;
            }

            // alloc the fn body for named functions
            match *name {
              Some(ref s) => self.state.alloc(s.to_var()?, *v1.clone())?,
              _ => {},
            };

            Scope(Box::new(*e1.clone()))
          },
          _ => return Err(RuntimeError::UnexpectedExpr("expected Func".to_string(), *v1.clone()))
        }
      },
      Scope(ref v1) if v1.is_value() => {
        self.state.end_scope();
        *v1.clone()
      },
      While(ref v1, ref e1o, _, ref e2o, ref e3) if v1.is_value() => {
        match v1.to_bool()? {
          true => While(Box::new(*e1o.clone()), e1o.clone(), e2o.clone(), e2o.clone(), e3.clone()),
          false => *e3.clone(),
        }
      },
      Print(ref v1) if v1.is_value() => {
        println!("{}", v1);
        Expr::Undefined
      },
      /**
       * Search Cases
       */
      Bop(ref op, ref v1, ref e2) if v1.is_value() => {
        Bop(
          op.clone(),
          Box::new(*v1.clone()),
          Box::new(self.step(*e2.clone())?)
        )
      },
      Bop(Assign, ref v1, ref e2) if v1.is_var() => {
        Bop(
          Assign,
          Box::new(*v1.clone()),
          Box::new(self.step(*e2.clone())?)
        )
      },
      Bop(op, e1, e2) => {
        Bop(op, Box::new(self.step(*e1)?), e2)
      },
      Uop(op, e1) => {
        Uop(op, Box::new(self.step(*e1)?))
      },
      Ternary(e1, e2, e3) => {
        Ternary(Box::new(self.step(*e1)?), e2, e3)
      },
      While(ref e1, ref e1o, ref v2, ref e2o, ref e3) if v2.is_value() => {
        While(Box::new(self.step(*e1.clone())?), e1o.clone(), v2.clone(), e2o.clone(), e3.clone())
      },
      While(e1, e1o, e2, e2o, e3) => {
        While(e1, e1o, Box::new(self.step(*e2)?), e2o, e3)
      },
      Decl(dt, addr, e1, e2) => {
        Decl(dt, Box::new(*addr.clone()), Box::new(self.step(*e1)?), e2)
      },
      FnCall(ref v1, ref args) if v1.is_func() => {
        let mut found_nonvalue = false;

        let stepped_args: Result<Vec<Expr>> = args.iter().map(|e| {
          if !found_nonvalue && !e.is_value() {
            found_nonvalue = true;
            self.step(e.clone())
          } else {
            Ok(e.clone())
          }
        }).collect();

        FnCall(v1.clone(), stepped_args?)
      },
      FnCall(e1, args) => {
        FnCall(Box::new(self.step(*e1)?), args)
      },
      Scope(e1) => {
        Scope(Box::new(self.step(*e1)?))
      },
      Print(e1) => {
        Print(Box::new(self.step(*e1)?))
      },
    };

    debug!("returning with mem {:?}" , self.state.mem);
    debug!("returning with e {:?}" , e1);
    Ok(e1)
  }

  pub fn eval(&mut self, input: &str) -> Result<Expr> {
    let mut e = parse(input)?;

    let mut num_iterations = 0;

    loop {
      if num_iterations > 1000000000 {
        return Err(RuntimeError::TooManyIterations(num_iterations))
      }

      debug!("-----------------");
      debug!("--- iterating on e {:?} ", e);
      debug!("--- iterating on m {:?} ", self.state.mem);
      num_iterations += 1;
      if e.is_value() {
        debug!("--- iterations: {}", num_iterations);
        return Ok(e.clone());
      } else {
        e = self.step(e.clone())?;
      }
    }
  }
}
<commit_msg>remove unecessary clone<commit_after>use parser::parser::{parse};
use expr::Expr;
use expr::Expr::*;
use expr::UnOp::*;
use expr::BinOp::*;
use expr::Dec::*;
use state::State;
use runtime_error::RuntimeError;
use std::result;

pub type Result<T> = result::Result<T, RuntimeError>;

pub struct Interpreter {
  pub state: State,
}

impl Interpreter {
  pub fn new() -> Interpreter {
    Interpreter {
      state: State::new(),
    }
  }

  pub fn step(&mut self, e: Expr) -> Result<Expr> {
    debug!("step(e) : {:?}", e);
    debug!("step(self.state) : {:?}", self.state.mem);

    let e1 = match e {
      Var(x) => {
        match self.state.get(x.clone()) {
          Some(e) => e,
          None => return Err(RuntimeError::VariableNotFound(x)),
        }
      },
      /**
       * Values are ineligible for step
       */
      Int(_) | Bool(_) | Func(_, _, _) | Undefined => {
        debug!("stepping on a value {:?}", e);
        return Err(RuntimeError::SteppingOnValue(e));
      },
      /**
       * Base cases
       */
      Uop(Not, ref e1) if e1.is_value() => {
        Bool(!e1.to_bool()?)
      },
      Uop(Neg, ref e1) if e1.is_value() => {
        Int(-1 * e1.to_int()?)
      },
      Bop(And, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_bool()? && e2.to_bool()?)
      },
      Bop(Or, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_bool()? || e2.to_bool()?)
      },
      Bop(Eq, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(*e1 == *e2)
      },
      Bop(Ne, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(*e1 != *e2)
      },
      Bop(Mod, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        let n1 = e1.to_int()?;
        let n2 = e2.to_int()?;

        // rust % gives the remainder, not modulus
        // let result = ((n1 % n2) + n2) % n2;
        let result = n1.checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?
          .checked_add(n2)
          .ok_or(RuntimeError::IntegerOverflow)?
          .checked_rem(n2)
          .ok_or(RuntimeError::IntegerUnderflow)?;

        Int(result)
      },
      Bop(Lt, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? < e2.to_int()?)
      },
      Bop(Gt, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? > e2.to_int()?)
      },
      Bop(Leq, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? <= e2.to_int()?)
      },
      Bop(Geq, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        Bool(e1.to_int()? >= e2.to_int()?)
      },
      Bop(Plus, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_add(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Minus, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_sub(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Times, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_mul(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerOverflow),
        }
      },
      Bop(Div, ref e1, ref e2) if e1.is_value() && e2.is_value() => {
        match e1.to_int()?.checked_div(e2.to_int()?) {
          Some(n) => Int(n),
          None => return Err(RuntimeError::IntegerUnderflow),
        }
      },
      Bop(Seq, ref v1, ref e2) if v1.is_value() => {
        *e2.clone()
      },
      Bop(Assign, ref v1, ref v2) if v1.is_var() && v2.is_value() => {
        let x = v1.to_var()?;
        self.state.assign(x, *v2.clone())?;
        debug!("done assigning {:?}", self.state.mem);
        *v2.clone()
      },
      Ternary(ref v1, ref e2, ref e3) if v1.is_value() => {
        match v1.to_bool()? {
          true => *e2.clone(),
          false => *e3.clone(),
        }
      },
      Decl(DConst, ref x, ref v1, ref e2) if v1.is_value() => {
        self.state.alloc_const(x.to_var()?, *v1.clone())?;
        *e2.clone()
      },
      Decl(DVar, ref x, ref v1, ref e2) if x.is_var() && v1.is_value() => {
        debug!("allocing {:?}", v1);
        self.state.alloc(x.to_var()?, *v1.clone())?;
        *e2.clone()
      },
      // lambda lift so we can use iter() in guard
      // https://github.com/rust-lang/rfcs/issues/1006
      FnCall(ref v1, ref es) if v1.is_func() && (|| es.iter().all(|v| v.is_value()))() => {
        match **v1 {
          Func(ref name, ref e1, ref xs) => {
            self.state.begin_scope();

            // alloc the params
            for (xn, en) in xs.iter().zip(es.iter()) {
              self.state.alloc(xn.to_var()?, en.clone())?;
            }

            // alloc the fn body for named functions
            match *name {
              Some(ref s) => self.state.alloc(s.to_var()?, *v1.clone())?,
              _ => {},
            };

            Scope(Box::new(*e1.clone()))
          },
          _ => return Err(RuntimeError::UnexpectedExpr("expected Func".to_string(), *v1.clone()))
        }
      },
      Scope(ref v1) if v1.is_value() => {
        self.state.end_scope();
        *v1.clone()
      },
      While(ref v1, ref e1o, _, ref e2o, ref e3) if v1.is_value() => {
        match v1.to_bool()? {
          true => While(Box::new(*e1o.clone()), e1o.clone(), e2o.clone(), e2o.clone(), e3.clone()),
          false => *e3.clone(),
        }
      },
      Print(ref v1) if v1.is_value() => {
        println!("{}", v1);
        Expr::Undefined
      },
      /**
       * Search Cases
       */
      Bop(ref op, ref v1, ref e2) if v1.is_value() => {
        Bop(
          op.clone(),
          Box::new(*v1.clone()),
          Box::new(self.step(*e2.clone())?)
        )
      },
      Bop(Assign, ref v1, ref e2) if v1.is_var() => {
        Bop(
          Assign,
          Box::new(*v1.clone()),
          Box::new(self.step(*e2.clone())?)
        )
      },
      Bop(op, e1, e2) => {
        Bop(op, Box::new(self.step(*e1)?), e2)
      },
      Uop(op, e1) => {
        Uop(op, Box::new(self.step(*e1)?))
      },
      Ternary(e1, e2, e3) => {
        Ternary(Box::new(self.step(*e1)?), e2, e3)
      },
      While(ref e1, ref e1o, ref v2, ref e2o, ref e3) if v2.is_value() => {
        While(Box::new(self.step(*e1.clone())?), e1o.clone(), v2.clone(), e2o.clone(), e3.clone())
      },
      While(e1, e1o, e2, e2o, e3) => {
        While(e1, e1o, Box::new(self.step(*e2)?), e2o, e3)
      },
      Decl(dt, addr, e1, e2) => {
        Decl(dt, Box::new(*addr.clone()), Box::new(self.step(*e1)?), e2)
      },
      FnCall(ref v1, ref args) if v1.is_func() => {
        let mut found_nonvalue = false;

        let stepped_args: Result<Vec<Expr>> = args.iter().map(|e| {
          if !found_nonvalue && !e.is_value() {
            found_nonvalue = true;
            self.step(e.clone())
          } else {
            Ok(e.clone())
          }
        }).collect();

        FnCall(v1.clone(), stepped_args?)
      },
      FnCall(e1, args) => {
        FnCall(Box::new(self.step(*e1)?), args)
      },
      Scope(e1) => {
        Scope(Box::new(self.step(*e1)?))
      },
      Print(e1) => {
        Print(Box::new(self.step(*e1)?))
      },
    };

    debug!("returning with mem {:?}" , self.state.mem);
    debug!("returning with e {:?}" , e1);
    Ok(e1)
  }

  pub fn eval(&mut self, input: &str) -> Result<Expr> {
    let mut e = parse(input)?;

    let mut num_iterations = 0;

    loop {
      if num_iterations > 1000000000 {
        return Err(RuntimeError::TooManyIterations(num_iterations))
      }

      debug!("-----------------");
      debug!("--- iterating on e {:?} ", e);
      debug!("--- iterating on m {:?} ", self.state.mem);
      num_iterations += 1;
      if e.is_value() {
        debug!("--- iterations: {}", num_iterations);
        return Ok(e.clone());
      } else {
        e = self.step(e.clone())?;
      }
    }
  }
}
<|endoftext|>


<commit_before>use command_handler::{CommandResult};
use std::process::{Stdio};
use launch_bin::launch_bin;
use cd::cd;
use env::env;
use env::setenv;
use env::unsetenv;
use parser::parser::Parser;
use parser::nodes::BinOp;
use parser::nodes::Command;
use parser::lexer::TokenOperator;
use parser::nodes::ASTNode;
use std::cmp::max;
use std::fs::File;

pub trait NodeVisitor {
    fn visit(&self, node: Box<ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult;
}

pub struct Interpreter {
    pub parser: Parser
}

impl NodeVisitor for Interpreter {
    fn visit(&self, node: Box<ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        if node.type_of() == "BinOp" {
            return self.visit_binop(node.downcast::<BinOp>().ok().unwrap())
        } else if node.type_of() == "Eof" {
            return CommandResult { child: None, status: 0 }
        } else {
            return self.visit_command(node.downcast::<Command>().ok().unwrap(), stdin, stdout);
        }
    }
}

impl Interpreter {
    fn set_command(&mut self, command: String) {
        self.parser.set_command(command);
    }

    fn visit_command(&self, node: Box<Command>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        let mut cmd: Vec<String> = node.value.clone().split(' ').map(|x: &str| x.to_string()).collect();

        let result = match cmd.as_str() {
            "cd"        => cd(&cmd.split(' ').map(|x: &str| x.to_string()).collect()),
            "env"       => env(),
            "setenv"    => setenv(&mut cmd.split(' ').map(|x: &str| x.to_string()).collect()),
            "unsetenv"  => unsetenv(&mut cmd.split(' ').map(|x: &str| x.to_string()).collect()),
            _           => launch_bin(&mut cmd.split(' ').map(|x: &str| x.to_string()).collect())
        };
        return result
    }

    fn visit_binop(&self, node: Box<BinOp>) -> CommandResult {
        let n = *node;
        match n.token.kind {
            TokenOperator::Semicolon => {
                self.visit(n.left, None, None);
                return self.visit(n.right, None, None);
            }
            TokenOperator::And => {
                let cr1 = self.visit(n.left, None, None);
                if cr1.status == 0 {
                    let cr2 = self.visit(n.right, None, None);
                    CommandResult { child: None, status: max(cr1.status, cr2.status) }
                } else {
                    CommandResult { child: None, status: cr1.status }
                }
            }
            TokenOperator::Or => {
                let cr1 = self.visit(n.left, None, None);
                if cr1.status != 0 {
                    let cr2 = self.visit(n.right, None, None);
                    CommandResult { child: None, status: max(cr1.status, cr2.status) }
                } else {
                    CommandResult { child: None, status: cr1.status }
                }
            } TokenOperator::SingleRight => {
                let path = n.right.downcast::<Command>().ok().unwrap().value;
                match  File::create(&path) {
                    Ok(f) => {
                        return self.visit(n.left, None, Some(f.into()));
                    },
                    Err(_) => {
                        println!("RustSH : file not found : {}", path);
                    },
                };
                CommandResult { child: None, status: 1 }
            } TokenOperator::SingleLeft => {
                let path = n.right.downcast::<Command>().ok().unwrap().value;

                match  File::open(&path) {
                    Ok(f) => {
                        return self.visit(n.left, Some(f.into()), None);
                    },
                    Err(_) => {
                        println!("RustSH: {} : file not found", path);
                    },
                };
                CommandResult { child: None, status: 1 }
            }
            _ => {unimplemented!()}
        }
    }

    pub fn interpret(&mut self, command: String) {
        self.set_command(command);
        let node = self.parser.expr();
        self.visit(node, None, None);
    }
}
<commit_msg>Changed the handling of the command vector<commit_after>use command_handler::{CommandResult};
use std::process::{Stdio};
use launch_bin::launch_bin;
use cd::cd;
use env::env;
use env::setenv;
use env::unsetenv;
use parser::parser::Parser;
use parser::nodes::BinOp;
use parser::nodes::Command;
use parser::lexer::TokenOperator;
use parser::nodes::ASTNode;
use std::cmp::max;
use std::fs::File;

pub trait NodeVisitor {
    fn visit(&self, node: Box<ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult;
}

pub struct Interpreter {
    pub parser: Parser
}

impl NodeVisitor for Interpreter {
    fn visit(&self, node: Box<ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        if node.type_of() == "BinOp" {
            return self.visit_binop(node.downcast::<BinOp>().ok().unwrap())
        } else if node.type_of() == "Eof" {
            return CommandResult { child: None, status: 0 }
        } else {
            return self.visit_command(node.downcast::<Command>().ok().unwrap(), stdin, stdout);
        }
    }
}

impl Interpreter {
    fn set_command(&mut self, command: String) {
        self.parser.set_command(command);
    }

    fn visit_command(&self, node: Box<Command>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        let mut cmd: Vec<String> = node.value.clone().split(' ').map(|x: &str| x.to_string()).collect();

        let result = match cmd[0].as_str() {
            "cd"        => cd(&mut cmd),
            "env"       => env(),
            "setenv"    => setenv(&mut cmd),
            "unsetenv"  => unsetenv(&mut cmd),
            _           => launch_bin(&mut cmd, stdin, stdout)
        };
        return result
    }

    fn visit_binop(&self, node: Box<BinOp>) -> CommandResult {
        let n = *node;
        match n.token.kind {
            TokenOperator::Semicolon => {
                self.visit(n.left, None, None);
                return self.visit(n.right, None, None);
            }
            TokenOperator::And => {
                let cr1 = self.visit(n.left, None, None);
                if cr1.status == 0 {
                    let cr2 = self.visit(n.right, None, None);
                    CommandResult { child: None, status: max(cr1.status, cr2.status) }
                } else {
                    CommandResult { child: None, status: cr1.status }
                }
            }
            TokenOperator::Or => {
                let cr1 = self.visit(n.left, None, None);
                if cr1.status != 0 {
                    let cr2 = self.visit(n.right, None, None);
                    CommandResult { child: None, status: max(cr1.status, cr2.status) }
                } else {
                    CommandResult { child: None, status: cr1.status }
                }
            } TokenOperator::SingleRight => {
                let path = n.right.downcast::<Command>().ok().unwrap().value;
                match  File::create(&path) {
                    Ok(f) => {
                        return self.visit(n.left, None, Some(f.into()));
                    },
                    Err(_) => {
                        println!("RustSH : file not found : {}", path);
                    },
                };
                CommandResult { child: None, status: 1 }
            } TokenOperator::SingleLeft => {
                let path = n.right.downcast::<Command>().ok().unwrap().value;

                match  File::open(&path) {
                    Ok(f) => {
                        return self.visit(n.left, Some(f.into()), None);
                    },
                    Err(_) => {
                        println!("RustSH: {} : file not found", path);
                    },
                };
                CommandResult { child: None, status: 1 }
            }
            _ => {unimplemented!()}
        }
    }

    pub fn interpret(&mut self, command: String) {
        self.set_command(command);
        let node = self.parser.expr();
        self.visit(node, None, None);
    }
}
<|endoftext|>


<commit_before>//! Template declaration and instantiation related things.
//!
//! The nomenclature surrounding templates is often confusing, so here are a few
//! brief definitions:
//!
//! * "Template definition": a class/struct/alias/function definition that takes
//! generic template parameters. For example:
//!
//! ```c++
//! template<typename T>
//! class List<T> {
//!     // ...
//! };
//! ```
//!
//! * "Template instantiation": an instantiation is a use of a template with
//! concrete template arguments. For example, `List<int>`.
//!
//! * "Template specialization": an alternative template definition providing a
//! custom definition for instantiations with the matching template
//! arguments. This C++ feature is unsupported by bindgen. For example:
//!
//! ```c++
//! template<>
//! class List<int> {
//!     // Special layout for int lists...
//! };
//! ```

use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;

/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
    /// Any extra information the implementor might need to make this decision.
    type Extra;

    /// Convert this thing to the item id of a named template type parameter.
    fn as_named(&self,
                ctx: &BindgenContext,
                extra: &Self::Extra)
                -> Option<ItemId>;

    /// Is this a named template type parameter?
    fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
        self.as_named(ctx, extra).is_some()
    }
}

/// A concrete instantiation of a generic template.
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
    /// The template definition which this is instantiating.
    definition: ItemId,
    /// The concrete template arguments, which will be substituted in the
    /// definition for the generic template parameters.
    args: Vec<ItemId>,
}

impl TemplateInstantiation {
    /// Construct a new template instantiation from the given parts.
    pub fn new<I>(template_definition: ItemId,
                  template_args: I)
                  -> TemplateInstantiation
        where I: IntoIterator<Item = ItemId>,
    {
        TemplateInstantiation {
            definition: template_definition,
            args: template_args.into_iter().collect(),
        }
    }

    /// Get the template definition for this instantiation.
    pub fn template_definition(&self) -> ItemId {
        self.definition
    }

    /// Get the concrete template arguments used in this instantiation.
    pub fn template_arguments(&self) -> &[ItemId] {
        &self.args[..]
    }

    /// Parse a `TemplateInstantiation` from a clang `Type`.
    pub fn from_ty(ty: &clang::Type,
                   ctx: &mut BindgenContext)
                   -> Option<TemplateInstantiation> {
        use clang_sys::*;

        let template_args = ty.template_args()
            .map_or(vec![], |args| {
                args.filter(|t| t.kind() != CXType_Invalid)
                    .map(|t| {
                        Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                    })
                    .collect()
            });

        if ty.declaration().is_builtin() {
            return None;
        }

        let definition = ty.declaration()
            .specialized()
            .or_else(|| {
                let mut template_ref = None;
                ty.declaration().visit(|child| {
                    if child.kind() == CXCursor_TemplateRef {
                        template_ref = Some(child);
                        return CXVisit_Break;
                    }

                    // Instantiations of template aliases might have the
                    // TemplateRef to the template alias definition arbitrarily
                    // deep, so we need to recurse here and not only visit
                    // direct children.
                    CXChildVisit_Recurse
                });

                template_ref.and_then(|cur| cur.referenced())
            })
            .expect("Should have found the template definition one way or another");

        let template_definition =
            Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);

        Some(TemplateInstantiation::new(template_definition, template_args))
    }

    /// Does this instantiation have a vtable?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_vtable(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_vtable(ctx))
    }

    /// Does this instantiation have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_destructor(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
    }
}

impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy_in_array(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
    }
}

impl CanDeriveDebug for TemplateInstantiation {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
        ctx.resolve_type(self.definition)
            .as_comp()
            .and_then(|c| {
                // For non-type template parameters, we generate an opaque
                // blob, and in this case the instantiation has a better
                // idea of the layout than the definition does.
                if c.has_non_type_template_params() {
                    let opaque = layout.unwrap_or(Layout::zero()).opaque();
                    Some(opaque.can_derive_debug(ctx, ()))
                } else {
                    None
                }
            })
            .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
    }
}

impl Trace for TemplateInstantiation {
    type Extra = ();

    fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
        for &item in self.template_arguments() {
            tracer.visit_kind(item, EdgeKind::TemplateArgument);
        }
    }
}
<commit_msg>Auto merge of #614 - fitzgen:not-just-builtin-templates, r=emilio<commit_after>//! Template declaration and instantiation related things.
//!
//! The nomenclature surrounding templates is often confusing, so here are a few
//! brief definitions:
//!
//! * "Template definition": a class/struct/alias/function definition that takes
//! generic template parameters. For example:
//!
//! ```c++
//! template<typename T>
//! class List<T> {
//!     // ...
//! };
//! ```
//!
//! * "Template instantiation": an instantiation is a use of a template with
//! concrete template arguments. For example, `List<int>`.
//!
//! * "Template specialization": an alternative template definition providing a
//! custom definition for instantiations with the matching template
//! arguments. This C++ feature is unsupported by bindgen. For example:
//!
//! ```c++
//! template<>
//! class List<int> {
//!     // Special layout for int lists...
//! };
//! ```

use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;

/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
    /// Any extra information the implementor might need to make this decision.
    type Extra;

    /// Convert this thing to the item id of a named template type parameter.
    fn as_named(&self,
                ctx: &BindgenContext,
                extra: &Self::Extra)
                -> Option<ItemId>;

    /// Is this a named template type parameter?
    fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
        self.as_named(ctx, extra).is_some()
    }
}

/// A concrete instantiation of a generic template.
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
    /// The template definition which this is instantiating.
    definition: ItemId,
    /// The concrete template arguments, which will be substituted in the
    /// definition for the generic template parameters.
    args: Vec<ItemId>,
}

impl TemplateInstantiation {
    /// Construct a new template instantiation from the given parts.
    pub fn new<I>(template_definition: ItemId,
                  template_args: I)
                  -> TemplateInstantiation
        where I: IntoIterator<Item = ItemId>,
    {
        TemplateInstantiation {
            definition: template_definition,
            args: template_args.into_iter().collect(),
        }
    }

    /// Get the template definition for this instantiation.
    pub fn template_definition(&self) -> ItemId {
        self.definition
    }

    /// Get the concrete template arguments used in this instantiation.
    pub fn template_arguments(&self) -> &[ItemId] {
        &self.args[..]
    }

    /// Parse a `TemplateInstantiation` from a clang `Type`.
    pub fn from_ty(ty: &clang::Type,
                   ctx: &mut BindgenContext)
                   -> Option<TemplateInstantiation> {
        use clang_sys::*;

        let template_args = ty.template_args()
            .map_or(vec![], |args| {
                args.filter(|t| t.kind() != CXType_Invalid)
                    .map(|t| {
                        Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                    })
                    .collect()
            });

        let definition = ty.declaration()
            .specialized()
            .or_else(|| {
                let mut template_ref = None;
                ty.declaration().visit(|child| {
                    if child.kind() == CXCursor_TemplateRef {
                        template_ref = Some(child);
                        return CXVisit_Break;
                    }

                    // Instantiations of template aliases might have the
                    // TemplateRef to the template alias definition arbitrarily
                    // deep, so we need to recurse here and not only visit
                    // direct children.
                    CXChildVisit_Recurse
                });

                template_ref.and_then(|cur| cur.referenced())
            });

        let definition = match definition {
            Some(def) => def,
            None => {
                if !ty.declaration().is_builtin() {
                    warn!("Could not find template definition for template \
                           instantiation");
                }
                return None
            }
        };

        let template_definition =
            Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);

        Some(TemplateInstantiation::new(template_definition, template_args))
    }

    /// Does this instantiation have a vtable?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_vtable(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_vtable(ctx))
    }

    /// Does this instantiation have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_destructor(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
    }
}

impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy_in_array(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
    }
}

impl CanDeriveDebug for TemplateInstantiation {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
        ctx.resolve_type(self.definition)
            .as_comp()
            .and_then(|c| {
                // For non-type template parameters, we generate an opaque
                // blob, and in this case the instantiation has a better
                // idea of the layout than the definition does.
                if c.has_non_type_template_params() {
                    let opaque = layout.unwrap_or(Layout::zero()).opaque();
                    Some(opaque.can_derive_debug(ctx, ()))
                } else {
                    None
                }
            })
            .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
    }
}

impl Trace for TemplateInstantiation {
    type Extra = ();

    fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
        for &item in self.template_arguments() {
            tracer.visit_kind(item, EdgeKind::TemplateArgument);
        }
    }
}
<|endoftext|>