<commit_before>#![feature(deque_extras)]
#![feature(box_syntax)]
#![feature(plugin)]
#![plugin(peg_syntax_ext)]

use std::collections::HashMap;
use std::fs::File;
use std::io::{stdout, Read, Write};
use std::env;
use std::process;

use self::to_num::ToNum;
use self::directory_stack::DirectoryStack;
use self::input_editor::readln;
use self::peg::parse;
use self::variables::Variables;
use self::history::History;

pub mod builtin;
pub mod directory_stack;
pub mod to_num;
pub mod input_editor;
pub mod peg;
pub mod variables;
pub mod history;

pub struct Mode {
    value: bool,
}

/// This struct will contain all of the data structures related to this
/// instance of the shell.
pub struct Shell {
    variables: Variables,
    modes: Vec<Mode>,
    directory_stack: DirectoryStack,
    history: History,
}

impl Shell {
    /// Panics if DirectoryStack construction fails
    pub fn new() -> Self {
        Shell {
            variables: Variables::new(),
            modes: vec![],
            directory_stack: DirectoryStack::new().expect(""),
            history: History::new(),
        }
    }

    pub fn print_prompt(&self) {
        let prompt_prefix = self.modes.iter().rev().fold(String::new(), |acc, mode| {
            acc +
            if mode.value {
                "+ "
            } else {
                "- "
            }
        });
        print!("{}", prompt_prefix);

        let cwd = env::current_dir().ok().map_or("?".to_string(),
                                                 |ref p| p.to_str().unwrap_or("?").to_string());

        print!("ion:{}# ", cwd);
        if let Err(message) = stdout().flush() {
            println!("{}: failed to flush prompt to stdout", message);
        }
    }

    fn on_command(&mut self, command_string: &str, commands: &HashMap<&str, Command>) {
        self.history.add(command_string.to_string());

        let mut jobs = parse(command_string);
        //self.variables.expand_variables(&mut jobs);

        // Execute commands
        for job in jobs.iter() {
            if job.command == "if" {
                let mut value = false;

                if let Some(left) = job.args.get(0) {
                    if let Some(cmp) = job.args.get(1) {
                        if let Some(right) = job.args.get(2) {
                            if *cmp == "==" {
                                value = *left == *right;
                            } else if *cmp == "!=" {
                                value = *left != *right;
                            } else if *cmp == ">" {
                                value = left.to_num_signed() > right.to_num_signed();
                            } else if *cmp == ">=" {
                                value = left.to_num_signed() >= right.to_num_signed();
                            } else if *cmp == "<" {
                                value = left.to_num_signed() < right.to_num_signed();
                            } else if *cmp == "<=" {
                                value = left.to_num_signed() <= right.to_num_signed();
                            } else {
                                println!("Unknown comparison: {}", cmp);
                            }
                        } else {
                            println!("No right hand side");
                        }
                    } else {
                        println!("No comparison operator");
                    }
                } else {
                    println!("No left hand side");
                }

                self.modes.insert(0, Mode { value: value });
                continue;
            }

            if job.command == "else" {
                if let Some(mode) = self.modes.get_mut(0) {
                    mode.value = !mode.value;
                } else {
                    println!("Syntax error: else found with no previous if");
                }
                continue;
            }

            if job.command == "fi" {
                if !self.modes.is_empty() {
                    self.modes.remove(0);
                } else {
                    println!("Syntax error: fi found with no previous if");
                }
                continue;
            }

            let skipped = self.modes.iter().any(|mode| !mode.value);
            if skipped {
                continue;
            }

            // Commands
            let mut args = job.args.clone();
            args.insert(0, job.command.clone());
            if let Some(command) = commands.get(job.command) {
                (*command.main)(args.as_slice(), self);
            } else {
                self.run_external_commmand(args);
            }
        }
    }

    fn run_external_commmand<'a>(&'a mut self, args: Vec<&'a str>) {
        if let Some(path) = args.get(0) {
            let mut command = process::Command::new(path);
            for i in 1..args.len() {
                if let Some(arg) = args.get(i) {
                    command.arg(arg);
                }
            }
            match command.spawn() {
                Ok(mut child) => {
                    match child.wait() {
                        Ok(status) => {
                            if let Some(code) = status.code() {
                                self.variables.set_var("?", &code.to_string());
                            } else {
                                println!("{}: No child exit code", path);
                            }
                        }
                        Err(err) => println!("{}: Failed to wait: {}", path, err),
                    }
                }
                Err(err) => println!("{}: Failed to execute: {}", path, err),
            }
        }
    }
}

/// Structure which represents a Terminal's command.
/// This command structure contains a name, and the code which run the
/// functionnality associated to this one, with zero, one or several argument(s).
/// # Example
/// ```
/// let my_command = Command {
///     name: "my_command",
///     help: "Describe what my_command does followed by a newline showing usage",
///     main: box|args: &[String], &mut Shell| {
///         println!("Say 'hello' to my command! :-D");
///     }
/// }
/// ```
pub struct Command {
    pub name: &'static str,
    pub help: &'static str,
    pub main: Box<Fn(&[&str], &mut Shell)>,
}

impl Command {
    /// Return the map from command names to commands
    pub fn map() -> HashMap<&'static str, Self> {
        let mut commands: HashMap<&str, Self> = HashMap::new();

        commands.insert("cd",
                        Command {
                            name: "cd",
                            help: "To change the current directory\n    cd <your_destination>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.cd(args);
                            },
                        });

        commands.insert("dirs",
                        Command {
                            name: "dirs",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.dirs(args);
                            },
                        });

        commands.insert("exit",
                        Command {
                            name: "exit",
                            help: "To exit the curent session",
                            main: box |_: &[&str], _: &mut Shell| {
                                process::exit(0);
                                // TODO exit with argument 1 as parameter
                            },
                        });

        commands.insert("let",
                        Command {
                            name: "let",
                            help: "View, set or unset variables",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.variables.let_(args);
                            },
                        });

        commands.insert("read",
                        Command {
                            name: "read",
                            help: "To read some variables\n    read <my_variable>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.variables.read(args);
                            },
                        });

        commands.insert("run",
                        Command {
                            name: "run",
                            help: "Run a script\n    run <script>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                builtin::run(args, shell);
                            },
                        });

        commands.insert("pushd",
                        Command {
                            name: "pushd",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.pushd(args);
                            },
                        });

        commands.insert("popd",
                        Command {
                            name: "popd",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.popd(args);
                            },
                        });

        commands.insert("history",
                        Command {
                            name: "history",
                            help: "Display all commands previously executed",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.history.history(args.iter().map(|s|*s));
                            },
                        });

        let command_helper: HashMap<&'static str, &'static str> = commands.iter()
                                                              .map(|(k, v)| {
                                                                  (*k, v.help)
                                                              })
                                                              .collect();

        commands.insert("help",
                        Command {
                            name: "help",
                            help: "Display a little helper for a given command\n    help ls",
                            main: box move |args: &[&str], _: &mut Shell| {
                                if let Some(command) = args.get(1) {
                                    if command_helper.contains_key(command) {
                                        match command_helper.get(command) {
                                            Some(help) => println!("{}", help),
                                            None => {
                                                println!("Command helper not found [run 'help']...")
                                            }
                                        }
                                    } else {
                                        println!("Command helper not found [run 'help']...");
                                    }
                                } else {
                                    for (command, _help) in command_helper.iter() {
                                        println!("{}", command);
                                    }
                                }
                            },
                        });

        commands
    }
}

fn main() {
    let commands = Command::map();
    let mut shell = Shell::new();

    for arg in env::args().skip(1) {
        let mut command_list = String::new();
        if let Ok(mut file) = File::open(&arg) {
            if let Err(message) = file.read_to_string(&mut command_list) {
                println!("{}: Failed to read {}", message, arg);
            }
        }
        shell.on_command(&command_list, &commands);
        return;
    }

    loop {
        shell.print_prompt();

        if let Some(command) = readln() {
            let command = command.trim();
            if !command.is_empty() {
                shell.on_command(command, &commands);
            }
        } else {
            break;
        }
    }
}
<commit_msg>Remove now useless clone of all args<commit_after>#![feature(deque_extras)]
#![feature(box_syntax)]
#![feature(plugin)]
#![plugin(peg_syntax_ext)]

use std::collections::HashMap;
use std::fs::File;
use std::io::{stdout, Read, Write};
use std::env;
use std::process;

