<commit_before>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::path::PathBuf;

use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_version: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{
    ($mac:ident) => ({
        $mac!(bench);
        $mac!(build);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    })
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);
    cargo::util::job::setup();

    if flags.flag_version {
        println!("{}", cargo::version());
        return Ok(None)
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(),
                       "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        })
    }
    each_subcommand!(cmd);

    try!(execute_subcommand(config, &args[1], &args));
    Ok(None)
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_subcommand(config: &Config,
                      cmd: &str,
                      args: &[String]) -> CargoResult<()> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
                    .iter()
                    .map(|dir| dir.join(&command_exe))
                    .filter_map(|dir| fs::metadata(&dir).ok().map(|m| (dir, m)))
                    .find(|&(_, ref meta)| is_executable(meta));
    let command = match path {
        Some((command, _)) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                Some(closest) => format!("no such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "no such subcommand".to_string()
            }))
        }
    };
    try!(util::process(&command).args(&args[1..]).exec());
    Ok(())
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue
            }
            if let Ok(meta) = entry.metadata() {
                if is_executable(&meta) {
                    let end = filename.len() - suffix.len();
                    commands.insert(filename[prefix.len()..end].to_string());
                }
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => (commands.insert(stringify!($cmd).replace("_", "-")))
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    use std::os::unix::prelude::*;
    metadata.is_file() && metadata.permissions().mode() & 0o111 != 0
}
#[cfg(windows)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    metadata.is_file()
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Auto merge of #2384 - jseyfried:master, r=alexcrichton<commit_after>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::path::PathBuf;

use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_version: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

mod subcommands {
    macro_rules! declare_mod {
        ($name:ident) => ( pub mod $name; )
    }
    each_subcommand!(declare_mod);
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);
    cargo::util::job::setup();

    if flags.flag_version {
        println!("{}", cargo::version());
        return Ok(None)
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(),
                       "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin(subcommands::$name::execute, config,
                                                   subcommands::$name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        })
    }
    each_subcommand!(cmd);

    try!(execute_subcommand(config, &args[1], &args));
    Ok(None)
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_subcommand(config: &Config,
                      cmd: &str,
                      args: &[String]) -> CargoResult<()> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
                    .iter()
                    .map(|dir| dir.join(&command_exe))
                    .filter_map(|dir| fs::metadata(&dir).ok().map(|m| (dir, m)))
                    .find(|&(_, ref meta)| is_executable(meta));
    let command = match path {
        Some((command, _)) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                Some(closest) => format!("no such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "no such subcommand".to_string()
            }))
        }
    };
    try!(util::process(&command).args(&args[1..]).exec());
    Ok(())
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue
            }
            if let Ok(meta) = entry.metadata() {
                if is_executable(&meta) {
                    let end = filename.len() - suffix.len();
                    commands.insert(filename[prefix.len()..end].to_string());
                }
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    use std::os::unix::prelude::*;
    metadata.is_file() && metadata.permissions().mode() & 0o111 != 0
}
#[cfg(windows)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    metadata.is_file()
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case, non_camel_case_types)]

pub use self::error::*;

use std::mem;

mod error;

pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(0isize) })
}

pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(-1isize) })
}

/// Run-Time Limit Categories
#[repr(C)]
pub enum Limit {
    /// The maximum size of any string or BLOB or table row, in bytes.
    SQLITE_LIMIT_LENGTH = SQLITE_LIMIT_LENGTH as isize,
    /// The maximum length of an SQL statement, in bytes.
    SQLITE_LIMIT_SQL_LENGTH = SQLITE_LIMIT_SQL_LENGTH as isize,
    /// The maximum number of columns in a table definition or in the result set of a SELECT
    /// or the maximum number of columns in an index or in an ORDER BY or GROUP BY clause.
    SQLITE_LIMIT_COLUMN = SQLITE_LIMIT_COLUMN as isize,
    /// The maximum depth of the parse tree on any expression.
    SQLITE_LIMIT_EXPR_DEPTH = SQLITE_LIMIT_EXPR_DEPTH as isize,
    /// The maximum number of terms in a compound SELECT statement.
    SQLITE_LIMIT_COMPOUND_SELECT = SQLITE_LIMIT_COMPOUND_SELECT as isize,
    /// The maximum number of instructions in a virtual machine program used to implement an SQL statement.
    SQLITE_LIMIT_VDBE_OP = SQLITE_LIMIT_VDBE_OP as isize,
    /// The maximum number of arguments on a function.
    SQLITE_LIMIT_FUNCTION_ARG = SQLITE_LIMIT_FUNCTION_ARG as isize,
    /// The maximum number of attached databases.
    SQLITE_LIMIT_ATTACHED = SQLITE_LIMIT_ATTACHED as isize,
    /// The maximum length of the pattern argument to the LIKE or GLOB operators.
    SQLITE_LIMIT_LIKE_PATTERN_LENGTH = SQLITE_LIMIT_LIKE_PATTERN_LENGTH as isize,
    /// The maximum index number of any parameter in an SQL statement.
    SQLITE_LIMIT_VARIABLE_NUMBER = SQLITE_LIMIT_VARIABLE_NUMBER as isize,
    /// The maximum depth of recursion for triggers.
    SQLITE_LIMIT_TRIGGER_DEPTH = SQLITE_LIMIT_TRIGGER_DEPTH as isize,
    /// The maximum number of auxiliary worker threads that a single prepared statement may start.
    SQLITE_LIMIT_WORKER_THREADS = SQLITE_LIMIT_WORKER_THREADS as isize,
}

include!(concat!(env!("OUT_DIR"), "/bindgen.rs"));
<commit_msg>Some limits are not available in 3.6.8<commit_after>#![allow(non_snake_case, non_camel_case_types)]

pub use self::error::*;

use std::mem;

mod error;

pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(0isize) })
}

pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(-1isize) })
}

/// Run-Time Limit Categories
#[repr(C)]
pub enum Limit {
    /// The maximum size of any string or BLOB or table row, in bytes.
    SQLITE_LIMIT_LENGTH = SQLITE_LIMIT_LENGTH as isize,
    /// The maximum length of an SQL statement, in bytes.
    SQLITE_LIMIT_SQL_LENGTH = SQLITE_LIMIT_SQL_LENGTH as isize,
    /// The maximum number of columns in a table definition or in the result set of a SELECT
    /// or the maximum number of columns in an index or in an ORDER BY or GROUP BY clause.
    SQLITE_LIMIT_COLUMN = SQLITE_LIMIT_COLUMN as isize,
    /// The maximum depth of the parse tree on any expression.
    SQLITE_LIMIT_EXPR_DEPTH = SQLITE_LIMIT_EXPR_DEPTH as isize,
    /// The maximum number of terms in a compound SELECT statement.
    SQLITE_LIMIT_COMPOUND_SELECT = SQLITE_LIMIT_COMPOUND_SELECT as isize,
    /// The maximum number of instructions in a virtual machine program used to implement an SQL statement.
    SQLITE_LIMIT_VDBE_OP = SQLITE_LIMIT_VDBE_OP as isize,
    /// The maximum number of arguments on a function.
    SQLITE_LIMIT_FUNCTION_ARG = SQLITE_LIMIT_FUNCTION_ARG as isize,
    /// The maximum number of attached databases.
    SQLITE_LIMIT_ATTACHED = SQLITE_LIMIT_ATTACHED as isize,
    /// The maximum length of the pattern argument to the LIKE or GLOB operators.
    SQLITE_LIMIT_LIKE_PATTERN_LENGTH = SQLITE_LIMIT_LIKE_PATTERN_LENGTH as isize,
    /// The maximum index number of any parameter in an SQL statement.
    SQLITE_LIMIT_VARIABLE_NUMBER = SQLITE_LIMIT_VARIABLE_NUMBER as isize,
    /// The maximum depth of recursion for triggers.
    SQLITE_LIMIT_TRIGGER_DEPTH = 10,
    /// The maximum number of auxiliary worker threads that a single prepared statement may start.
    SQLITE_LIMIT_WORKER_THREADS = 11,
}

include!(concat!(env!("OUT_DIR"), "/bindgen.rs"));
<|endoftext|>


<commit_before>fn run_feature_checks(_ecx: u32, _edx: u32) {
    // TODO
}