use self::to_num::ToNum;
use self::directory_stack::DirectoryStack;
use self::input_editor::readln;
use self::peg::parse;
use self::variables::Variables;
use self::history::History;

pub mod builtin;
pub mod directory_stack;
pub mod to_num;
pub mod input_editor;
pub mod peg;
pub mod variables;
pub mod history;

pub struct Mode {
    value: bool,
}

/// This struct will contain all of the data structures related to this
/// instance of the shell.
pub struct Shell {
    variables: Variables,
    modes: Vec<Mode>,
    directory_stack: DirectoryStack,
    history: History,
}

impl Shell {
    /// Panics if DirectoryStack construction fails
    pub fn new() -> Self {
        Shell {
            variables: Variables::new(),
            modes: vec![],
            directory_stack: DirectoryStack::new().expect(""),
            history: History::new(),
        }
    }

    pub fn print_prompt(&self) {
        let prompt_prefix = self.modes.iter().rev().fold(String::new(), |acc, mode| {
            acc +
            if mode.value {
                "+ "
            } else {
                "- "
            }
        });
        print!("{}", prompt_prefix);

        let cwd = env::current_dir().ok().map_or("?".to_string(),
                                                 |ref p| p.to_str().unwrap_or("?").to_string());

        print!("ion:{}# ", cwd);
        if let Err(message) = stdout().flush() {
            println!("{}: failed to flush prompt to stdout", message);
        }
    }

    fn on_command(&mut self, command_string: &str, commands: &HashMap<&str, Command>) {
        self.history.add(command_string.to_string());

        let mut jobs = parse(command_string);
        //self.variables.expand_variables(&mut jobs);

        // Execute commands
        for job in jobs.iter() {
            if job.command == "if" {
                let mut value = false;

                if let Some(left) = job.args.get(0) {
                    if let Some(cmp) = job.args.get(1) {
                        if let Some(right) = job.args.get(2) {
                            if *cmp == "==" {
                                value = *left == *right;
                            } else if *cmp == "!=" {
                                value = *left != *right;
                            } else if *cmp == ">" {
                                value = left.to_num_signed() > right.to_num_signed();
                            } else if *cmp == ">=" {
                                value = left.to_num_signed() >= right.to_num_signed();
                            } else if *cmp == "<" {
                                value = left.to_num_signed() < right.to_num_signed();
                            } else if *cmp == "<=" {
                                value = left.to_num_signed() <= right.to_num_signed();
                            } else {
                                println!("Unknown comparison: {}", cmp);
                            }
                        } else {
                            println!("No right hand side");
                        }
                    } else {
                        println!("No comparison operator");
                    }
                } else {
                    println!("No left hand side");
                }

                self.modes.insert(0, Mode { value: value });
                continue;
            }

            if job.command == "else" {
                if let Some(mode) = self.modes.get_mut(0) {
                    mode.value = !mode.value;
                } else {
                    println!("Syntax error: else found with no previous if");
                }
                continue;
            }

            if job.command == "fi" {
                if !self.modes.is_empty() {
                    self.modes.remove(0);
                } else {
                    println!("Syntax error: fi found with no previous if");
                }
                continue;
            }

            let skipped = self.modes.iter().any(|mode| !mode.value);
            if skipped {
                continue;
            }

            // Commands
            if let Some(command) = commands.get(job.command) {
                (*command.main)(job.args.as_slice(), self);
            } else {
                self.run_external_commmand(&job.args);
            }
        }
    }

    fn run_external_commmand<'a>(&'a mut self, args: &Vec<&'a str>) {
        if let Some(path) = args.get(0) {
            let mut command = process::Command::new(path);
            for i in 1..args.len() {
                if let Some(arg) = args.get(i) {
                    command.arg(arg);
                }
            }
            match command.spawn() {
                Ok(mut child) => {
                    match child.wait() {
                        Ok(status) => {
                            if let Some(code) = status.code() {
                                self.variables.set_var("?", &code.to_string());
                            } else {
                                println!("{}: No child exit code", path);
                            }
                        }
                        Err(err) => println!("{}: Failed to wait: {}", path, err),
                    }
                }
                Err(err) => println!("{}: Failed to execute: {}", path, err),
            }
        }
    }
}

/// Structure which represents a Terminal's command.
/// This command structure contains a name, and the code which run the
/// functionnality associated to this one, with zero, one or several argument(s).
/// # Example
/// ```
/// let my_command = Command {
///     name: "my_command",
///     help: "Describe what my_command does followed by a newline showing usage",
///     main: box|args: &[String], &mut Shell| {
///         println!("Say 'hello' to my command! :-D");
///     }
/// }
/// ```
pub struct Command {
    pub name: &'static str,
    pub help: &'static str,
    pub main: Box<Fn(&[&str], &mut Shell)>,
}

impl Command {
    /// Return the map from command names to commands
    pub fn map() -> HashMap<&'static str, Self> {
        let mut commands: HashMap<&str, Self> = HashMap::new();

        commands.insert("cd",
                        Command {
                            name: "cd",
                            help: "To change the current directory\n    cd <your_destination>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.cd(args);
                            },
                        });

        commands.insert("dirs",
                        Command {
                            name: "dirs",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.dirs(args);
                            },
                        });

        commands.insert("exit",
                        Command {
                            name: "exit",
                            help: "To exit the curent session",
                            main: box |_: &[&str], _: &mut Shell| {
                                process::exit(0);
                                // TODO exit with argument 1 as parameter
                            },
                        });

        commands.insert("let",
                        Command {
                            name: "let",
                            help: "View, set or unset variables",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.variables.let_(args);
                            },
                        });

        commands.insert("read",
                        Command {
                            name: "read",
                            help: "To read some variables\n    read <my_variable>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.variables.read(args);
                            },
                        });

        commands.insert("run",
                        Command {
                            name: "run",
                            help: "Run a script\n    run <script>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                builtin::run(args, shell);
                            },
                        });

        commands.insert("pushd",
                        Command {
                            name: "pushd",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.pushd(args);
                            },
                        });

        commands.insert("popd",
                        Command {
                            name: "popd",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.directory_stack.popd(args);
                            },
                        });

        commands.insert("history",
                        Command {
                            name: "history",
                            help: "Display all commands previously executed",
                            main: box |args: &[&str], shell: &mut Shell| {
                                shell.history.history(args.iter().map(|s|*s));
                            },
                        });

        let command_helper: HashMap<&'static str, &'static str> = commands.iter()
                                                              .map(|(k, v)| {
                                                                  (*k, v.help)
                                                              })
                                                              .collect();

        commands.insert("help",
                        Command {
                            name: "help",
                            help: "Display a little helper for a given command\n    help ls",
                            main: box move |args: &[&str], _: &mut Shell| {
                                if let Some(command) = args.get(1) {
                                    if command_helper.contains_key(command) {
                                        match command_helper.get(command) {
                                            Some(help) => println!("{}", help),
                                            None => {
                                                println!("Command helper not found [run 'help']...")
                                            }
                                        }
                                    } else {
                                        println!("Command helper not found [run 'help']...");
                                    }
                                } else {
                                    for (command, _help) in command_helper.iter() {
                                        println!("{}", command);
                                    }
                                }
                            },
                        });

        commands
    }
}