pub fn init() {
    let ecx: u32;
    let edx: u32;
    unsafe {
        // CPUID_GETFEATURES
        asm!(
            "xor ecx, ecx; xor edx, edx; mov eax, 1; cpuid"
            : "={ecx}"(ecx), "={edx}"(edx) :: "eax", "ecx", "edx"
            : "intel", "volatile"
        );
    }
    rprintln!("CPU FEATURE BITS: {:b} {:b}", ecx, edx);
    run_feature_checks(ecx, edx);
}
<commit_msg>Improve cpuid module<commit_after>use alloc::String;
use alloc::borrow::ToOwned;

pub fn cpu_brand() -> String {
    let mut result = String::new();

    'outer: for index in 0x80000002u32..=0x80000004u32 {
        let eax: u32;
        let ebx: u32;
        let ecx: u32;
        let edx: u32;
        unsafe {
            asm!(
                "xor ecx, ecx; xor edx, edx; cpuid"
                : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
                : "{eax}"(index)
                :
                : "intel", "volatile"
            );
            let values = [eax, ebx, ecx, edx];
            for v in values.iter() {
                for i in 0..=3 {
                    let bytepos = i * 8;
                    let byte = ((v & (0xFF << bytepos)) >> bytepos) as u8;
                    if byte == 0 {
                        break 'outer;
                    }
                    result.push(byte as char);
                }
            }
        }
    }
    result.trim().to_owned()
}

fn run_feature_checks(_ecx: u32, _edx: u32) {
    // TODO
}

pub fn init() {
    let ecx: u32;
    let edx: u32;
    unsafe {
        // CPUID_GETFEATURES
        asm!(
            "xor ecx, ecx; xor edx, edx; mov eax, 1; cpuid"
            : "={ecx}"(ecx), "={edx}"(edx)
            :
            : "eax", "ebx"
            : "intel", "volatile"
        );
    }
    rprintln!("CPU: FEATURE BITS: {:b} {:b}", ecx, edx);
    run_feature_checks(ecx, edx);
}
<|endoftext|>


<commit_before>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

# Links

http://www.data-compression.info/Algorithms/DC/

# Example

```rust
use compress::bwt::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple::<uint>(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::{io, iter};
use vec = std::slice;
use super::mtf::MTF;

pub type Symbol = u8;
pub type Rank = u8;
pub static TotalSymbols: uint = 0x100;

/// Distance coding context
/// Has all the information potentially needed by the underlying coding model
pub struct Context {
    /// current symbol
    symbol: Symbol,
    /// last known MTF rank
    last_rank: Rank,
    /// maximum possible distance
    distance_limit: uint,
}

impl Context {
    /// create a new distance context
    pub fn new(s: Symbol, r: Rank, dmax: uint) -> Context {
        Context {
            symbol: s,
            last_rank: r,
            distance_limit: dmax,
        }
    }
}

/// DC body iterator, can be used to encode distances
pub struct EncodeIterator<'a,'b,D> {
    data: iter::Enumerate<iter::Zip<vec::Items<'a,Symbol>,vec::Items<'b,D>>>,
    pos: [uint, ..TotalSymbols],
    size: uint,
}

impl<'a, 'b, D: NumCast> EncodeIterator<'a,'b,D> {
    /// fixme
    pub fn new(input: &'a [Symbol], dist: &'b [D], next: &[D, ..TotalSymbols]) -> EncodeIterator<'a,'b,D> {
        assert_eq!(input.len(), dist.len());
        let mut pos = [0u, ..TotalSymbols];
        for (pi,ni) in pos.mut_iter().zip(next.iter()) {
            *pi = ni.to_uint().unwrap();
        }
        EncodeIterator {
            data: input.iter().zip(dist.iter()).enumerate(),
            pos: pos,
            size: input.len()
        }
    }
}

impl<'a, 'b, D: Clone + Eq + NumCast> Iterator<(D,Context)> for EncodeIterator<'a,'b,D> {
    fn next(&mut self) -> Option<(D,Context)> {
        let filler: D = NumCast::from(self.size).unwrap();
        self.data.find(|&(_,(_,d))| *d != filler).map(|(i,(sym,d))| {
            let rank = i - self.pos[*sym as uint];
            assert!(0<rank && rank<TotalSymbols);
            self.pos[*sym as uint] = i + d.to_uint().unwrap();
            (d.clone(), Context::new(*sym, rank as Rank, self.size-i))
        })
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode<'a, 'b, D: Clone + Eq + NumCast>(input: &'a [Symbol], distances: &'b mut [D], mtf: &mut MTF) -> ~[(Symbol,D)] {
    let n = input.len();
    assert_eq!(distances.len(), n);
    let mut last = [n, ..TotalSymbols];
    let mut unique: ~[(Symbol,D)] = vec::with_capacity(TotalSymbols);
    let filler: D = NumCast::from(n).unwrap();
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = filler.clone();
        let base = last[sym as uint];
        last[sym as uint] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == n {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            let d = NumCast::from(i).unwrap();
            unique.push((sym,d));
        }else {
            let rank = mtf.encode(sym) as uint;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = NumCast::from(i-base-rank-1).unwrap();
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym as uint];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, n-base-rank-1);
        assert!(n >= base+rank+1);
        distances[base] = NumCast::from(n-base-rank-1).unwrap();
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),d)| *d==filler && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple<D: Clone + Eq + NumCast>(input: &[Symbol]) -> (~[Symbol],~[D]) {
    let n = input.len();
    if n==0 {
        (~[],~[])
    }else   {
        let mut raw_dist: ~[D] = vec::from_elem(n, NumCast::from(0).unwrap());
        let pairs = encode(input, raw_dist, &mut MTF::new());
        let mut symbols = pairs.iter().map(|&(sym,_)| sym);
        let init_iter = pairs.iter().map(|pair| { let (_, ref d) = *pair; d.clone() });
        let filler: D = NumCast::from(n).unwrap();
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|d| if *d!=filler {Some(d.clone())} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols.collect(), combined.collect())
    }
}

/// Decode a block of distances given initial symbol distances
pub fn decode_body(mut next: [uint,..TotalSymbols], output: &mut [Symbol], mtf: &mut MTF,
        fn_dist: |Context|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut i = 0u;
    for (sym,d) in next.iter().enumerate() {
        if *d < n {
            let mut j = i;
            while j>0u && next[mtf.symbols[j-1] as uint] > *d {
                mtf.symbols[j] = mtf.symbols[j-1];
                j -= 1;
            }
            mtf.symbols[j] = sym as Symbol;
            i += 1;
        }
    }
    if i<=1 {
        // redundant alphabet case
        let sym = mtf.symbols[0];
        for out in output.mut_iter()    {
            *out = sym;
        }
        return Ok(())
    }

    let alphabet_size = i;
    let mut ranks = [0 as Rank, ..TotalSymbols];
    for rank in range(0, i) {
        let sym = mtf.symbols[rank];
        debug!("\tRegistering symbol {} of rank {} at position {}",
            sym, rank, next[sym as uint]);
        ranks[sym as uint] = rank as Rank;
    }

    i = 0u;
    while i<n {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1] as uint];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let ctx = Context::new(sym, ranks[sym as uint], n-i);
        let future = match fn_dist(ctx) {
            Ok(d) => stop + d,
            Err(e) => return Err(e)
        };
        debug!("\t\tLooking for future position {}", future);
        assert!(future <= n);
        let mut rank = 1u;
        while rank < alphabet_size && future+rank > next[mtf.symbols[rank] as uint] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank < alphabet_size {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank] as uint]);
        }else {
            debug!("\t\tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym as uint] = future+rank-1;
        ranks[sym as uint] = rank as Rank;
    }
    assert_eq!(next.iter().position(|&d| d<n || d>=n+alphabet_size), None);
    assert_eq!(i, n);
    Ok(())
}

/// Decode a block of distances with a list of initial symbols
pub fn decode(alphabet: Option<&[Symbol]>, output: &mut [Symbol], mtf: &mut MTF,
    fn_dist: |Context|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut next = [n, ..TotalSymbols];
    match alphabet {
        Some(list) => {
            // given fixed alphabet
            for &sym in list.iter() {
                let ctx = Context::new(sym, 0, n);
                // initial distances are not ordered
                next[sym as uint] = match fn_dist(ctx) {
                    Ok(d) => d, // + (rank as Distance)
                    Err(e) => return Err(e)
                };
            }
        },
        None => {
            // alphabet is large, total range of symbols is assumed
            for i in range(0, TotalSymbols) {
                let ctx = Context::new(i as Symbol, 9, n);
                next[i] = match fn_dist(ctx) {
                    Ok(d) => d,
                    Err(e) => return Err(e)
                };
            }
        },
    }

    decode_body(next, output, mtf, fn_dist)
}

/// decode with "batteries included" for quick testing
pub fn decode_simple<D: ToPrimitive>(n: uint, alphabet: &[Symbol], distances: &[D]) -> ~[Symbol] {
    let mut output = vec::from_elem(n, 0 as Symbol);
    let mut di = 0u;
    decode(Some(alphabet), output.as_mut_slice(), &mut MTF::new(), |_ctx| {
        di += 1;
        if di > distances.len() {
            Err(io::standard_error(io::EndOfFile))
        }else {
            Ok(distances[di-1].to_uint().unwrap())
        }
    }).unwrap();
    output
}

#[cfg(test)]
mod test {
    use std;

    fn roundtrip(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = super::encode_simple::<uint>(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = super::decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_full_alphabet(bytes: &[u8]) {
        let n = bytes.len();
        info!("Roundtrip DC (full alphabet) of size {}", n);
        let mut mtf = super::MTF::new();
        // encoding with full alphabet
        let mut raw_dist = std::slice::from_elem(n, 0u);
        let pairs = super::encode(bytes, raw_dist, &mut mtf);
        let mut alphabet = std::slice::from_elem(0x100, n);
        for &(sym,dist) in pairs.iter() {
            alphabet[sym as uint] = dist;
        }
        let raw_iter = raw_dist.iter().filter(|&d| *d!=n);
        let distances: ~[&uint] = alphabet.iter().chain(raw_iter).collect();
        // decoding with full alphabet
        let mut decoded = std::slice::from_elem(n, 0 as super::Symbol);
        let mut di = 0u;
        super::decode(None, decoded.as_mut_slice(), &mut mtf, |_sym| {
            di += 1;
            Ok(distances[di-1].to_uint().unwrap())
        }).unwrap();
        // comparing with input
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn roundtrips_short() {
        roundtrip(bytes!("teeesst_dc"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("../data/test.txt"));
    }

    #[test]
    fn roundtrips_long() {
        let input: ~[u8] = std::iter::range_inclusive(0u8, 0xFFu8).collect();
        roundtrip_full_alphabet(input);
    }
}
<commit_msg>DC - unified encoding/decoding to be more symmetrical and use the new format<commit_after>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

# Links

http://www.data-compression.info/Algorithms/DC/

# Example

```rust
use compress::bwt::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple::<uint>(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::{io, iter};
use vec = std::slice;
use super::mtf::MTF;

pub type Symbol = u8;
pub type Rank = u8;
pub static TotalSymbols: uint = 0x100;

/// Distance coding context
/// Has all the information potentially needed by the underlying coding model
pub struct Context {
    /// current symbol
    symbol: Symbol,
    /// last known MTF rank
    last_rank: Rank,
    /// maximum possible distance
    distance_limit: uint,
}

impl Context {
    /// create a new distance context
    pub fn new(s: Symbol, r: Rank, dmax: uint) -> Context {
        Context {
            symbol: s,
            last_rank: r,
            distance_limit: dmax,
        }
    }
}

/// DC body iterator, can be used to encode distances
pub struct EncodeIterator<'a,'b,D> {
    data: iter::Enumerate<iter::Zip<vec::Items<'a,Symbol>,vec::Items<'b,D>>>,
    pos: [uint, ..TotalSymbols],
    size: uint,
}

impl<'a, 'b, D: NumCast> EncodeIterator<'a,'b,D> {
    /// create a new encode iterator
    pub fn new(input: &'a [Symbol], dist: &'b [D], init: [uint, ..TotalSymbols]) -> EncodeIterator<'a,'b,D> {
        assert_eq!(input.len(), dist.len());
        EncodeIterator {
            data: input.iter().zip(dist.iter()).enumerate(),
            pos: init,
            size: input.len()
        }
    }

    /// get the initial symbol positions, to be called before iteration
    pub fn get_init<'c>(&'c self) -> &'c [uint, ..TotalSymbols] {
        &self.pos
    }
}

impl<'a, 'b, D: Clone + Eq + NumCast> Iterator<(D,Context)> for EncodeIterator<'a,'b,D> {
    fn next(&mut self) -> Option<(D,Context)> {
        let filler: D = NumCast::from(self.size).unwrap();
        self.data.find(|&(_,(_,d))| *d != filler).map(|(i,(sym,d))| {
            let rank = i - self.pos[*sym as uint];
            assert!(rank < TotalSymbols);
            self.pos[*sym as uint] = i + d.to_uint().unwrap();
            (d.clone(), Context::new(*sym, rank as Rank, self.size-i))
        })
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode<'a, 'b, D: Clone + Copy + Eq + NumCast>(input: &'a [Symbol], distances: &'b mut [D], mtf: &mut MTF) -> EncodeIterator<'a,'b,D> {
    let n = input.len();
    assert_eq!(distances.len(), n);
    let mut num_unique = 0u;
    let mut last = [n, ..TotalSymbols];
    let mut init = [n, ..TotalSymbols];
    let filler: D = NumCast::from(n).unwrap();
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = filler.clone();
        let base = last[sym as uint];
        last[sym as uint] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == n {
            let rank = num_unique;
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            init[sym as uint] = i;
            num_unique += 1;
        }else {
            let rank = mtf.encode(sym) as uint;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = NumCast::from(i-base-rank-1).unwrap();
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(num_unique).iter().enumerate() {
        let base = last[sym as uint];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, n-base-rank-1);
        assert!(n >= base+rank+1);
        distances[base] = NumCast::from(n-base-rank-1).unwrap();
    }
    // a basic but expensive check, to be improved
    //assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
    //    position(|((&a,&b),d)| *d==filler && a!=b), None);
    EncodeIterator::new(input, distances, init)
}

/// encode with "batteries included" for quick testing
pub fn encode_simple<D: Clone + Copy + Eq + NumCast>(input: &[Symbol]) -> ~[D] {
    let n = input.len();
    let mut raw_dist: ~[D] = vec::from_elem(n, NumCast::from(0).unwrap());
    let mut eniter = encode(input, raw_dist, &mut MTF::new());
    let init: ~[D] = vec::from_fn(TotalSymbols, |i| NumCast::from(eniter.get_init()[i]).unwrap());
    init.iter().map(|d| d.clone()).chain(eniter.by_ref().map(|(d,_)| d)).collect()
}

/// Decode a block of distances given the initial symbol positions
pub fn decode(mut next: [uint,..TotalSymbols], output: &mut [Symbol], mtf: &mut MTF,
        fn_dist: |Context|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut i = 0u;
    for (sym,d) in next.iter().enumerate() {
        if *d < n {
            let mut j = i;
            while j>0u && next[mtf.symbols[j-1] as uint] > *d {
                mtf.symbols[j] = mtf.symbols[j-1];
                j -= 1;
            }
            mtf.symbols[j] = sym as Symbol;
            i += 1;
        }
    }
    if i<=1 {
        // redundant alphabet case
        let sym = mtf.symbols[0];
        for out in output.mut_iter()    {
            *out = sym;
        }
        return Ok(())
    }

    let alphabet_size = i;
    let mut ranks = [0 as Rank, ..TotalSymbols];
    for rank in range(0, i) {
        let sym = mtf.symbols[rank];
        debug!("\tRegistering symbol {} of rank {} at position {}",
            sym, rank, next[sym as uint]);
        ranks[sym as uint] = rank as Rank;
    }

    i = 0u;
    while i<n {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1] as uint];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let ctx = Context::new(sym, ranks[sym as uint], n-i);
        let future = match fn_dist(ctx) {
            Ok(d) => stop + d,
            Err(e) => return Err(e)
        };
        debug!("\t\tLooking for future position {}", future);
        assert!(future <= n);
        let mut rank = 1u;
        while rank < alphabet_size && future+rank > next[mtf.symbols[rank] as uint] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank < alphabet_size {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank] as uint]);
        }else {
            debug!("\t\tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym as uint] = future+rank-1;
        ranks[sym as uint] = rank as Rank;
    }
    assert_eq!(next.iter().position(|&d| d<n || d>=n+alphabet_size), None);
    assert_eq!(i, n);
    Ok(())
}

/// decode with "batteries included" for quick testing
pub fn decode_simple<D: ToPrimitive>(n: uint, distances: &[D]) -> ~[Symbol] {
    let mut output = vec::from_elem(n, 0 as Symbol);
    let mut init = [0u, ..TotalSymbols];
    for i in range(0, TotalSymbols) {
        init[i] = distances[i].to_uint().unwrap();
    }
    let mut di = TotalSymbols;
    decode(init, output.as_mut_slice(), &mut MTF::new(), |_ctx| {
        di += 1;
        if di > distances.len() {
            Err(io::standard_error(io::EndOfFile))
        }else {
            Ok(distances[di-1].to_uint().unwrap())
        }
    }).unwrap();
    output
}