fn main() {
    let commands = Command::map();
    let mut shell = Shell::new();

    for arg in env::args().skip(1) {
        let mut command_list = String::new();
        if let Ok(mut file) = File::open(&arg) {
            if let Err(message) = file.read_to_string(&mut command_list) {
                println!("{}: Failed to read {}", message, arg);
            }
        }
        shell.on_command(&command_list, &commands);
        return;
    }

    loop {
        shell.print_prompt();

        if let Some(command) = readln() {
            let command = command.trim();
            if !command.is_empty() {
                shell.on_command(command, &commands);
            }
        } else {
            break;
        }
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;

use std::fs::OpenOptions;
use std::io::Read;
use std::io::SeekFrom;
use std::io::Seek;
use std::thread;
use std::fs::File;
use std::io::Write;
use hyper::Url as DownloadUrl;
use hyper::header::{Connection, AcceptRanges};
use hyper::header::{Headers, Range};
use hyper::Client;

#[derive(Debug)]
struct Downloader {
    url: Url,
    start: u64,
    end: u64,
    file_name: String,
    cursor:u64
}

impl Downloader {
    fn new(url: &str, start: u64, end: u64, file_name: &str,cursor:u64) -> Self {
        Downloader {
            url: url.to_owned(),
            start: start,
            end: end,
            file_name: file_name.to_owned(),
            cursor:cursor
        }
    }
    fn download(&self) {
        let mut headers = Headers::new();
        headers.set(Range::bytes(0, 100));
        let client = Client::new();
        let mut res = client.get(&self.url)
                            .header(Range::bytes(self.start, self.end))
                            .header(Connection::keep_alive())
                            .send()
                            .unwrap();
        let mut body: Vec<u8> = Vec::new();
        res.read_to_end(&mut body).unwrap();
        let mut file = DownloadManager::request_file(&self.file_name[..]);
        file.seek(SeekFrom::Start(self.cursor));
        file.write_all(body.as_slice());
    }
}

type Url = String;

enum State {
    Initial,
    Ready,
    Downloading,
    Completed,
    Paused,
    Stopped,
}

struct DownloadManager {
    task_queue: Vec<Downloader>,
    url: Url,
    max_connection: usize,
    file: Option<File>,
    state: State,
    block_size: usize,
    resume: bool,
}

impl DownloadManager {
    fn new() -> Self {
        DownloadManager {
            task_queue: vec![],
            url: "".to_owned(),
            max_connection: 0,
            file: None,
            state: State::Initial,
            block_size: 1024,
            resume: false,
        }
    }
    fn add_url(&mut self, url: &str) -> &mut DownloadManager {
        self.url = url.to_owned();
        self
    }
    fn max_connection(&mut self, max_con: usize) -> &mut DownloadManager {
        self.max_connection = max_con;
        self
    }
    fn file(&mut self, file_path: &str) -> &mut DownloadManager {
        self.file = Some(DownloadManager::request_file(file_path));
        self
    }
    fn block_size(&mut self, block_size: usize) -> &mut DownloadManager {
        self.block_size = block_size;
        self
    }
    fn finish(&mut self) {
        self.state = State::Ready;
    }
    fn start(&mut self) {
        let mut start_range = 0;
        let mut end_range = self.block_size as u64;
        for i in 0..self.max_connection {
            println!("Start Range {:?}", start_range);
            println!("End Range {:?}", end_range);
            println!("Downloading part {} of {}", i, self.max_connection);
            self.task_queue
                .push(Downloader::new(&self.url, start_range, end_range, "./readme.txt",start_range));

            self.task_queue[i].download();
            start_range = end_range + 1;
            end_range = (start_range - 1) * 2;
        }
    }
    fn request_file(path: &str) -> File {
        let file = OpenOptions::new()
                       .read(true)
                       .write(true)
                       .create(true)
                       .open(path);
        if let Ok(file) = file {
            file
        } else {
            panic!("File open error");
        }
    }
    fn check_resume(&self) -> bool {
        // TODO Add HEAD request to get Accept-Range Header
        false
    }
}

fn main() {
    let mut manager = DownloadManager::new();
    manager.add_url("https://wordpress.org/plugins/about/readme.txt")
           .max_connection(8)
           .file("readme.txt")
           .finish();
    let _download_thread = thread::spawn(move || {
                               manager.start();
                           })
                               .join();
}
<commit_msg>adding resume check and content length check<commit_after>extern crate hyper;
extern crate url;

use std::fs::OpenOptions;
use std::io::Read;
use std::io::SeekFrom;
use std::io::Seek;
use std::thread;
use std::fs::File;
use std::io::Write;
use hyper::Url as DownloadUrl;
use hyper::header::{Connection, AcceptRanges};
use hyper::header::{ByteRangeSpec, Range, ContentLength};
use hyper::Client;

#[derive(Debug)]
struct Downloader {
    id: usize,
    url: Url,
    start: u64,
    end: u64,
    file_name: String,
    cursor: u64,
}

impl Downloader {
    fn new(id: usize, url: &str, start: u64, end: u64, file_name: &str, cursor: u64) -> Self {
        Downloader {
            id: id,
            url: url.to_owned(),
            start: start,
            end: end,
            file_name: file_name.to_owned(),
            cursor: cursor,
        }
    }
    fn download(&self) {
        let client = Client::new();
        let mut res = client.get(&self.url)
                            .header(if self.end == 0 {
                                Range::Bytes(vec![ByteRangeSpec::Last(self.end)])
                            } else {
                                Range::bytes(self.start, self.end)
                            })
                            .header(Connection::keep_alive())
                            .send()
                            .unwrap();
        let mut body: Vec<u8> = Vec::new();
        res.read_to_end(&mut body).unwrap();
        // Id incremented file parts
        let mut file = DownloadManager::request_file(&format!("{}{}", self.file_name, self.id)[..]);
        file.seek(SeekFrom::Start(self.cursor));
        file.write_all(body.as_slice());
    }
}

type Url = String;

enum State {
    Initial,
    Ready,
    Downloading,
    Completed,
    Paused,
    Stopped,
}

struct DownloadManager {
    task_queue: Vec<Downloader>,
    url: Url,
    max_connection: usize,
    file: Option<File>,
    state: State,
    block_size: usize,
    resume: bool,
}

impl DownloadManager {
    fn new() -> Self {
        DownloadManager {
            task_queue: vec![],
            url: "".to_owned(),
            max_connection: 0,
            file: None,
            state: State::Initial,
            block_size: 1024,
            resume: false,
        }
    }
    fn add_url(&mut self, url: &str) -> &mut DownloadManager {
        self.url = url.to_owned();
        self
    }
    fn max_connection(&mut self, max_con: usize) -> &mut DownloadManager {
        self.max_connection = max_con;
        self
    }
    fn file(&mut self, file_path: &str) -> &mut DownloadManager {
        self.file = Some(DownloadManager::request_file(file_path));
        self
    }
    fn block_size(&mut self, block_size: usize) -> &mut DownloadManager {
        self.block_size = block_size;
        self
    }
    fn finish(&mut self) {
        self.state = State::Ready;
    }
    fn start(&mut self) {
        let mut content_length: u64 = 0;
        match self.check_resume() {
            (true, len) => {
                let ContentLength(length) = len;
                content_length = length;
            }
            (false, _) => println!("Download does not support resume"),
        }
        let mut start_range: u64 = 0;
        let mut end_range: u64 = self.block_size as u64;
        for i in 0..self.max_connection {
            if end_range >= content_length {
                Downloader::new(99,
                                &self.url,
                                content_length,
                                0,
                                "./readme.txt",
                                content_length)
                    .download();
            } else {
                println!("Downloading part {} of {}", i, self.max_connection);
                self.task_queue
                    .push(Downloader::new(i,
                                          &self.url,
                                          start_range,
                                          end_range,
                                          "./readme.txt",
                                          start_range));
                self.task_queue[i].download();
                start_range = end_range + 1;
                end_range = (start_range - 1) * 2;
            }
        }
        // self.join_them(self.task_queue);
    }

    fn check_resume(&self) -> (bool, ContentLength) {
        let client = Client::new();
        let head_req = client.head(DownloadUrl::parse(&self.url).unwrap());
        match head_req.send() {
            Ok(res) => {
                (res.headers.has::<AcceptRanges>(),
                 *res.headers.get::<ContentLength>().unwrap())
            }
            Err(_) => (false, ContentLength(0)),
        }
    }

    //    fn join_them(&self,task_queue:Vec<Downloader>) {
    // let file = self.file_name;
    // for i in task_queue {
    // i.file_name
    // }
    // }

    fn request_file(path: &str) -> File {
        let file = OpenOptions::new()
                       .read(true)
                       .write(true)
                       .create(true)
                       .open(path);
        if let Ok(file) = file {
            file
        } else {
            panic!("File open error");
        }
    }
}

fn main() {
    let mut manager = DownloadManager::new();
    manager.add_url("https://wordpress.org/plugins/about/readme.txt")
           .max_connection(4)
           .file("readme.txt")
           .finish();
    let _download_thread = thread::spawn(move || {
                               manager.start();
                           })
                               .join();
}
<|endoftext|>


<commit_before>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    Circle { radius : i32, x : i32, y : i32 },
    /*Rec { width : i32, height : i32, x : i32, y : i32 },
    VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },*/
    // TODO add color
    // TODO add background color
    // TODO add point case
    // TODO add overlap
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();

        while c as u8 as char != 'q' {
            if c as u8 as char == 'j' {
                y+=1;
                cursor_move( y, x );
            } else if c as u8 as char == 'k' {
                y-=1;
                cursor_move( y, x );
            } else if c as u8 as char == 'l' {
               x+=1;
               cursor_move( y, x );
            } else if c as u8 as char == 'h' {
               x-=1;
               cursor_move( y, x );
            }
            refresh();
            c = getch();
        }

        endwin();
    }
}