#[cfg(test)]
mod test {
    fn roundtrip(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let distances = super::encode_simple::<uint>(bytes);
        debug!("Roundtrip DC input: {:?}, distances: {:?}", bytes, distances);
        let decoded = super::decode_simple(bytes.len(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn roundtrips() {
        roundtrip(bytes!("teeesst_dc"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("../data/test.txt"));
    }
}
<|endoftext|>


<commit_before>mod stdlib_names;

use itertools::{join, Itertools};

use ast::Expression;
use error::Error;
use stdlib::stdlib_names::*;
use table::Table;
use to_javascript::ToJavaScript;

type Callback = fn(String, &mut [Box<Expression>], &mut Stdlib) -> Result<String, Error>;

#[derive(Clone)]
pub struct Stdlib<'a> {
    pub function_table: Table<'a, Callback>,
    pub variable_table: Table<'a, String>,
    pub alias_map: Table<'a, String>,
}

impl<'a> Stdlib<'a> {
    pub fn new(function_table: Table<'a, Callback>, variable_table: Table<'a, String>, alias_map: Table<'a, String>) -> Stdlib<'a> {
        let mut stdlib = Stdlib {
            function_table,
            variable_table,
            alias_map,
        };

        stdlib.populate();

        stdlib
    }

    fn populate(&mut self) {
        self.function_table.insert(String::from("if"), builtin_if);

        self.function_table
            .insert(String::from("return"), builtin_return);

        self.function_table
            .insert(String::from("const"), builtin_binding);

        self.function_table
            .insert(String::from("var"), builtin_binding);

        self.function_table
            .insert(String::from("let"), builtin_binding);

        self.function_table
            .insert(String::from("function"), builtin_function_definition);

        self.function_table
            .insert(String::from("quote"), builtin_quote);

        self.function_table
            .insert(String::from("lambda"), builtin_lambda);

        self.function_table
            .insert(String::from("js"), builtin_raw_js);

        self.function_table.insert(String::from("nth"), builtin_nth);

        self.function_table
            .insert(String::from("defalias"), builtin_def_alias);

        self.alias_map.insert(
            String::from("map"),
            String::from("Array.prototype.map.call"),
        );

        self.alias_map.insert(
            String::from("forEach"),
            String::from("Array.prototype.forEach.call"),
        );

        self.alias_map.insert(
            String::from("filter"),
            String::from("Array.prototype.filter.call"),
        );

        self.alias_map
            .insert(String::from("define"), String::from("const"));

        self.alias_map
            .insert(String::from("defun"), String::from("function"));

        self.alias_map
            .insert(String::from("not"), String::from("!"));

        self.alias_map
            .insert(String::from("and"), String::from("&&"));

        self.alias_map
            .insert(String::from("or"), String::from("||"));

        self.alias_map
            .insert(String::from("="), String::from("==="));

        for generic in GENERIC_FUNCTION {
            self.function_table
                .insert(generic.to_string(), builtin_generic_function);
        }

        for (builtin, _) in self.alias_map.container.iter() {
            self.function_table
                .insert(builtin.to_string(), builtin_alias);
        }

        for binop in MATHS_BINOPS {
            self.function_table.insert(binop.to_string(), builtin_binop);
        }

        // Plus and minus are both binary and unary
        // But I have deemed binary to have a higher precedence, so binary goes first
        for logic in LOGIC_BINOPS {
            self.function_table.insert(logic.to_string(), builtin_binop);
        }

        for unary in UNARY_OPS {
            self.function_table.insert(unary.to_string(), builtin_unary);
        }
    }
}

fn builtin_if(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("if statement".to_string())),
        1 => Err(Error::too_few_arguments(
            "if statement condition".to_string(),
        )),
        2 => Ok(format!(
            "if ({}) {{ {} }}",
            args[0].eval(stdlib)?,
            args[1].eval(stdlib)?
        )),
        3 => Ok(format!(
            "if ({}) {{ {} }} else {{ {} }}",
            args[0].eval(stdlib)?,
            args[1].eval(stdlib)?,
            args[2].eval(stdlib)?
        )),
        // TODO: Add error message here
        _ => Err(Error::too_many_arguments(
            "unknown number of arguments supplied to if statement".to_string(),
        )),
    }
}

fn builtin_return(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("return".to_string())),
        1 => Ok(format!("return {}", args[0].eval(stdlib)?)),
        _ => Err(Error::too_many_arguments("return".to_string())),
    }
}

fn builtin_binding(
    name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    // TODO: Add name to the error messages
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("binding".to_string())),
        2 => {
            let (ident, value) = args.split_first_mut().unwrap();

            match ident {
                box Expression::Identifier(ref mut ident) => {
                    // TODO: Remove clones
                    stdlib
                        .variable_table
                        .insert(ident.value.clone(), ident.value.clone());

                    Ok(format!(
                        "{} {} = {}",
                        name,
                        ident.value.clone(),
                        value[0].eval(stdlib)?
                    ))
                }

                _ => Err(Error::invalid_expression(
                    "non-identifier given to binding".to_string(),
                )),
            }
        }
        _ => Err(Error::too_many_arguments("binding".to_string())),
    }
}
fn builtin_generic_function(
    name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    let args_fmt = join(
        args.into_iter()
            .map(|expr| expr.eval(stdlib))
            .fold_results(vec![], |mut i, expr| {
                i.push(expr);

                i
            })?,
        ",",
    );

    Ok(format!("{}({})", name, args_fmt))
}

fn builtin_alias(
    name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    // TODO: Remove clone
    match stdlib.alias_map.clone().get_mut(&name.clone()) {
        Some(name) => {
            stdlib.clone().function_table.get(name).unwrap()(name.to_string(), args, stdlib)
        }

        _ => Err(Error::undefined_func(name)),
    }
}

fn builtin_function_definition(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 | 2 => Err(Error::too_few_arguments("function definition".to_string())),
        3 => {
            let (name, rest) = args.split_first_mut().unwrap();

            let (args, body) = rest.split_first_mut().unwrap();

            match (args, name) {
                (box Expression::List(args_expr), box Expression::Identifier(func_name)) => {
                    // TODO: Remove clone
                    // Add the funciton to the parent variable table
                    stdlib
                        .variable_table
                        .insert(func_name.value.clone(), func_name.value.clone());

                    // Create a new child stdlib
                    // TODO: Remove clone
                    let mut stdlib =
                        Stdlib::new(
                            Table::new(Some(Box::new(&stdlib.function_table))),
                            Table::new(Some(Box::new(&stdlib.variable_table))),
                            stdlib.alias_map.clone());

                    let args_fmt = join(
                        args_expr
                                .value
                                // TODO: Remove .clone
                                .clone()
                                .into_iter()
                                // TODO: Remove unwrap
                                .map(|mut expr| {
                                    // TODO: Remove unwrap
                                    let expr_name = identifier_to_string(expr.clone()).unwrap();

                                    // TODO: Remove clones
                                    stdlib.variable_table.insert(expr_name.clone(),
                                        expr_name.clone());

                                    expr.eval(&mut stdlib)
                                })
                                .fold_results(vec![], |mut i, expr| {
                                    i.push(expr);

                                    i
                                })?,
                        ",",
                    );

                    Ok(format!(
                        "function {}({}){{ {}; }}",
                        func_name.value,
                        args_fmt,
                        body[0].eval(&mut stdlib)?
                    ))
                }
                (_, _) => Err(Error::invalid_expression(
                    "non list given to function binding".to_string(),
                )),
            }
        }
        _ => Err(Error::too_many_arguments("function definition".to_string())),
    }
}

fn builtin_quote(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    let args_fmt = join(
        args
        .into_iter()
        // TODO: Remove clone
        .map(|expr| expr.eval(stdlib))
        .fold_results(vec![], |mut i, expr| {
            i.push(expr);

            i
        })?,
        ",",
    );

    Ok(format!("\"[{}]\"", args_fmt))
}