<commit_msg>using match instead of if statements for handling keyboard input<commit_after>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    Circle { radius : i32, x : i32, y : i32 },
    /*Rec { width : i32, height : i32, x : i32, y : i32 },
    VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },*/
    // TODO add color
    // TODO add background color
    // TODO add point case
    // TODO add overlap
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                'j' => {
                    y+=1;
                    cursor_move( y, x );
                },
                'k' => {
                    y-=1;
                    cursor_move( y, x );
                },
                'l' => {
                    x+=1;
                    cursor_move( y, x );
                },
                'h' => {
                    x-=1;
                    cursor_move( y, x );
                },
                _ => (),
            }
            refresh();
            c = getch();
        }

        endwin();
    }
}

<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate piston_window;
extern crate time;
extern crate rand;
extern crate ai_behavior;
extern crate cgmath;
extern crate opengl_graphics;

mod app;
mod camera;
mod entity;
mod player;
mod config;

use piston_window::{ PistonWindow, WindowSettings };
use piston::input::*;
use piston::event_loop::*;
use opengl_graphics::*;
use graphics::{ Image, clear, default_draw_state };
use graphics::rectangle::square;
use std::path::Path;

use cgmath::rad;
use cgmath::{ Vector2, Vector4 };
use cgmath::{ Rotation2, Basis2 };

fn draw_background(x: u32, y: u32, context: graphics::context::Context, gl_graphics: &mut GlGraphics, txt: &Texture) {
    let (width, height) = txt.get_size();
    for i in 0..x + 1 {
        for j in 0..y + 1 {
            let image = Image::new().rect(square((i * width) as f64, (j * height) as f64, width as f64));
            image.draw(txt, default_draw_state(), context.transform, gl_graphics);
        }
    }
}

fn main() {
    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow = WindowSettings::new("GGJ2016", [800, 600])
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap_or_else(|e| { panic!("Failed to build PistonWindow: {}", e) });
    window.set_ups(60);
    let mut gl = GlGraphics::new(opengl);

    let mut app = app::App::new();
    let size_image = 160;
    // Add player to entities (player instanciated in app)
    //app.add_entity(Box::new(player::Player::new()));

    let texture = Texture::from_path(Path::new("assets/img/ground/placeholder_01.jpg")).unwrap();

    for e in window {
        if let Some(args) = e.press_args() {
            app.key_press(args);
        }

        if let Some(args) = e.update_args() {
            app.update(args);
        }

        if let Some(args) = e.render_args() {
            let grid_width = args.width / size_image;
            let grid_height = args.height / size_image;
            gl.draw(args.viewport(), |c, gl| {
                clear([0.5, 0.2, 0.9, 1.0], gl);
                draw_background(grid_width, grid_height, c, gl, &texture);
            });
            app.render(args);
        }
    }
}
<commit_msg>Generate ground randomly with textures from an array<commit_after>extern crate piston;
extern crate graphics;
extern crate piston_window;
extern crate time;
extern crate rand;
extern crate ai_behavior;
extern crate cgmath;
extern crate opengl_graphics;

mod app;
mod camera;
mod entity;
mod player;
mod config;

use piston_window::{ PistonWindow, WindowSettings };
use piston::input::*;
use piston::event_loop::*;
use opengl_graphics::*;
use graphics::{ Image, clear, default_draw_state };
use graphics::rectangle::square;
use std::path::Path;
use rand::{Rng, SeedableRng, XorShiftRng};

use cgmath::rad;
use cgmath::{ Vector2, Vector4 };
use cgmath::{ Rotation2, Basis2 };

fn draw_background(x: u32, y: u32, context: graphics::context::Context, gl_graphics: &mut GlGraphics, textures: &Vec<Texture>, seed: [u32;4]) {
    let mut rng1: XorShiftRng = SeedableRng::from_seed(seed);
    let txt: &Texture = textures.get(0).unwrap();
    let (width, height) = txt.get_size();
    for i in 0..(x/width) + 1 {
        for j in 0..(y/height) + 1 {
            let rand = rng1.gen::<u32>() % textures.len() as u32;
            let txt: &Texture = textures.get(rand as usize).unwrap();
            let (width, height) = txt.get_size();
            let image = Image::new().rect(square((i * width) as f64, (j * height) as f64, width as f64));
            image.draw(txt, default_draw_state(), context.transform, gl_graphics);
        }
    }
}