fn builtin_lambda(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("lambda".to_string())),
        _ => {
            // TODO: Remove unwrap
            let (args, exprs) = args.split_first_mut().unwrap();

            // Create a new child stdlib
            // TODO: Remove clone
            let mut stdlib = Stdlib::new(
                Table::new(Some(Box::new(&stdlib.function_table))),
                Table::new(Some(Box::new(&stdlib.variable_table))),
                stdlib.alias_map.clone());

            match args {
                box Expression::List(list) => {
                    list.value.clone().into_iter().for_each(|expr| {
                        // TODO: Remove unwrap
                        //let expr_name = identifier_to_string(expr.clone()).unwrap();

                        let expr_name = expr.to_string();

                        stdlib
                            .variable_table
                            .insert(expr_name.clone(), expr_name.clone());
                    });

                    let args_fmt = list.value
                        .clone()
                        .into_iter()
                        .map(|arg| arg.to_string())
                        .collect::<Vec<String>>()
                        .join(",");

                    let exprs_fmt = join(
                        exprs
                            .into_iter()
                            .map(|expr| expr.eval(&mut stdlib))
                            .fold_results(vec![], |mut i, expr| {
                                i.push(expr);

                                i
                            })?,
                        ",",
                    );

                    Ok(format!("({}) => {{ {} }}", args_fmt, exprs_fmt))
                }
                _ => Err(Error::invalid_expression(
                    "non-list given to lambda expression".to_string(),
                )),
            }
        }
    }
}

fn builtin_raw_js(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("raw javascript".to_string())),
        _ => {
            let js_fmt = join(
                args.into_iter()
                    .map(|expr| expr.eval(stdlib))
                    .fold_results(vec![], |mut i, expr| {
                        i.push(expr);

                        i
                    })?,
                ";",
            );

            Ok(format!("eval({})", js_fmt))
        }
    }
}

fn builtin_nth(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("nth".to_string())),
        2 => {
            let (list, nth) = args.split_first_mut().unwrap();

            Ok(format!("{}[{}]", list.eval(stdlib)?, nth[0].eval(stdlib)?))
        }
        _ => Err(Error::too_many_arguments("nth".to_string())),
    }
}

fn builtin_def_alias(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("alias".to_string())),
        2 => {
            let mut function_name = args[0].eval(stdlib)?.clone();

            // Strip the quotes from the string
            function_name.retain(|c| c != '"');

            let mut alias = args[1].eval(stdlib)?.clone();

            // Strip the quotes from the string
            alias.retain(|c| c != '"');

            // We insert the alias into the map
            stdlib
                .alias_map
                .insert(alias.clone(), function_name.clone());

            // We add the alias into the function
            stdlib.function_table.insert(alias.clone(), builtin_alias);

            // The function being alised needs to be added as a generic function
            stdlib
                .function_table
                .insert(function_name.clone(), builtin_generic_function);

            // The function doesn't actually produce any output!
            Ok("".to_string())
        }
        _ => Err(Error::too_many_arguments("alias".to_string())),
    }
}

fn builtin_binop(
    op: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("binary operation".to_string())),
        1 => builtin_unary(op, args, stdlib),
        2 => {
            // This is messy _but_ it should make the match easier to understand
            match (args[0].clone(), args[1].clone()) {
                // Pre-calcuate if op an maths operation
                (box Expression::Number(ref l), box Expression::Number(ref r))
                    if MATHS_BINOPS.contains(&&*op) =>
                {
                    precalculate_numbers(op, l.value, r.value)
                }

                // TODO: Fix this
                (_, _) => Ok(format!(
                    "{}{}{}",
                    args[0].eval(stdlib)?,
                    op,
                    args[1].eval(stdlib)?
                )),
            }
        }
        _ => {
            let joined = join(
                args.into_iter()
                    .map(|expr| expr.eval(stdlib))
                    .fold_results(vec![], |mut i, expr| {
                        i.push(expr);

                        i
                    })?,
                &op,
            );

            Ok(joined)
        }
    }
}

fn builtin_unary(
    op: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match op.as_ref() {
        "+" | "-" | "!" | "++" | "--" | "~" => Ok(format!("{}{}", op, args[0].eval(stdlib)?)),

        // Unary operators which are words next an extra space.
        "typeof" | "delete" => Ok(format!("{} {}", op, args[0].eval(stdlib)?)),
        _ => Err(Error::too_few_arguments("unary operator".to_string())),
    }
}

fn identifier_to_string(expr: Box<Expression>) -> Option<String> {
    match expr {
        box Expression::Identifier(ident) => Some(ident.value),
        _ => None,
    }
}

/// Use to convert expressions contained within qoutes to a string without evaluating it
fn precalculate_numbers(op: String, left: f64, right: f64) -> Result<String, Error> {
    match op.as_ref() {
        "+" => Ok(format!("{}", left + right)),
        "-" => Ok(format!("{}", left - right)),
        "*" => Ok(format!("{}", left * right)),
        "/" if right != 0.0 => Ok(format!("{}", left / right)),
        "%" => Ok(format!("{}", left % right)),

        "/" => Err(Error::invalid_expression(
            "Divide by zero encountered on numeric literal binary operation".to_string(),
        )),

        // Assume divide by 0 here
        _ => Err(Error::invalid_expression(
            "Divide by zero encountered on numeric literal binary operation".to_string(),
        )),
    }
}
<commit_msg>Run cargo fmt<commit_after>mod stdlib_names;

use itertools::{join, Itertools};

use ast::Expression;
use error::Error;
use stdlib::stdlib_names::*;
use table::Table;
use to_javascript::ToJavaScript;

type Callback = fn(String, &mut [Box<Expression>], &mut Stdlib) -> Result<String, Error>;

#[derive(Clone)]
pub struct Stdlib<'a> {
    pub function_table: Table<'a, Callback>,
    pub variable_table: Table<'a, String>,
    pub alias_map: Table<'a, String>,
}

impl<'a> Stdlib<'a> {
    pub fn new(
        function_table: Table<'a, Callback>,
        variable_table: Table<'a, String>,
        alias_map: Table<'a, String>,
    ) -> Stdlib<'a> {
        let mut stdlib = Stdlib {
            function_table,
            variable_table,
            alias_map,
        };

        stdlib.populate();

        stdlib
    }

    fn populate(&mut self) {
        self.function_table.insert(String::from("if"), builtin_if);

        self.function_table
            .insert(String::from("return"), builtin_return);

        self.function_table
            .insert(String::from("const"), builtin_binding);

        self.function_table
            .insert(String::from("var"), builtin_binding);

        self.function_table
            .insert(String::from("let"), builtin_binding);

        self.function_table
            .insert(String::from("function"), builtin_function_definition);

        self.function_table
            .insert(String::from("quote"), builtin_quote);

        self.function_table
            .insert(String::from("lambda"), builtin_lambda);

        self.function_table
            .insert(String::from("js"), builtin_raw_js);

        self.function_table.insert(String::from("nth"), builtin_nth);

        self.function_table
            .insert(String::from("defalias"), builtin_def_alias);

        self.alias_map.insert(
            String::from("map"),
            String::from("Array.prototype.map.call"),
        );

        self.alias_map.insert(
            String::from("forEach"),
            String::from("Array.prototype.forEach.call"),
        );

        self.alias_map.insert(
            String::from("filter"),
            String::from("Array.prototype.filter.call"),
        );

        self.alias_map
            .insert(String::from("define"), String::from("const"));

        self.alias_map
            .insert(String::from("defun"), String::from("function"));

        self.alias_map
            .insert(String::from("not"), String::from("!"));

        self.alias_map
            .insert(String::from("and"), String::from("&&"));

        self.alias_map
            .insert(String::from("or"), String::from("||"));

        self.alias_map
            .insert(String::from("="), String::from("==="));

        for generic in GENERIC_FUNCTION {
            self.function_table
                .insert(generic.to_string(), builtin_generic_function);
        }

        for (builtin, _) in self.alias_map.container.iter() {
            self.function_table
                .insert(builtin.to_string(), builtin_alias);
        }

        for binop in MATHS_BINOPS {
            self.function_table.insert(binop.to_string(), builtin_binop);
        }

        // Plus and minus are both binary and unary
        // But I have deemed binary to have a higher precedence, so binary goes first
        for logic in LOGIC_BINOPS {
            self.function_table.insert(logic.to_string(), builtin_binop);
        }

        for unary in UNARY_OPS {
            self.function_table.insert(unary.to_string(), builtin_unary);
        }
    }
}

fn builtin_if(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("if statement".to_string())),
        1 => Err(Error::too_few_arguments(
            "if statement condition".to_string(),
        )),
        2 => Ok(format!(
            "if ({}) {{ {} }}",
            args[0].eval(stdlib)?,
            args[1].eval(stdlib)?
        )),
        3 => Ok(format!(
            "if ({}) {{ {} }} else {{ {} }}",
            args[0].eval(stdlib)?,
            args[1].eval(stdlib)?,
            args[2].eval(stdlib)?
        )),
        // TODO: Add error message here
        _ => Err(Error::too_many_arguments(
            "unknown number of arguments supplied to if statement".to_string(),
        )),
    }
}

fn builtin_return(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("return".to_string())),
        1 => Ok(format!("return {}", args[0].eval(stdlib)?)),
        _ => Err(Error::too_many_arguments("return".to_string())),
    }
}

fn builtin_binding(
    name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    // TODO: Add name to the error messages
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("binding".to_string())),
        2 => {
            let (ident, value) = args.split_first_mut().unwrap();

            match ident {
                box Expression::Identifier(ref mut ident) => {
                    // TODO: Remove clones
                    stdlib
                        .variable_table
                        .insert(ident.value.clone(), ident.value.clone());

                    Ok(format!(
                        "{} {} = {}",
                        name,
                        ident.value.clone(),
                        value[0].eval(stdlib)?
                    ))
                }

                _ => Err(Error::invalid_expression(
                    "non-identifier given to binding".to_string(),
                )),
            }
        }
        _ => Err(Error::too_many_arguments("binding".to_string())),
    }
}
fn builtin_generic_function(
    name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    let args_fmt = join(
        args.into_iter()
            .map(|expr| expr.eval(stdlib))
            .fold_results(vec![], |mut i, expr| {
                i.push(expr);

                i
            })?,
        ",",
    );

    Ok(format!("{}({})", name, args_fmt))
}

fn builtin_alias(
    name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    // TODO: Remove clone
    match stdlib.alias_map.clone().get_mut(&name.clone()) {
        Some(name) => {
            stdlib.clone().function_table.get(name).unwrap()(name.to_string(), args, stdlib)
        }

        _ => Err(Error::undefined_func(name)),
    }
}

fn builtin_function_definition(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 | 2 => Err(Error::too_few_arguments("function definition".to_string())),
        3 => {
            let (name, rest) = args.split_first_mut().unwrap();

            let (args, body) = rest.split_first_mut().unwrap();

            match (args, name) {
                (box Expression::List(args_expr), box Expression::Identifier(func_name)) => {
                    // TODO: Remove clone
                    // Add the funciton to the parent variable table
                    stdlib
                        .variable_table
                        .insert(func_name.value.clone(), func_name.value.clone());

                    // Create a new child stdlib
                    // TODO: Remove clone
                    let mut stdlib = Stdlib::new(
                        Table::new(Some(Box::new(&stdlib.function_table))),
                        Table::new(Some(Box::new(&stdlib.variable_table))),
                        stdlib.alias_map.clone(),
                    );

                    let args_fmt = join(
                        args_expr
                                .value
                                // TODO: Remove .clone
                                .clone()
                                .into_iter()
                                // TODO: Remove unwrap
                                .map(|mut expr| {
                                    // TODO: Remove unwrap
                                    let expr_name = identifier_to_string(expr.clone()).unwrap();

                                    // TODO: Remove clones
                                    stdlib.variable_table.insert(expr_name.clone(),
                                        expr_name.clone());

                                    expr.eval(&mut stdlib)
                                })
                                .fold_results(vec![], |mut i, expr| {
                                    i.push(expr);

                                    i
                                })?,
                        ",",
                    );

                    Ok(format!(
                        "function {}({}){{ {}; }}",
                        func_name.value,
                        args_fmt,
                        body[0].eval(&mut stdlib)?
                    ))
                }
                (_, _) => Err(Error::invalid_expression(
                    "non list given to function binding".to_string(),
                )),
            }
        }
        _ => Err(Error::too_many_arguments("function definition".to_string())),
    }
}

fn builtin_quote(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    let args_fmt = join(
        args
        .into_iter()
        // TODO: Remove clone
        .map(|expr| expr.eval(stdlib))
        .fold_results(vec![], |mut i, expr| {
            i.push(expr);

            i
        })?,
        ",",
    );

    Ok(format!("\"[{}]\"", args_fmt))
}

fn builtin_lambda(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("lambda".to_string())),
        _ => {
            // TODO: Remove unwrap
            let (args, exprs) = args.split_first_mut().unwrap();

            // Create a new child stdlib
            // TODO: Remove clone
            let mut stdlib = Stdlib::new(
                Table::new(Some(Box::new(&stdlib.function_table))),
                Table::new(Some(Box::new(&stdlib.variable_table))),
                stdlib.alias_map.clone(),
            );

            match args {
                box Expression::List(list) => {
                    list.value.clone().into_iter().for_each(|expr| {
                        // TODO: Remove unwrap
                        //let expr_name = identifier_to_string(expr.clone()).unwrap();

                        let expr_name = expr.to_string();

                        stdlib
                            .variable_table
                            .insert(expr_name.clone(), expr_name.clone());
                    });

                    let args_fmt = list.value
                        .clone()
                        .into_iter()
                        .map(|arg| arg.to_string())
                        .collect::<Vec<String>>()
                        .join(",");

                    let exprs_fmt = join(
                        exprs
                            .into_iter()
                            .map(|expr| expr.eval(&mut stdlib))
                            .fold_results(vec![], |mut i, expr| {
                                i.push(expr);

                                i
                            })?,
                        ",",
                    );

                    Ok(format!("({}) => {{ {} }}", args_fmt, exprs_fmt))
                }
                _ => Err(Error::invalid_expression(
                    "non-list given to lambda expression".to_string(),
                )),
            }
        }
    }
}

fn builtin_raw_js(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("raw javascript".to_string())),
        _ => {
            let js_fmt = join(
                args.into_iter()
                    .map(|expr| expr.eval(stdlib))
                    .fold_results(vec![], |mut i, expr| {
                        i.push(expr);

                        i
                    })?,
                ";",
            );

            Ok(format!("eval({})", js_fmt))
        }
    }
}

fn builtin_nth(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("nth".to_string())),
        2 => {
            let (list, nth) = args.split_first_mut().unwrap();

            Ok(format!("{}[{}]", list.eval(stdlib)?, nth[0].eval(stdlib)?))
        }
        _ => Err(Error::too_many_arguments("nth".to_string())),
    }
}

fn builtin_def_alias(
    _name: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 | 1 => Err(Error::too_few_arguments("alias".to_string())),
        2 => {
            let mut function_name = args[0].eval(stdlib)?.clone();

            // Strip the quotes from the string
            function_name.retain(|c| c != '"');

            let mut alias = args[1].eval(stdlib)?.clone();

            // Strip the quotes from the string
            alias.retain(|c| c != '"');

            // We insert the alias into the map
            stdlib
                .alias_map
                .insert(alias.clone(), function_name.clone());

            // We add the alias into the function
            stdlib.function_table.insert(alias.clone(), builtin_alias);

            // The function being alised needs to be added as a generic function
            stdlib
                .function_table
                .insert(function_name.clone(), builtin_generic_function);

            // The function doesn't actually produce any output!
            Ok("".to_string())
        }
        _ => Err(Error::too_many_arguments("alias".to_string())),
    }
}

fn builtin_binop(
    op: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match args.len() {
        0 => Err(Error::too_few_arguments("binary operation".to_string())),
        1 => builtin_unary(op, args, stdlib),
        2 => {
            // This is messy _but_ it should make the match easier to understand
            match (args[0].clone(), args[1].clone()) {
                // Pre-calcuate if op an maths operation
                (box Expression::Number(ref l), box Expression::Number(ref r))
                    if MATHS_BINOPS.contains(&&*op) =>
                {
                    precalculate_numbers(op, l.value, r.value)
                }

                // TODO: Fix this
                (_, _) => Ok(format!(
                    "{}{}{}",
                    args[0].eval(stdlib)?,
                    op,
                    args[1].eval(stdlib)?
                )),
            }
        }
        _ => {
            let joined = join(
                args.into_iter()
                    .map(|expr| expr.eval(stdlib))
                    .fold_results(vec![], |mut i, expr| {
                        i.push(expr);

                        i
                    })?,
                &op,
            );

            Ok(joined)
        }
    }
}

fn builtin_unary(
    op: String,
    args: &mut [Box<Expression>],
    stdlib: &mut Stdlib,
) -> Result<String, Error> {
    match op.as_ref() {
        "+" | "-" | "!" | "++" | "--" | "~" => Ok(format!("{}{}", op, args[0].eval(stdlib)?)),

        // Unary operators which are words next an extra space.
        "typeof" | "delete" => Ok(format!("{} {}", op, args[0].eval(stdlib)?)),
        _ => Err(Error::too_few_arguments("unary operator".to_string())),
    }
}