fn main() {
    let mut rng = rand::thread_rng();
    let seed: [u32;4] = [rng.gen::<u32>(), rng.gen::<u32>(), rng.gen::<u32>(), rng.gen::<u32>()];
    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow = WindowSettings::new("GGJ2016", [800, 600])
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap_or_else(|e| { panic!("Failed to build PistonWindow: {}", e) });
    window.set_ups(60);
    let mut gl = GlGraphics::new(opengl);

    let mut app = app::App::new();
    // Add player to entities (player instanciated in app)
    //app.add_entity(Box::new(player::Player::new()));

    let mut textures :Vec<Texture>= Vec::new();
    textures.push(Texture::from_path(Path::new("assets/img/ground/placeholder_01.jpg")).unwrap());
    textures.push(Texture::from_path(Path::new("assets/img/ground/placeholder_02.jpg")).unwrap());

    for e in window {
        if let Some(args) = e.press_args() {
            app.key_press(args);
        }

        if let Some(args) = e.update_args() {
            app.update(args);
        }

        if let Some(args) = e.render_args() {
            gl.draw(args.viewport(), |c, gl| {
                clear([0.5, 0.2, 0.9, 1.0], gl);
                draw_background(args.width, args.height, c, gl, &textures, seed);
            });
            app.render(args);
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Try out execd command sample<commit_after>use std::process::Command;

fn main() {
    let output = Command::new("rustc")
        .arg("--version")
        .output().unwrap_or_else(|e| {
            panic!("failed to execute process: {}", e)
    });

    if output.status.success() {
        let s = String::from_utf8_lossy(&output.stdout);

        print!("rustc succeeded and stdout was:\n{}", s);
    } else {
        let s = String::from_utf8_lossy(&output.stderr);

        print!("rustc failed and stderr was:\n{}", s);
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Modify main.rs<commit_after>fn main() {
    println!("Hello, world!!");
}
<|endoftext|>


<commit_before>extern crate rppal;

use std::env;
use std::ffi::OsString;
use rppal::gpio::{GPIO,Mode,Level};

const LAST_PIN_NUMBER: u8 = 27;
const HELP_CMD_STR: &'static str = "help";
const SET_CMD_STR: &'static str = "set";
const GET_CMD_STR: &'static str = "get";
const HIGH_PIN_STATE_STR: &'static str = "high";
const LOW_PIN_STATE_STR: &'static str = "low";
const ALL_PINS_STR: &'static str = "all";
const HELP_EXAMPLE_STR: &'static str = "sudo ./pi3gpio help";

fn main() {
	handle_cmd ( env::args_os() );
}

fn handle_cmd (mut cmd: env::ArgsOs) {
	match cmd.nth(1) {
		Some (action) => {
			if action == OsString::from(HELP_CMD_STR) {
				print_help_text ();
			}
			else if action == OsString::from(SET_CMD_STR) {
				set_pins (cmd);
			}
			else if action == OsString::from(GET_CMD_STR) {
				read_pins (cmd);
			}
			else {
				panic! ("Unknown command {:?}! \nFor help run \"{}\"", action, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("No command found! \nFor help run \"{}\"", HELP_EXAMPLE_STR ),
	}
}

fn print_help_text () {
	println! ("SYNTAX: sudo ./pi3gpio command [state] [pins]");
	println! ("	command: ");
	println! ("		{}	prints the help text", HELP_CMD_STR );
	println! ("		{}	sets the value of the indicated pins to the indicated value", SET_CMD_STR );
	println! ("		{}	prints the state of the indicated pins", GET_CMD_STR );
	println! ("	state: ");
	println! ("		{}	logical 1 for the indicated pins, equivalent voltage 3.3[V]", HIGH_PIN_STATE_STR );
	println! ("		{}	logical 0 for the indicated pins, equivalent voltage 0[V]", LOW_PIN_STATE_STR );
	println! ("	pins: ");
	println! ("		{}	BCM pins between 0 and {}", ALL_PINS_STR, LAST_PIN_NUMBER );
	println! ("Examples:");
	println! ("	sudo ./pi3gpio help ");
	println! ("	sudo ./pi3gpio get all");
	println! ("	sudo ./pi3gpio get 4");
	println! ("	sudo ./pi3gpio get 10 11");
	println! ("	sudo ./pi3gpio set low all");
	println! ("	sudo ./pi3gpio set high 12");
	println! ("	sudo ./pi3gpio set low 2 5 7");
}

trait ReadState{
	fn read_state (self, gpio: &mut GPIO);
}

impl ReadState for OsString {
	fn read_state (self, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => read_pin ( gpio, pin ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn read_all_pins ( gpio: &mut GPIO ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		read_pin ( gpio, pin );
	}
}

fn read_pin ( gpio: &mut GPIO, pin: u8) {
	gpio.set_mode( pin, Mode::Input );
	match gpio.read(pin) {
		Ok(state) =>	println! ("Pin {} = {:?}", pin, state ),
		Err (_) => println! ("Could not read state of pin {}",pin),
	}
}

fn read_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				read_all_pins ( &mut gpio );
				return;
			}
			else {
				pin_as_os_string.read_state ( &mut gpio );
			}
		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.read_state ( &mut gpio );
	}

}

trait ToU8 {
	fn to_u8 (self) -> Result<u8, &'static str >;
}

impl ToU8 for OsString {
	fn to_u8 (self) -> Result<u8, &'static str> {
		match self.into_string() {
			Ok(x) => match x.parse::<u8>() {
				Ok (y) => return Ok (y),
				Err(_) => return Err("String indicating pin number could not be converted to u8!" ),
			},
			Err(_) => return Err("OsString indicating pin number could not be converted to String!" ),
		}
	}
}

fn initiate_gpio_handle () -> GPIO {
    let gpio: GPIO;
    match GPIO::new(){
	    Ok (x) => gpio = x,
	    Err (e) => panic! ("Could not access GPIO memory! {}",e),
    }

    gpio
}

fn get_pin_state ( argument: Option<OsString>  ) -> Level {
	let mut pin_state = Level::Low;
	match argument {
		Some (state) => {
			if state == OsString::from(HIGH_PIN_STATE_STR) {
				pin_state = Level::High;
			}
			else if state != OsString::from(LOW_PIN_STATE_STR) {
				panic! ("State {:?} is invalid! \nFor help run \"{}\"", state, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("State not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

    pin_state
}

trait SetState{
	fn set_state (self, pin_state: Level ,gpio: &mut GPIO);
}

impl SetState for OsString {
	fn set_state (self, pin_state: Level, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => set_pin ( gpio, pin, pin_state ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn set_all_pins ( gpio: &mut GPIO, pin_state: Level ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		set_pin ( gpio, pin, pin_state );
	}
}

fn set_pin ( gpio: &mut GPIO, pin: u8, pin_state: Level ) {
	println! ("Set pin {} to {:?}", pin, pin_state);
	gpio.set_mode( pin, Mode::Output );
	gpio.write ( pin, pin_state );
}

fn set_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();
	gpio.set_clear_on_drop ( false );

	let pin_state = get_pin_state( cmd.nth(0) );

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				set_all_pins ( &mut gpio, pin_state );
				return;
			}
			else {
				pin_as_os_string.set_state( pin_state, &mut gpio );
			}

		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.set_state( pin_state, &mut gpio );
	}
}
<commit_msg>Update main.rs<commit_after>// Copyright 2017 Viorel Bota
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

extern crate rppal;

use std::env;
use std::ffi::OsString;
use rppal::gpio::{GPIO,Mode,Level};

const LAST_PIN_NUMBER: u8 = 27;
const HELP_CMD_STR: &'static str = "help";
const SET_CMD_STR: &'static str = "set";
const GET_CMD_STR: &'static str = "get";
const HIGH_PIN_STATE_STR: &'static str = "high";
const LOW_PIN_STATE_STR: &'static str = "low";
const ALL_PINS_STR: &'static str = "all";
const HELP_EXAMPLE_STR: &'static str = "sudo ./pi3gpio help";

fn main() {
	handle_cmd ( env::args_os() );
}

fn handle_cmd (mut cmd: env::ArgsOs) {
	match cmd.nth(1) {
		Some (action) => {
			if action == OsString::from(HELP_CMD_STR) {
				print_help_text ();
			}
			else if action == OsString::from(SET_CMD_STR) {
				set_pins (cmd);
			}
			else if action == OsString::from(GET_CMD_STR) {
				read_pins (cmd);
			}
			else {
				panic! ("Unknown command {:?}! \nFor help run \"{}\"", action, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("No command found! \nFor help run \"{}\"", HELP_EXAMPLE_STR ),
	}
}

fn print_help_text () {
	println! ("SYNTAX: sudo ./pi3gpio command [state] [pins]");
	println! ("	command: ");
	println! ("		{}	prints the help text", HELP_CMD_STR );
	println! ("		{}	sets the value of the indicated pins to the indicated value", SET_CMD_STR );
	println! ("		{}	prints the state of the indicated pins", GET_CMD_STR );
	println! ("	state: ");
	println! ("		{}	logical 1 for the indicated pins, equivalent voltage 3.3[V]", HIGH_PIN_STATE_STR );
	println! ("		{}	logical 0 for the indicated pins, equivalent voltage 0[V]", LOW_PIN_STATE_STR );
	println! ("	pins: ");
	println! ("		{}	BCM pins between 0 and {}", ALL_PINS_STR, LAST_PIN_NUMBER );
	println! ("Examples:");
	println! ("	sudo ./pi3gpio help ");
	println! ("	sudo ./pi3gpio get all");
	println! ("	sudo ./pi3gpio get 4");
	println! ("	sudo ./pi3gpio get 10 11");
	println! ("	sudo ./pi3gpio set low all");
	println! ("	sudo ./pi3gpio set high 12");
	println! ("	sudo ./pi3gpio set low 2 5 7");
}

trait ReadState{
	fn read_state (self, gpio: &mut GPIO);
}

impl ReadState for OsString {
	fn read_state (self, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => read_pin ( gpio, pin ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn read_all_pins ( gpio: &mut GPIO ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		read_pin ( gpio, pin );
	}
}

fn read_pin ( gpio: &mut GPIO, pin: u8) {
	gpio.set_mode( pin, Mode::Input );
	match gpio.read(pin) {
		Ok(state) =>	println! ("Pin {} = {:?}", pin, state ),
		Err (_) => println! ("Could not read state of pin {}",pin),
	}
}

fn read_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				read_all_pins ( &mut gpio );
				return;
			}
			else {
				pin_as_os_string.read_state ( &mut gpio );
			}
		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.read_state ( &mut gpio );
	}

}

trait ToU8 {
	fn to_u8 (self) -> Result<u8, &'static str >;
}

impl ToU8 for OsString {
	fn to_u8 (self) -> Result<u8, &'static str> {
		match self.into_string() {
			Ok(x) => match x.parse::<u8>() {
				Ok (y) => return Ok (y),
				Err(_) => return Err("String indicating pin number could not be converted to u8!" ),
			},
			Err(_) => return Err("OsString indicating pin number could not be converted to String!" ),
		}
	}
}

fn initiate_gpio_handle () -> GPIO {
    let gpio: GPIO;
    match GPIO::new(){
	    Ok (x) => gpio = x,
	    Err (e) => panic! ("Could not access GPIO memory! {}",e),
    }

    gpio
}

fn get_pin_state ( argument: Option<OsString>  ) -> Level {
	let mut pin_state = Level::Low;
	match argument {
		Some (state) => {
			if state == OsString::from(HIGH_PIN_STATE_STR) {
				pin_state = Level::High;
			}
			else if state != OsString::from(LOW_PIN_STATE_STR) {
				panic! ("State {:?} is invalid! \nFor help run \"{}\"", state, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("State not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

    pin_state
}

trait SetState{
	fn set_state (self, pin_state: Level ,gpio: &mut GPIO);
}

impl SetState for OsString {
	fn set_state (self, pin_state: Level, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => set_pin ( gpio, pin, pin_state ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn set_all_pins ( gpio: &mut GPIO, pin_state: Level ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		set_pin ( gpio, pin, pin_state );
	}
}

fn set_pin ( gpio: &mut GPIO, pin: u8, pin_state: Level ) {
	println! ("Set pin {} to {:?}", pin, pin_state);
	gpio.set_mode( pin, Mode::Output );
	gpio.write ( pin, pin_state );
}

fn set_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();
	gpio.set_clear_on_drop ( false );

	let pin_state = get_pin_state( cmd.nth(0) );

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				set_all_pins ( &mut gpio, pin_state );
				return;
			}
			else {
				pin_as_os_string.set_state( pin_state, &mut gpio );
			}

		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.set_state( pin_state, &mut gpio );
	}
}

// For library "rppal" version "0.1.2" the following LICENSE (MIT) applyes:
// "
//   Copyright (c) 2017 Rene van der Meer
//
//   Permission is hereby granted, free of charge, to any person obtaining a
//   copy of this software and associated documentation files (the "Software"),
//   to deal in the Software without restriction, including without limitation
//   the rights to use, copy, modify, merge, publish, distribute, sublicense,
//   and/or sell copies of the Software, and to permit persons to whom the
//   Software is furnished to do so, subject to the following conditions:
//
//   The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//   DEALINGS IN THE SOFTWARE.
// "

// For the "std" rust library the following LINCESE (MIT) applyes:
// "
//   Copyright (c) 2010 The Rust Project Developers
//
//   Permission is hereby granted, free of charge, to any
//   person obtaining a copy of this software and associated
//   documentation files (the "Software"), to deal in the
//   Software without restriction, including without
//   limitation the rights to use, copy, modify, merge,
//   publish, distribute, sublicense, and/or sell copies of
//   the Software, and to permit persons to whom the Software
//   is furnished to do so, subject to the following
//   conditions:
//
//   The above copyright notice and this permission notice
//   shall be included in all copies or substantial portions
//   of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
//   ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//   TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
//   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
//   SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
//   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
//   IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//   DEALINGS IN THE SOFTWARE.
// "
<|endoftext|>


<commit_before>#![feature(env, path, io)]
use std::old_io as io;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

type Ops = Vec<Op>;
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(Ops)
}

use Op::*;

struct State {
    index: usize,
    memory: [u8; 256]
}

impl State {
    fn peek(&self) -> u8 {
        self.memory[self.index % 256]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % 256] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => { let x = self.peek(); self.poke(x + i); },
            &Mov(n) => self.index += n,
            &In => {
                match io::stdio::stdin().read_u8() {
                    Ok(c) => self.poke(c),
                    Err(e) => panic!(e)
                }
            },
            &Out => {
                io::stdio::stdout().write_u8(self.peek());
            },
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops);
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in filenames[1..].iter() {
        let mut reader = reader(&Path::new(filename));
        let mut state = State { index: 0, memory: [0; 256] };
        let mut chars = reader.chars().peekable();

        'run: loop {
            match parse(&mut chars) {
                Something(op) => state.step(&op),
                EOF => break'run,
                _ => {}
            }
        }
    }
}

fn parse(mut chars: &mut std::iter::Peekable<io::Chars<io::BufferedReader<io::fs::File>>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut children: Ops = Vec::new();
                while !(chars.peek() == Some(&Ok(']'))) {
                    match parse(&mut chars) {
                        Something(op) => children.push(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(children))
            },
            _ => Nothing  // other characters
        },
        _ => EOF
    }
}

fn reader(path: &Path) -> io::BufferedReader<io::File> {
    match io::File::open_mode(path, io::Open, io::Read) {
        Ok(f) => io::BufferedReader::new(f),
        Err(e) => panic!(e)
    }
}
<commit_msg>fix: simpler IO error handling<commit_after>#![feature(env, path, io)]
use std::old_io as io;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

type Ops = Vec<Op>;
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(Ops)
}

use Op::*;

struct State {
    index: usize,
    memory: [u8; 256]
}

impl State {
    fn peek(&self) -> u8 {
        self.memory[self.index % 256]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % 256] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => { let x = self.peek(); self.poke(x + i); },
            &Mov(n) => self.index += n,
            &In => {
                self.poke(io::stdio::stdin().read_u8().unwrap());
            },
            &Out => {
                io::stdio::stdout().write_u8(self.peek()).unwrap();
            },
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops);
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in filenames[1..].iter() {
        let mut reader = reader(&Path::new(filename));
        let mut state = State { index: 0, memory: [0; 256] };
        let mut chars = reader.chars().peekable();

        'run: loop {
            match parse(&mut chars) {
                Something(op) => state.step(&op),
                EOF => break'run,
                _ => {}
            }
        }
    }
}

fn parse(mut chars: &mut std::iter::Peekable<io::Chars<io::BufferedReader<io::fs::File>>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut children: Ops = Vec::new();
                while !(chars.peek() == Some(&Ok(']'))) {
                    match parse(&mut chars) {
                        Something(op) => children.push(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(children))
            },
            _ => Nothing  // other characters
        },
        _ => EOF
    }
}

fn reader(path: &Path) -> io::BufferedReader<io::File> {
    match io::File::open_mode(path, io::Open, io::Read) {
        Ok(f) => io::BufferedReader::new(f),
        Err(e) => panic!(e)
    }
}
<|endoftext|>


<commit_before>//! nock implements a nock interpreter.
// Copyright (2017) Jeremy A. Wall.
//
// 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.
use parser::{Noun, ParseError, atom};
use std::error;
use std::fmt;
use std::fmt::Display;

make_error!(NockError, "NockError: {}\n");

impl From<ParseError> for NockError {
    fn from(err: ParseError) -> Self {
        Self::new_with_cause("AST Parse Error", Box::new(err))
    }
}

fn slice_to_noun(nouns: &[Noun]) -> Result<Noun, NockError> {
    if nouns.len() > 1 {
        Ok(Noun::Cell(nouns.iter().cloned().collect()))
    } else if nouns.len() == 1 {
        Ok(nouns[0].clone())
    } else {
        Err(NockError::new("!! Nock Empty Cell"))
    }
}

// true means take the head.
// false means take the tail
fn make_tree_path(addr: u64) -> Vec<bool> {
    // 6 is the head of 3
    // 3 is the tail of 1
    // 1 is the whole tree.

    // 13 is the tail of 6
    // 6 is the head of 3
    // 3 is the tail of 1
    // 1 is the whole tree.
    let mut ret = Vec::new();
    let mut next = addr;
    loop {
        ret.push(next % 2 == 0);
        next = next / 2;
        if next <= 1 {
            break;
        }
    }
    // TODO(jwall): if we could not have to reverse that would be nice.
    ret.iter().rev().cloned().collect()
}

fn fas(subj: &Noun, addr: u64) -> Result<Noun, NockError> {
    if addr == 0 {
        return Err(NockError::new("!! Invalid slot address 0"));
    }
    if addr == 1 {
        return Ok(subj.clone());
    }
    if addr == 2 {
        return Ok(try!(subj.head()).clone());
    }
    if addr == 3 {
        return slice_to_noun(try!(subj.tail()));
    }
    let path = make_tree_path(addr);
    let mut subject = subj.clone();
    for take_head in path {
        subject = if take_head {
            try!(subject.head()).clone()
        } else {
            try!(slice_to_noun(try!(subject.tail())))
        }
    }
    Ok(subject)
}

#[cfg(test)]
#[test]
fn test_simple_fas() {
    // /[1 [531 25 99]] is [531 25 99];
    let cases = vec![(cell!(atom(531), atom(25), atom(99)), 1,
                      cell!(atom(531), atom(25), atom(99))),
                     // /[2 [531 25 99]] is 531;
                     (cell!(atom(531), atom(25), atom(99)), 2,
                      atom(531)),
                     // /[3 [531 25 99]] is [25 99];
                     (cell!(atom(531), atom(25), atom(99)), 3,
                      cell!(atom(25), atom(99))),
                     // /[6 [531 25 99]] is 25;
                     (cell!(atom(531), atom(25), atom(99)), 6,
                      atom(25)),
                     (cell!(atom(531), cell!(atom(25), atom(26)), atom(99)), 6,
                      cell!(atom(25), atom(26))),
                     (cell!(atom(531), cell!(atom(25), atom(26)), atom(99)), 12,
                      atom(25)),
                     (cell!(atom(531), cell!(atom(25), atom(26)), atom(99)), 13,
                      atom(26)),
                     ];
    for (subj, addr, expected) in cases {
        assert_eq!(expected, fas(&subj, addr).unwrap());
    }
    // [12 [531 25 99]] crashes
}

#[cfg(test)]
#[test]
#[should_panic]
fn test_fas_crash() {
    let cell = cell!(atom(531), atom(25), atom(99));
    // We expect an error here so we crash.
    fas(&cell, 12).unwrap();
}

// Returns 1 false for an atom and 0 true for a Noun::Cell.
fn wut(noun: Noun) -> Noun {
    match noun {
        Noun::Atom(_) => atom(1),
        Noun::Cell(_) => atom(0),
    }
}

// lus increments a atom but crashes for a Noun::Cell.
fn lus(noun: Noun) -> Result<Noun, NockError> {
    match noun {
        Noun::Atom(a) => Ok(atom(a + 1)),
        Noun::Cell(_) => Err(NockError::new("!! Can't increment a cell")),
    }
}

fn cmp_noun(a: &Noun, b: &[Noun]) -> Noun {
    let falsy = atom(0);
    let truthy = atom(1);
    match a {
        &Noun::Cell(ref list) => {
            if list.len() != b.len() {
                return falsy;
            }
            for (i, n) in list.iter().enumerate() {
                if cmp_noun(n, &b[i..]) == falsy {
                    return falsy;
                }
            }
            return truthy;
        }
        &Noun::Atom(a) => {
            if b.len() != 1 {
                if let Noun::Atom(b) = b[0] {
                    if a == b {
                        return truthy;
                    }
                }
            }
            return falsy;
        }
    }
}

// tis compares a Noun::Cell's head and tail Nouns for equality.
fn tis(noun: Noun) -> Result<Noun, NockError> {
    match noun {
        Noun::Atom(_) => Err(NockError::new("!! Can't compaire Atom like a cell")),
        Noun::Cell(list) => {
            if list.len() >= 2 {
                Ok(cmp_noun(&list[0], &list[1..]))
            } else {
                Err(NockError::new("!! Can't compare a cell of only one Noun"))
            }
        }
    }
}

// evaluates a nock expression of type [subj formula] or [formula] or atom
pub fn eval(noun: Noun) -> Result<Noun, NockError> {
    match &noun {
        &Noun::Atom(_) => nock_internal(&Noun::Atom(0), noun.clone()),
        &Noun::Cell(ref list) => {
            if list.len() >= 2 {
                nock_internal(try!(noun.head()), try!(slice_to_noun(try!(noun.tail()))))
            } else {
                Err(NockError::new("!! Invalid Nock Expression"))
            }
        }
    }
}

// Evaluates a nock formula against a subj.
fn nock_internal(subj: &Noun, formula: Noun) -> Result<Noun, NockError> {
    match formula {
        Noun::Atom(_) => return Err(NockError::new(format!("!! Nock Infinite Loop"))),
        cell => {
            match try!(cell.head()) {
                &Noun::Atom(a) => {
                    // We expect an instruction from 0 to 10
                    match a {
                        0 => {
                            let tail = try!(slice_to_noun(try!(cell.tail())));
                            if let Noun::Atom(b) = tail {
                                return fas(subj, b);
                            } else {
                                return Err(NockError::new(format!("!! not a slot index {}", tail)));
                            }
                        }
                        1 => {
                            return Ok(try!(slice_to_noun(try!(cell.tail()))));
                        }
                        2 => {
                            return Ok(try!(nock_internal(subj,
                                                         try!(slice_to_noun(try!(cell.tail()))))));
                        }
                        3 => {
                            return Ok(wut(try!(nock_internal(subj,
                                                             try!(slice_to_noun(
                                                    try!(cell.tail())))))));
                        }
                        4 => {
                            let tail_noun = try!(slice_to_noun(try!(cell.tail())));
                            if let Noun::Cell(_) = tail_noun {
                                return Ok(try!(lus(try!(nock_internal(subj, tail_noun)))));
                            }
                            return Ok(try!(lus(tail_noun)));
                        }
                        5 => {
                            return Ok(try!(tis(try!(slice_to_noun(try!(cell.tail()))))));
                        }
                        // macros
                        6 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 3 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            let d = try!(slice_to_noun(&tail[2..]));
                            // *[a 6 b c d]     *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
                            let formula = cell!(atom(2),
                                                // [0 1]
                                                cell!(atom(0), atom(1)),
                                                // 2
                                                atom(2),
                                                // [1 c d]
                                                cell!(atom(1), c, d),
                                                // [1 0]
                                                cell!(atom(1), atom(0)),
                                                // 2
                                                atom(2),
                                                // [1 2 3]
                                                cell!(atom(1), atom(2), atom(3)),
                                                // [1 0]
                                                cell!(atom(1), atom(0)),
                                                // 4 4 b]
                                                atom(4),
                                                atom(4),
                                                b);
                            return nock_internal(subj, formula);
                        }
                        7 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            // *[a 7 b c] -> *[a 2 b 1 c]
                            let formula = cell!(atom(2), b, atom(1), c);
                            return nock_internal(subj, formula);
                        }
                        8 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            // *[a 8 b c]       *[a 7 [[7 [0 1] b] 0 1] c]
                            let formula = cell!(atom(7),
                                                cell!(cell!(atom(7), cell!(atom(0), atom(1)), b),
                                                      atom(0),
                                                      atom(1)),
                                                c);
                            return nock_internal(subj, formula);
                        }
                        9 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            // *[a 9 b c]       *[a 7 c 2 [0 1] 0 b]
                            let formula =
                                cell!(atom(7), c, atom(2), cell!(atom(0), atom(1)), atom(0), b);
                            return nock_internal(subj, formula);
                        }
                        10 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            match b {
                                Noun::Atom(_) => {
                                    // *[a 10 b c]      *[a c]
                                    // b is discarded.
                                    return nock_internal(subj, c);
                                }
                                Noun::Cell(list) => {
                                    let d = c;
                                    // b is discarded.
                                    let c = try!(slice_to_noun(&list[1..]));
                                    // *[a 10 [b c] d]  *[a 8 c 7 [0 3] d]
                                    let formula =
                                        cell!(atom(8), c, atom(7), cell!(atom(0), atom(3)), d);
                                    return nock_internal(subj, formula);
                                }
                            }
                        }
                        _ => {
                            return Err(NockError::new(format!("!! Unknown Nock instruction {}",
                                                              a)));
                        }
                    }
                }
                head_formula => {
                    let head = try!(nock_internal(subj, head_formula.clone()));
                    let new_formula = try!(slice_to_noun(try!(cell.tail())));
                    let tail_noun = try!(nock_internal(subj, new_formula));
                    return Ok(cell!(head, tail_noun));
                }
            }
        }
    }
}
<commit_msg>Tests for nock operation '+'.<commit_after>//! nock implements a nock interpreter.
// Copyright (2017) Jeremy A. Wall.
//
// 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.
use parser::{Noun, ParseError, atom};
use std::error;
use std::fmt;
use std::fmt::Display;

make_error!(NockError, "NockError: {}\n");

impl From<ParseError> for NockError {
    fn from(err: ParseError) -> Self {
        Self::new_with_cause("AST Parse Error", Box::new(err))
    }
}

fn slice_to_noun(nouns: &[Noun]) -> Result<Noun, NockError> {
    if nouns.len() > 1 {
        Ok(Noun::Cell(nouns.iter().cloned().collect()))
    } else if nouns.len() == 1 {
        Ok(nouns[0].clone())
    } else {
        Err(NockError::new("!! Nock Empty Cell"))
    }
}

// true means take the head.
// false means take the tail
fn make_tree_path(addr: u64) -> Vec<bool> {
    // 6 is the head of 3
    // 3 is the tail of 1
    // 1 is the whole tree.

    // 13 is the tail of 6
    // 6 is the head of 3
    // 3 is the tail of 1
    // 1 is the whole tree.
    let mut ret = Vec::new();
    let mut next = addr;
    loop {
        ret.push(next % 2 == 0);
        next = next / 2;
        if next <= 1 {
            break;
        }
    }
    // TODO(jwall): if we could not have to reverse that would be nice.
    ret.iter().rev().cloned().collect()
}

fn fas(subj: &Noun, addr: u64) -> Result<Noun, NockError> {
    if addr == 0 {
        return Err(NockError::new("!! Invalid slot address 0"));
    }
    if addr == 1 {
        return Ok(subj.clone());
    }
    if addr == 2 {
        return Ok(try!(subj.head()).clone());
    }
    if addr == 3 {
        return slice_to_noun(try!(subj.tail()));
    }
    let path = make_tree_path(addr);
    let mut subject = subj.clone();
    for take_head in path {
        subject = if take_head {
            try!(subject.head()).clone()
        } else {
            try!(slice_to_noun(try!(subject.tail())))
        }
    }
    Ok(subject)
}

#[cfg(test)]
#[test]
fn test_simple_fas() {
    // /[1 [531 25 99]] is [531 25 99];
    let cases = vec![(cell!(atom(531), atom(25), atom(99)), 1,
                      cell!(atom(531), atom(25), atom(99))),
                     // /[2 [531 25 99]] is 531;
                     (cell!(atom(531), atom(25), atom(99)), 2,
                      atom(531)),
                     // /[3 [531 25 99]] is [25 99];
                     (cell!(atom(531), atom(25), atom(99)), 3,
                      cell!(atom(25), atom(99))),
                     // /[6 [531 25 99]] is 25;
                     (cell!(atom(531), atom(25), atom(99)), 6,
                      atom(25)),
                     (cell!(atom(531), cell!(atom(25), atom(26)), atom(99)), 6,
                      cell!(atom(25), atom(26))),
                     (cell!(atom(531), cell!(atom(25), atom(26)), atom(99)), 12,
                      atom(25)),
                     (cell!(atom(531), cell!(atom(25), atom(26)), atom(99)), 13,
                      atom(26)),
                     ];
    for (subj, addr, expected) in cases {
        assert_eq!(expected, fas(&subj, addr).unwrap());
    }
    // [12 [531 25 99]] crashes
}

#[cfg(test)]
#[test]
#[should_panic]
fn test_fas_crash() {
    let cell = cell!(atom(531), atom(25), atom(99));
    // We expect an error here so we crash.
    fas(&cell, 12).unwrap();
}

// Returns 1 false for an atom and 0 true for a Noun::Cell.
fn wut(noun: Noun) -> Noun {
    match noun {
        Noun::Atom(_) => atom(1),
        Noun::Cell(_) => atom(0),
    }
}

// lus increments a atom but crashes for a Noun::Cell.
fn lus(noun: Noun) -> Result<Noun, NockError> {
    match noun {
        Noun::Atom(a) => Ok(atom(a + 1)),
        Noun::Cell(_) => Err(NockError::new("!! Can't increment a cell")),
    }
}

#[cfg(test)]
#[test]
fn test_lus() {
    assert_eq!(lus(atom(1)).expect("Should be able to increment an atom"), atom(2));
}

#[cfg(test)]
#[test]
#[should_panic]
fn test_lus_crash() {
    lus(cell!(atom(1), atom(2))).unwrap();
}

fn cmp_noun(a: &Noun, b: &[Noun]) -> Noun {
    let falsy = atom(0);
    let truthy = atom(1);
    match a {
        &Noun::Cell(ref list) => {
            if list.len() != b.len() {
                return falsy;
            }
            for (i, n) in list.iter().enumerate() {
                if cmp_noun(n, &b[i..]) == falsy {
                    return falsy;
                }
            }
            return truthy;
        }
        &Noun::Atom(a) => {
            if b.len() != 1 {
                if let Noun::Atom(b) = b[0] {
                    if a == b {
                        return truthy;
                    }
                }
            }
            return falsy;
        }
    }
}

// tis compares a Noun::Cell's head and tail Nouns for equality.
fn tis(noun: Noun) -> Result<Noun, NockError> {
    match noun {
        Noun::Atom(_) => Err(NockError::new("!! Can't compaire Atom like a cell")),
        Noun::Cell(list) => {
            if list.len() >= 2 {
                Ok(cmp_noun(&list[0], &list[1..]))
            } else {
                Err(NockError::new("!! Can't compare a cell of only one Noun"))
            }
        }
    }
}

// evaluates a nock expression of type [subj formula] or [formula] or atom
pub fn eval(noun: Noun) -> Result<Noun, NockError> {
    match &noun {
        &Noun::Atom(_) => nock_internal(&Noun::Atom(0), noun.clone()),
        &Noun::Cell(ref list) => {
            if list.len() >= 2 {
                nock_internal(try!(noun.head()), try!(slice_to_noun(try!(noun.tail()))))
            } else {
                Err(NockError::new("!! Invalid Nock Expression"))
            }
        }
    }
}

// Evaluates a nock formula against a subj.
fn nock_internal(subj: &Noun, formula: Noun) -> Result<Noun, NockError> {
    match formula {
        Noun::Atom(_) => return Err(NockError::new(format!("!! Nock Infinite Loop"))),
        cell => {
            match try!(cell.head()) {
                &Noun::Atom(a) => {
                    // We expect an instruction from 0 to 10
                    match a {
                        0 => {
                            let tail = try!(slice_to_noun(try!(cell.tail())));
                            if let Noun::Atom(b) = tail {
                                return fas(subj, b);
                            } else {
                                return Err(NockError::new(format!("!! not a slot index {}", tail)));
                            }
                        }
                        1 => {
                            return Ok(try!(slice_to_noun(try!(cell.tail()))));
                        }
                        2 => {
                            return Ok(try!(nock_internal(subj,
                                                         try!(slice_to_noun(try!(cell.tail()))))));
                        }
                        3 => {
                            return Ok(wut(try!(nock_internal(subj,
                                                             try!(slice_to_noun(
                                                    try!(cell.tail())))))));
                        }
                        4 => {
                            let tail_noun = try!(slice_to_noun(try!(cell.tail())));
                            if let Noun::Cell(_) = tail_noun {
                                return Ok(try!(lus(try!(nock_internal(subj, tail_noun)))));
                            }
                            return Ok(try!(lus(tail_noun)));
                        }
                        5 => {
                            return Ok(try!(tis(try!(slice_to_noun(try!(cell.tail()))))));
                        }
                        // macros
                        6 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 3 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            let d = try!(slice_to_noun(&tail[2..]));
                            // *[a 6 b c d]     *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
                            let formula = cell!(atom(2),
                                                // [0 1]
                                                cell!(atom(0), atom(1)),
                                                // 2
                                                atom(2),
                                                // [1 c d]
                                                cell!(atom(1), c, d),
                                                // [1 0]
                                                cell!(atom(1), atom(0)),
                                                // 2
                                                atom(2),
                                                // [1 2 3]
                                                cell!(atom(1), atom(2), atom(3)),
                                                // [1 0]
                                                cell!(atom(1), atom(0)),
                                                // 4 4 b]
                                                atom(4),
                                                atom(4),
                                                b);
                            return nock_internal(subj, formula);
                        }
                        7 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            // *[a 7 b c] -> *[a 2 b 1 c]
                            let formula = cell!(atom(2), b, atom(1), c);
                            return nock_internal(subj, formula);
                        }
                        8 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            // *[a 8 b c]       *[a 7 [[7 [0 1] b] 0 1] c]
                            let formula = cell!(atom(7),
                                                cell!(cell!(atom(7), cell!(atom(0), atom(1)), b),
                                                      atom(0),
                                                      atom(1)),
                                                c);
                            return nock_internal(subj, formula);
                        }
                        9 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            // *[a 9 b c]       *[a 7 c 2 [0 1] 0 b]
                            let formula =
                                cell!(atom(7), c, atom(2), cell!(atom(0), atom(1)), atom(0), b);
                            return nock_internal(subj, formula);
                        }
                        10 => {
                            let tail = try!(cell.tail());
                            if tail.len() < 2 {
                                return Err(NockError::new("!! Need 3 Nouns for macro 6"));
                            }
                            let b = tail[0].clone();
                            let c = tail[1].clone();
                            match b {
                                Noun::Atom(_) => {
                                    // *[a 10 b c]      *[a c]
                                    // b is discarded.
                                    return nock_internal(subj, c);
                                }
                                Noun::Cell(list) => {
                                    let d = c;
                                    // b is discarded.
                                    let c = try!(slice_to_noun(&list[1..]));
                                    // *[a 10 [b c] d]  *[a 8 c 7 [0 3] d]
                                    let formula =
                                        cell!(atom(8), c, atom(7), cell!(atom(0), atom(3)), d);
                                    return nock_internal(subj, formula);
                                }
                            }
                        }
                        _ => {
                            return Err(NockError::new(format!("!! Unknown Nock instruction {}",
                                                              a)));
                        }
                    }
                }
                head_formula => {
                    let head = try!(nock_internal(subj, head_formula.clone()));
                    let new_formula = try!(slice_to_noun(try!(cell.tail())));
                    let tail_noun = try!(nock_internal(subj, new_formula));
                    return Ok(cell!(head, tail_noun));
                }
            }
        }
    }
}
<|endoftext|>