fn identifier_to_string(expr: Box<Expression>) -> Option<String> {
    match expr {
        box Expression::Identifier(ident) => Some(ident.value),
        _ => None,
    }
}

/// Use to convert expressions contained within qoutes to a string without evaluating it
fn precalculate_numbers(op: String, left: f64, right: f64) -> Result<String, Error> {
    match op.as_ref() {
        "+" => Ok(format!("{}", left + right)),
        "-" => Ok(format!("{}", left - right)),
        "*" => Ok(format!("{}", left * right)),
        "/" if right != 0.0 => Ok(format!("{}", left / right)),
        "%" => Ok(format!("{}", left % right)),

        "/" => Err(Error::invalid_expression(
            "Divide by zero encountered on numeric literal binary operation".to_string(),
        )),

        // Assume divide by 0 here
        _ => Err(Error::invalid_expression(
            "Divide by zero encountered on numeric literal binary operation".to_string(),
        )),
    }
}
<|endoftext|>


<commit_before>extern crate hyper;

use std::io::copy;
use std::sync::Mutex;

use self::hyper::net::Fresh;
use self::hyper::client::Client;
use self::hyper::client::RedirectPolicy;
use self::hyper::header::Connection;
use self::hyper::header::Host;
use self::hyper::server::Handler;
use self::hyper::server::Request;
use self::hyper::server::Response;
use self::hyper::uri::RequestUri::AbsolutePath;

use http::app_manager::AppManager;
use common::error::Error;

pub struct Dispatcher {
    pub app_manager: Mutex<AppManager>,
}

impl Dispatcher {
    pub fn new(app_manager: AppManager) -> Dispatcher {
        Dispatcher {
            app_manager: Mutex::new(app_manager),
        }
    }

    fn extract_app_name<'a>(&'a self, request: &'a Request) -> &str {
        let host = &request.headers.get::<Host>().unwrap().hostname;
        let host_parts = host.split(".").collect::<Vec<_>>();

        host_parts.first().unwrap()
    }

    fn ensure_app_running(&self, app_name: &str) -> Result<u16, Error> {
        let mut app_manager = self.app_manager.lock().unwrap();

        app_manager.ensure_app_running(&app_name)
    }

    fn forward_uri<'a>(&'a self, request: &'a Request) -> &str {
        match request.uri {
            AbsolutePath(ref value) => value,
            _ => panic!(),
        }
    }
}

impl Handler for Dispatcher {
    fn handle(&self, mut request: Request, mut response: Response<Fresh>) {
        let app_name = self.extract_app_name(&request).to_string();
        let result = self.ensure_app_running(&app_name);

        let port: u16;
        if result.is_ok() {
            port = result.unwrap();
        } else {
            response.send(b"App not configured").unwrap();
            return;
        }

        let uri = self.forward_uri(&request).to_string();

        let app_url = format!("http://localhost:{}{}", port, uri);

        let connection_header = match request.headers.get::<Connection>() {
            Some(value) => value.clone(),
            None => Connection::close(),
        };

        let mut client = Client::new();
        client.set_redirect_policy(RedirectPolicy::FollowNone);

        let mut app_response = client.request(request.method.clone(), &app_url)
            .headers(request.headers.clone())
            .header(Connection::close())
            .body(&mut request)
            .send().unwrap();

        *response.status_mut() = app_response.status.clone();

        response.headers_mut().clear();
        response.headers_mut().extend(app_response.headers.iter());
        response.headers_mut().set(connection_header);

        let mut stream = response.start().unwrap();
        copy(&mut app_response, &mut stream).unwrap();
        stream.end().unwrap();
    }
}
<commit_msg>refactor: Use more idiomatic error handling<commit_after>extern crate hyper;

use std::io::copy;
use std::sync::Mutex;

use self::hyper::net::Fresh;
use self::hyper::client::Client;
use self::hyper::client::RedirectPolicy;
use self::hyper::header::Connection;
use self::hyper::header::Host;
use self::hyper::server::Handler;
use self::hyper::server::Request;
use self::hyper::server::Response;
use self::hyper::uri::RequestUri::AbsolutePath;

use http::app_manager::AppManager;
use common::error::Error;

pub struct Dispatcher {
    pub app_manager: Mutex<AppManager>,
}

impl Dispatcher {
    pub fn new(app_manager: AppManager) -> Dispatcher {
        Dispatcher {
            app_manager: Mutex::new(app_manager),
        }
    }

    fn extract_app_name<'a>(&'a self, request: &'a Request) -> &str {
        let host = &request.headers.get::<Host>().unwrap().hostname;
        let host_parts = host.split(".").collect::<Vec<_>>();

        host_parts.first().unwrap()
    }

    fn ensure_app_running(&self, app_name: &str) -> Result<u16, Error> {
        let mut app_manager = self.app_manager.lock().unwrap();

        app_manager.ensure_app_running(&app_name)
    }

    fn forward_uri<'a>(&'a self, request: &'a Request) -> &str {
        match request.uri {
            AbsolutePath(ref value) => value,
            _ => panic!(),
        }
    }
}

impl Handler for Dispatcher {
    fn handle(&self, mut request: Request, mut response: Response<Fresh>) {
        let app_name = self.extract_app_name(&request).to_string();
        let result = self.ensure_app_running(&app_name);

        let port = match result {
            Ok(value) => value,
            Err(_) => {
                response.send(b"App not configured").unwrap();
                return;
            },
        };

        let uri = self.forward_uri(&request).to_string();

        let app_url = format!("http://localhost:{}{}", port, uri);

        let connection_header = match request.headers.get::<Connection>() {
            Some(value) => value.clone(),
            None => Connection::close(),
        };

        let mut client = Client::new();
        client.set_redirect_policy(RedirectPolicy::FollowNone);

        let mut app_response = client.request(request.method.clone(), &app_url)
            .headers(request.headers.clone())
            .header(Connection::close())
            .body(&mut request)
            .send().unwrap();

        *response.status_mut() = app_response.status.clone();

        response.headers_mut().clear();
        response.headers_mut().extend(app_response.headers.iter());
        response.headers_mut().set(connection_header);

        let mut stream = response.start().unwrap();
        copy(&mut app_response, &mut stream).unwrap();
        stream.end().unwrap();
    }
}
<|endoftext|>


<commit_before>//! Lambda encoding for byte strings

use lambda_calculus::term::*;
use lambda_calculus::booleans::{tru, fls};
use std::char;

/// Decode lambda-encoded data as a `String`.
///
/// # Example
/// ```
/// use blc::binary_encoding::from_binary;
/// use blc::lambda_encoding::decode;
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(decode(k.unwrap()), "(λλ2)");
/// ```
pub fn decode(term: Term) -> String {
    if term == fls() {
        "".into()
    } else if term.is_list() && term.head_ref().unwrap().is_list() {
        let (head, tail) = term.uncons().unwrap(); // safe, ensured by is_list
        let terms: Vec<Term> = head.into_iter().collect();
        let bits = terms
            .into_iter()
            .map(|t| (t
                .unabs()
                .and_then(|t| t.unabs())
                .and_then(|t| t.unvar())
                .unwrap() - 1) as u8
            ).collect::<Vec<u8>>();
        let byte = !bits.iter().fold(0, |acc, &b| acc * 2 + b);
        let chr = char::from(byte);
        chr.to_string() + &decode(tail)
    } else if term.head_ref() == Ok(&fls()) {
        "1".to_string() + &decode(term.tail().unwrap())
    } else if term.head_ref() == Ok(&tru()) {
        "0".to_string() + &decode(term.tail().unwrap())
    } else {
        format!("({})", term)
    }
}

fn encode_byte(byte: u8) -> Term {
    let bitstr = format!("{:08b}", byte);
    let bits = bitstr.as_bytes();
    Term::from(bits.into_iter().map(|&bit| encode_bit(bit)).collect::<Vec<Term>>())
}

fn encode_bit(bit: u8) -> Term {
    match bit {
        b'0' => tru(),
        b'1' => fls(),
        _ => unreachable!()
    }
}

/// Encode bytes as a lambda `Term`.
///
/// # Example
/// ```
/// use blc::lambda_encoding::encode;
///
/// assert_eq!(&*format!("{}", encode(b"a")),
///     "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
/// ```
pub fn encode(input: &[u8]) -> Term {
    Term::from(input.into_iter().map(|&b| encode_byte(b)).collect::<Vec<Term>>())
}

#[cfg(test)]
mod test {
    use super::*;
    use binary_encoding::from_binary;
    use std::str;

    #[test]
    fn encoding_lambda() {
        assert_eq!(&*format!("{}", encode(b"0")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"1")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"a")),
            "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
    }

    #[test]
    fn decoding() {
        let k =     from_binary(b"0000110").unwrap();
        let s =     from_binary(b"00000001011110100111010").unwrap();
        let quine = from_binary(b"000101100100011010000000000001011\
                                  011110010111100111111011111011010").unwrap();

        assert_eq!(decode(k),     "(λλ2)");
        assert_eq!(decode(s),     "(λλλ31(21))");
        assert_eq!(decode(quine), "(λ1((λ11)(λλλλλ14(3(55)2)))1)");
    }

    #[test]
    fn decode_encode_lambda() {
        assert_eq!(decode(encode(b"herp derp")),             "herp derp");
        assert_eq!(decode(encode(b"0111010101011")),         "0111010101011");
        assert_eq!(decode(encode(b"01zeros110and1ones101")), "01zeros110and1ones101");
        assert_eq!(decode(encode(b"\0(1)")),                 "\0(1)");
    }
}
<commit_msg>split off decode_byte() from decode()<commit_after>//! Lambda encoding for byte strings

use lambda_calculus::term::*;
use lambda_calculus::booleans::{tru, fls};
use std::char;

/// Decode lambda-encoded data as a `String`.
///
/// # Example
/// ```
/// use blc::binary_encoding::from_binary;
/// use blc::lambda_encoding::decode;
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(decode(k.unwrap()), "(λλ2)");
/// ```
pub fn decode(term: Term) -> String {
    if term == fls() {
        "".into()
    } else if term.is_list() && term.head_ref().unwrap().is_list() {
        let (head, tail) = term.uncons().unwrap(); // safe, ensured by is_list
        let byte = decode_byte(head);
        let chr = char::from(byte);
        chr.to_string() + &decode(tail)
    } else if term.head_ref() == Ok(&fls()) {
        "1".to_string() + &decode(term.tail().unwrap())
    } else if term.head_ref() == Ok(&tru()) {
        "0".to_string() + &decode(term.tail().unwrap())
    } else {
        format!("({})", term)
    }
}

fn decode_byte(encoded_byte: Term) -> u8 {
    let bits = encoded_byte
        .into_iter()
        .map(|t| (t
            .unabs()
            .and_then(|t| t.unabs())
            .and_then(|t| t.unvar())
            .expect("not a lambda-encoded byte!") - 1) as u8
        );

    !bits.fold(0, |acc, b| acc * 2 + b)
}

fn encode_byte(byte: u8) -> Term {
    let bitstr = format!("{:08b}", byte);
    let bits = bitstr.as_bytes();
    Term::from(bits.into_iter().map(|&bit| encode_bit(bit)).collect::<Vec<Term>>())
}

fn encode_bit(bit: u8) -> Term {
    match bit {
        b'0' => tru(),
        b'1' => fls(),
        _ => unreachable!()
    }
}

/// Encode bytes as a lambda `Term`.
///
/// # Example
/// ```
/// use blc::lambda_encoding::encode;
///
/// assert_eq!(&*format!("{}", encode(b"a")),
///     "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
/// ```
pub fn encode(input: &[u8]) -> Term {
    Term::from(input.into_iter().map(|&b| encode_byte(b)).collect::<Vec<Term>>())
}

#[cfg(test)]
mod test {
    use super::*;
    use binary_encoding::from_binary;
    use std::str;

    #[test]
    fn encoding_lambda() {
        assert_eq!(&*format!("{}", encode(b"0")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"1")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"a")),
            "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
    }

    #[test]
    fn decoding() {
        let k =     from_binary(b"0000110").unwrap();
        let s =     from_binary(b"00000001011110100111010").unwrap();
        let quine = from_binary(b"000101100100011010000000000001011\
                                  011110010111100111111011111011010").unwrap();

        assert_eq!(decode(k),     "(λλ2)");
        assert_eq!(decode(s),     "(λλλ31(21))");
        assert_eq!(decode(quine), "(λ1((λ11)(λλλλλ14(3(55)2)))1)");
    }

    #[test]
    fn decode_encode_lambda() {
        assert_eq!(decode(encode(b"herp derp")),             "herp derp");
        assert_eq!(decode(encode(b"0111010101011")),         "0111010101011");
        assert_eq!(decode(encode(b"01zeros110and1ones101")), "01zeros110and1ones101");
        assert_eq!(decode(encode(b"\0(1)")),                 "\0(1)");
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use std::time::{SystemTime, UNIX_EPOCH};
use coreutils::{ArgParser, Flag};
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{date} */ r#"
NAME
    date - prints the system time

SYNOPSIS
    date [ -h | --help]

DESCRIPTION
    Prints the system time and date

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

// Sweet algorithm from http://ptspts.blogspot.com/2009/11/how-to-convert-unix-timestamp-to-civil.html
// TODO: Apply timezone offset
fn format_time(mut ts: i64) -> String {
    let s = ts%86400;
    ts /= 86400;
    let h = s/3600;
    let m = s/60%60;
    let s = s%60;
    let x = (ts*4+102032)/146097+15;
    let b = ts+2442113+x-(x/4);
    let mut c = (b*20-2442)/7305;
    let d = b-365*c-c/4;
    let mut e = d*1000/30601;
    let f = d-e*30-e*601/1000;
    if e < 14 {
        c -= 4716;
        e -= 1;
    } else {
        c -= 4715;
        e -= 13;
    }
    format!("{:<04}-{:<02}-{:<02} {:<02}:{:<02}:{:<02}", c, e, f, h, m, s)
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.enabled_flag(Flag::Long("help")) {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut tz_offset = 0;
    for arg in &parser.args {
        if let Ok(offset) = arg.parse::<i64>() {
            tz_offset = offset;
        }
    }

    let tz_name = if tz_offset == 0 {
        format!("UTC")
    } else if tz_offset > 0 {
        format!("UTC+{:>02}", tz_offset)
    } else {
        format!("UTC-{:>02}", -tz_offset)
    };

    let time = SystemTime::now();
    let duration = time.duration_since(UNIX_EPOCH).try(&mut stderr);
    let mut ts = duration.as_secs() as i64;
    ts += tz_offset * 3600;

    stdout.write(format!("{} {}\n", format_time(ts), tz_name).as_bytes()).try(&mut stderr);
}
<commit_msg>Fix padding<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use std::time::{SystemTime, UNIX_EPOCH};
use coreutils::{ArgParser, Flag};
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{date} */ r#"
NAME
    date - prints the system time

SYNOPSIS
    date [ -h | --help]

DESCRIPTION
    Prints the system time and date

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

// Sweet algorithm from http://ptspts.blogspot.com/2009/11/how-to-convert-unix-timestamp-to-civil.html
// TODO: Apply timezone offset
fn format_time(mut ts: i64) -> String {
    let s = ts%86400;
    ts /= 86400;
    let h = s/3600;
    let m = s/60%60;
    let s = s%60;
    let x = (ts*4+102032)/146097+15;
    let b = ts+2442113+x-(x/4);
    let mut c = (b*20-2442)/7305;
    let d = b-365*c-c/4;
    let mut e = d*1000/30601;
    let f = d-e*30-e*601/1000;
    if e < 14 {
        c -= 4716;
        e -= 1;
    } else {
        c -= 4715;
        e -= 13;
    }
    format!("{:>04}-{:>02}-{:>02} {:>02}:{:>02}:{:>02}", c, e, f, h, m, s)
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.enabled_flag(Flag::Long("help")) {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut tz_offset = 0;
    for arg in &parser.args {
        if let Ok(offset) = arg.parse::<i64>() {
            tz_offset = offset;
        }
    }

    let tz_name = if tz_offset == 0 {
        format!("UTC")
    } else if tz_offset > 0 {
        format!("UTC+{:>02}", tz_offset)
    } else {
        format!("UTC-{:>02}", -tz_offset)
    };

    let time = SystemTime::now();
    let duration = time.duration_since(UNIX_EPOCH).try(&mut stderr);
    let mut ts = duration.as_secs() as i64;
    ts += tz_offset * 3600;

    stdout.write(format!("{} {}\n", format_time(ts), tz_name).as_bytes()).try(&mut stderr);
}
<|endoftext|>