<commit_before>//! rust-analyzer is lazy and doesn't compute anything unless asked. This
//! sometimes is counter productive when, for example, the first goto definition
//! request takes longer to compute. This modules implemented prepopulation of
//! various caches, it's not really advanced at the moment.

use hir::db::DefDatabase;
use ide_db::base_db::{CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt};
use rustc_hash::FxHashSet;

use crate::RootDatabase;

/// We started indexing a crate.
#[derive(Debug)]
pub struct PrimeCachesProgress {
    pub on_crate: String,
    pub n_done: usize,
    pub n_total: usize,
}

pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) {
    let _p = profile::span("prime_caches");
    let graph = db.crate_graph();
    // We're only interested in the transitive dependencies of all workspace crates.
    let to_prime: FxHashSet<_> = graph
        .iter()
        .filter(|&id| {
            let file_id = graph[id].root_file_id;
            let root_id = db.file_source_root(file_id);
            !db.source_root(root_id).is_library
        })
        .flat_map(|id| graph.transitive_deps(id))
        .collect();

    let topo = toposort(&graph, &to_prime);

    // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
    // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
    // cancellation, so we cannot use rayon.
    for (i, &crate_id) in topo.iter().enumerate() {
        let crate_name = graph[crate_id].display_name.as_deref().unwrap_or_default().to_string();

        cb(PrimeCachesProgress { on_crate: crate_name, n_done: i, n_total: topo.len() });
        db.crate_def_map(crate_id);
        db.import_map(crate_id);
    }
}

fn toposort(graph: &CrateGraph, crates: &FxHashSet<CrateId>) -> Vec<CrateId> {
    // Just subset the full topologically sorted set for simplicity.

    let all = graph.crates_in_topological_order();
    let mut result = Vec::with_capacity(crates.len());
    for krate in all {
        if crates.contains(&krate) {
            result.push(krate);
        }
    }
    result
}
<commit_msg>Only prime direct dependencies of the workspace crates<commit_after>//! rust-analyzer is lazy and doesn't compute anything unless asked. This
//! sometimes is counter productive when, for example, the first goto definition
//! request takes longer to compute. This modules implemented prepopulation of
//! various caches, it's not really advanced at the moment.

use hir::db::DefDatabase;
use ide_db::base_db::{SourceDatabase, SourceDatabaseExt};
use rustc_hash::FxHashSet;

use crate::RootDatabase;

/// We started indexing a crate.
#[derive(Debug)]
pub struct PrimeCachesProgress {
    pub on_crate: String,
    pub n_done: usize,
    pub n_total: usize,
}

pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) {
    let _p = profile::span("prime_caches");
    let graph = db.crate_graph();
    // We're only interested in the workspace crates and the `ImportMap`s of their direct
    // dependencies, though in practice the latter also compute the `DefMap`s.
    // We don't prime transitive dependencies because they're generally not visible in
    // the current workspace.
    let to_prime: FxHashSet<_> = graph
        .iter()
        .filter(|&id| {
            let file_id = graph[id].root_file_id;
            let root_id = db.file_source_root(file_id);
            !db.source_root(root_id).is_library
        })
        .flat_map(|id| graph[id].dependencies.iter().map(|krate| krate.crate_id))
        .collect();

    // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
    // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
    // cancellation, so we cannot use rayon.
    let n_total = to_prime.len();
    for (n_done, &crate_id) in to_prime.iter().enumerate() {
        let crate_name = graph[crate_id].display_name.as_deref().unwrap_or_default().to_string();

        cb(PrimeCachesProgress { on_crate: crate_name, n_done, n_total });
        // This also computes the DefMap
        db.import_map(crate_id);
    }
}
<|endoftext|>


<commit_before>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

use super::{AsNapiObject, NapiValue, NapiValueInternal};

#[derive(Clone, Copy, Debug)]
pub struct NapiArray<'a> {
    value: sys::napi_value,
    env: &'a NapiEnv,
}

impl<'a> NapiArray<'a> {
    pub fn new(env: &'a NapiEnv) -> NapiResult<Self> {
        let mut value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_array(env.as_sys_env(), &mut value)
        })?;

        Ok(Self { value, env })
    }

    pub fn with_len(env: &'a NapiEnv, len: usize) -> NapiResult<Self> {
        let mut value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_array_with_length(
                env.as_sys_env(),
                len,
                &mut value,
            )
        })?;

        Ok(Self { value, env })
    }

    pub fn len(&self) -> NapiResult<u32> {
        let mut result = 0;

        self.env.handle_status(unsafe {
            sys::napi_get_array_length(
                self.env.as_sys_env(),
                self.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }
}

impl<'a> NapiValue for NapiArray<'a> {
    fn as_sys_value(&self) -> sys::napi_value {
        self.value
    }

    fn env(&self) -> &NapiEnv {
        self.env
    }
}

impl<'a> NapiValueInternal<'a> for NapiArray<'a> {
    fn construct(env: &'a NapiEnv, value: sys::napi_value) -> Self {
        Self { env, value }
    }
}

impl<'a> AsNapiObject for NapiArray<'a> {}
<commit_msg>feat(napi): implement NapiArray::is_empty<commit_after>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

use super::{AsNapiObject, NapiValue, NapiValueInternal};

#[derive(Clone, Copy, Debug)]
pub struct NapiArray<'a> {
    value: sys::napi_value,
    env: &'a NapiEnv,
}

impl<'a> NapiArray<'a> {
    pub fn new(env: &'a NapiEnv) -> NapiResult<Self> {
        let mut value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_array(env.as_sys_env(), &mut value)
        })?;

        Ok(Self { value, env })
    }

    pub fn with_len(env: &'a NapiEnv, len: usize) -> NapiResult<Self> {
        let mut value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_array_with_length(
                env.as_sys_env(),
                len,
                &mut value,
            )
        })?;

        Ok(Self { value, env })
    }

    pub fn len(&self) -> NapiResult<u32> {
        let mut result = 0;

        self.env.handle_status(unsafe {
            sys::napi_get_array_length(
                self.env.as_sys_env(),
                self.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }

    pub fn is_empty(&self) -> NapiResult<bool> {
        self.len().map(|l| l == 0)
    }
}

impl<'a> NapiValue for NapiArray<'a> {
    fn as_sys_value(&self) -> sys::napi_value {
        self.value
    }

    fn env(&self) -> &NapiEnv {
        self.env
    }
}

impl<'a> NapiValueInternal<'a> for NapiArray<'a> {
    fn construct(env: &'a NapiEnv, value: sys::napi_value) -> Self {
        Self { env, value }
    }
}

impl<'a> AsNapiObject for NapiArray<'a> {}
<|endoftext|>


<commit_before>use block::Block;
use block::Block::{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y};

use fragments::Fragment;
use fragments::{arc, line};

use point_block::PointBlock;
use properties::Properties;

pub fn box_drawing(ch: &char) -> (Vec<Block>, Vec<Fragment>) {
    let a = &PointBlock::block(A);
    let b = &PointBlock::block(B);
    let c = &PointBlock::block(C);
    let d = &PointBlock::block(D);
    let e = &PointBlock::block(E);
    let _f = &PointBlock::block(F);
    let _g = &PointBlock::block(G);
    let h = &PointBlock::block(H);
    let _i = &PointBlock::block(I);
    let _j = &PointBlock::block(J);
    let k = &PointBlock::block(K);
    let l = &PointBlock::block(L);
    let m = &PointBlock::block(M);
    let n = &PointBlock::block(N);
    let o = &PointBlock::block(O);
    let p = &PointBlock::block(P);
    let q = &PointBlock::block(Q);
    let r = &PointBlock::block(R);
    let s = &PointBlock::block(S);
    let t = &PointBlock::block(T);
    let u = &PointBlock::block(U);
    let v = &PointBlock::block(V);
    let w = &PointBlock::block(W);
    let x = &PointBlock::block(X);
    let y = &PointBlock::block(Y);
    //////////////////////////////
    //
    //  Static are all Strong signal
    //  and are used Box Drawing
    //
    ////////////////////////////////
    if ch.in_any(vec!['─', '━']) {
        (vec![K, O], vec![line(k, o)])
    } else if ch.is('¯') {
        // overscore?
        (vec![A, E], vec![line(a, e)])
    } else if ch.is('│') {
        (vec![C, W], vec![line(c, w)])
    } else if ch.is('┃') {
        (vec![E, Y], vec![line(e, y)])
    } else if ch.is('╭') {
        (vec![O, W], vec![arc(o, r, 2), line(r, w)])
    } else if ch.any("┌┍┎┏") {
        (vec![W, O], vec![line(m, w), line(m, o)])
    } else if ch.is('╮') {
        (vec![K, W], vec![line(w, r), arc(r, k, 2)])
    } else if ch.any("┐┑┒┓") {
        (vec![W, K], vec![line(m, w), line(m, k)])
    } else if ch.is('╰') {
        (vec![C, O], vec![line(c, h), arc(h, o, 2)])
    } else if ch.any("┗└┕┖") {
        (vec![C, O], vec![line(m, c), line(m, o)])
    } else if ch.is('╯') {
        (vec![C, K], vec![line(c, h), arc(k, h, 2)])
    } else if ch.any("┘┙┚┛") {
        (vec![C, K], vec![line(m, c), line(m, k)])
    } else if ch.any("┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋") {
        (
            vec![C, W, K, O],
            vec![line(m, c), line(m, w), line(m, k), line(m, o)],
        )
    } else if ch.any("┬┭┮┯┰┱┲┳") {
        (vec![W, K, O], vec![line(m, w), line(m, k), line(m, o)])
    } else if ch.any("┴┵┶┷┸┹┺┻") {
        (vec![C, K, O], vec![line(m, c), line(m, k), line(m, o)])
    } else if ch.any("├┝┞┟┠┡┢┣") {
        (vec![C, W, O], vec![line(m, c), line(m, w), line(m, o)])
    } else if ch.any("┤┥┦┧┨┩┪┫") {
        (vec![C, W, K], vec![line(m, c), line(m, w), line(m, k)])
    } else if ch.is('║') {
        (
            vec![B, V, D, X],
            vec![line(b, v), line(v, b), line(d, x), line(x, d)],
        )
    } else if ch.is('═') {
        (vec![K, O, P, T], vec![line(k, o), line(k, o), line(p, t)])
    } else if ch.is('╔') {
        (
            vec![O, V, T, X],
            vec![line(o, l), line(l, v), line(t, s), line(s, x)],
        )
    } else if ch.is('╗') {
        (
            vec![K, X, P, V],
            vec![line(k, n), line(n, x), line(p, q), line(q, v)],
        )
    } else if ch.is('╚') {
        (
            vec![B, T, D, O],
            vec![line(b, q), line(q, t), line(d, n), line(n, o)],
        )
    } else if ch.is('╝') {
        (
            vec![P, K, B, D],
            vec![line(p, s), line(s, d), line(k, l), line(l, b)],
        )
    } else if ch.is('╒') {
        (vec![W, O, T], vec![line(m, w), line(m, o), line(r, t)])
    } else if ch.is('╓') {
        (vec![O, V, X], vec![line(l, o), line(l, v), line(n, x)])
    } else if ch.is('╬') {
        (
            vec![B, D, V, X, K, P, O, T],
            vec![
                line(b, l),
                line(l, k),
                line(p, q),
                line(q, v),
                line(d, n),
                line(n, o),
                line(t, s),
                line(s, x),
            ],
        )
    } else if ch.is('╦') {
        (
            vec![K, O, P, V, T, X],
            vec![line(k, o), line(p, q), line(q, v), line(t, s), line(s, x)],
        )
    } else if ch.is('╩') {
        (
            vec![P, T, K, B, D, O],
            vec![line(p, t), line(k, l), line(l, b), line(d, n), line(n, o)],
        )
    } else if ch.is('╠') {
        (
            vec![B, V, D, O, T, X],
            vec![line(b, v), line(d, n), line(n, o), line(t, s), line(s, x)],
        )
    } else if ch.is('╣') {
        (
            vec![D, X, B, K, P, V],
            vec![line(d, x), line(b, l), line(l, k), line(p, q), line(q, v)],
        )
    } else if ch.is('╱') {
        (vec![U, E], vec![line(u, e)])
    } else if ch.is('╲') {
        (vec![A, Y], vec![line(a, y)])
    } else if ch.is('╳') {
        (vec![A, Y, U, E], vec![line(a, y), line(u, e)])
    } else if ch.is('╒') {
        (vec![W, O, T], vec![line(m, w), line(m, o), line(r, t)])
    } else if ch.is('╓') {
        (vec![O, V, X], vec![line(l, o), line(l, v), line(n, x)])
    } else if ch.is('╞') {
        (vec![C, W, O, T], vec![line(c, w), line(m, o), line(r, t)])
    } else if ch.is('╡') {
        (vec![W, C, K, P], vec![line(c, w), line(k, m), line(p, r)])
    } else if ch.is('╤') {
        (
            vec![K, O, P, T, W],
            vec![line(k, o), line(p, t), line(r, w)],
        )
    } else if ch.is('╥') {
        (vec![K, O, V, X], vec![line(k, o), line(l, v), line(n, x)])
    } else if ch.is('╖') {
        (vec![K, X, V], vec![line(k, n), line(n, x), line(l, v)])
    } else if ch.is('╙') {
        (vec![O, B, D], vec![line(l, o), line(l, b), line(n, d)])
    } else if ch.is('╜') {
        (vec![K, B, D], vec![line(k, n), line(l, b), line(n, d)])
    } else if ch.is('╕') {
        (vec![W, K, P], vec![line(m, w), line(k, m), line(p, r)])
    } else if ch.is('╛') {
        (vec![C, P, K], vec![line(c, r), line(r, p), line(k, m)])
    } else if ch.is('╘') {
        (vec![C, O, T], vec![line(c, r), line(m, o), line(r, t)])
    } else if ch.is('╢') {
        (
            vec![D, B, K, V, X],
            vec![line(d, x), line(b, v), line(k, l)],
        )
    } else if ch.is('╟') {
        (
            vec![D, X, B, V, O],
            vec![line(d, x), line(b, v), line(n, o)],
        )
    } else if ch.is('╪') {
        (
            vec![C, W, K, O, P, T],
            vec![line(c, w), line(k, o), line(p, t)],
        )
    } else if ch.is('╧') {
        (
            vec![K, O, P, T, C],
            vec![line(k, o), line(p, t), line(c, m)],
        )
    } else if ch.is('╫') {
        (
            vec![K, O, B, V, D, X],
            vec![line(k, o), line(b, v), line(d, x)],
        )
    } else if ch.is('╨') {
        (vec![K, O, B, D], vec![line(k, o), line(b, l), line(d, n)])
    } else {
        (vec![], vec![])
    }
}
<commit_msg>Fix vertical line box drawing<commit_after>use block::Block;
use block::Block::{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y};

use fragments::Fragment;
use fragments::{arc, line};

use point_block::PointBlock;
use properties::Properties;

pub fn box_drawing(ch: &char) -> (Vec<Block>, Vec<Fragment>) {
    let a = &PointBlock::block(A);
    let b = &PointBlock::block(B);
    let c = &PointBlock::block(C);
    let d = &PointBlock::block(D);
    let e = &PointBlock::block(E);
    let _f = &PointBlock::block(F);
    let _g = &PointBlock::block(G);
    let h = &PointBlock::block(H);
    let _i = &PointBlock::block(I);
    let _j = &PointBlock::block(J);
    let k = &PointBlock::block(K);
    let l = &PointBlock::block(L);
    let m = &PointBlock::block(M);
    let n = &PointBlock::block(N);
    let o = &PointBlock::block(O);
    let p = &PointBlock::block(P);
    let q = &PointBlock::block(Q);
    let r = &PointBlock::block(R);
    let s = &PointBlock::block(S);
    let t = &PointBlock::block(T);
    let u = &PointBlock::block(U);
    let v = &PointBlock::block(V);
    let w = &PointBlock::block(W);
    let x = &PointBlock::block(X);
    let y = &PointBlock::block(Y);
    //////////////////////////////
    //
    //  Static are all Strong signal
    //  and are used Box Drawing
    //
    ////////////////////////////////
    if ch.in_any(vec!['─', '━']) {
        (vec![K, O], vec![line(k, o)])
    } else if ch.is('¯') {
        // overscore?
        (vec![A, E], vec![line(a, e)])
    } else if ch.is('│') {
        (vec![C, W], vec![line(c, w)])
    } else if ch.is('┃') {
        (vec![E, Y], vec![line(c, w)])
    } else if ch.is('╭') {
        (vec![O, W], vec![arc(o, r, 2), line(r, w)])
    } else if ch.any("┌┍┎┏") {
        (vec![W, O], vec![line(m, w), line(m, o)])
    } else if ch.is('╮') {
        (vec![K, W], vec![line(w, r), arc(r, k, 2)])
    } else if ch.any("┐┑┒┓") {
        (vec![W, K], vec![line(m, w), line(m, k)])
    } else if ch.is('╰') {
        (vec![C, O], vec![line(c, h), arc(h, o, 2)])
    } else if ch.any("┗└┕┖") {
        (vec![C, O], vec![line(m, c), line(m, o)])
    } else if ch.is('╯') {
        (vec![C, K], vec![line(c, h), arc(k, h, 2)])
    } else if ch.any("┘┙┚┛") {
        (vec![C, K], vec![line(m, c), line(m, k)])
    } else if ch.any("┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋") {
        (
            vec![C, W, K, O],
            vec![line(m, c), line(m, w), line(m, k), line(m, o)],
        )
    } else if ch.any("┬┭┮┯┰┱┲┳") {
        (vec![W, K, O], vec![line(m, w), line(m, k), line(m, o)])
    } else if ch.any("┴┵┶┷┸┹┺┻") {
        (vec![C, K, O], vec![line(m, c), line(m, k), line(m, o)])
    } else if ch.any("├┝┞┟┠┡┢┣") {
        (vec![C, W, O], vec![line(m, c), line(m, w), line(m, o)])
    } else if ch.any("┤┥┦┧┨┩┪┫") {
        (vec![C, W, K], vec![line(m, c), line(m, w), line(m, k)])
    } else if ch.is('║') {
        (
            vec![B, V, D, X],
            vec![line(b, v), line(v, b), line(d, x), line(x, d)],
        )
    } else if ch.is('═') {
        (vec![K, O, P, T], vec![line(k, o), line(k, o), line(p, t)])
    } else if ch.is('╔') {
        (
            vec![O, V, T, X],
            vec![line(o, l), line(l, v), line(t, s), line(s, x)],
        )
    } else if ch.is('╗') {
        (
            vec![K, X, P, V],
            vec![line(k, n), line(n, x), line(p, q), line(q, v)],
        )
    } else if ch.is('╚') {
        (
            vec![B, T, D, O],
            vec![line(b, q), line(q, t), line(d, n), line(n, o)],
        )
    } else if ch.is('╝') {
        (
            vec![P, K, B, D],
            vec![line(p, s), line(s, d), line(k, l), line(l, b)],
        )
    } else if ch.is('╒') {
        (vec![W, O, T], vec![line(m, w), line(m, o), line(r, t)])
    } else if ch.is('╓') {
        (vec![O, V, X], vec![line(l, o), line(l, v), line(n, x)])
    } else if ch.is('╬') {
        (
            vec![B, D, V, X, K, P, O, T],
            vec![
                line(b, l),
                line(l, k),
                line(p, q),
                line(q, v),
                line(d, n),
                line(n, o),
                line(t, s),
                line(s, x),
            ],
        )
    } else if ch.is('╦') {
        (
            vec![K, O, P, V, T, X],
            vec![line(k, o), line(p, q), line(q, v), line(t, s), line(s, x)],
        )
    } else if ch.is('╩') {
        (
            vec![P, T, K, B, D, O],
            vec![line(p, t), line(k, l), line(l, b), line(d, n), line(n, o)],
        )
    } else if ch.is('╠') {
        (
            vec![B, V, D, O, T, X],
            vec![line(b, v), line(d, n), line(n, o), line(t, s), line(s, x)],
        )
    } else if ch.is('╣') {
        (
            vec![D, X, B, K, P, V],
            vec![line(d, x), line(b, l), line(l, k), line(p, q), line(q, v)],
        )
    } else if ch.is('╱') {
        (vec![U, E], vec![line(u, e)])
    } else if ch.is('╲') {
        (vec![A, Y], vec![line(a, y)])
    } else if ch.is('╳') {
        (vec![A, Y, U, E], vec![line(a, y), line(u, e)])
    } else if ch.is('╒') {
        (vec![W, O, T], vec![line(m, w), line(m, o), line(r, t)])
    } else if ch.is('╓') {
        (vec![O, V, X], vec![line(l, o), line(l, v), line(n, x)])
    } else if ch.is('╞') {
        (vec![C, W, O, T], vec![line(c, w), line(m, o), line(r, t)])
    } else if ch.is('╡') {
        (vec![W, C, K, P], vec![line(c, w), line(k, m), line(p, r)])
    } else if ch.is('╤') {
        (
            vec![K, O, P, T, W],
            vec![line(k, o), line(p, t), line(r, w)],
        )
    } else if ch.is('╥') {
        (vec![K, O, V, X], vec![line(k, o), line(l, v), line(n, x)])
    } else if ch.is('╖') {
        (vec![K, X, V], vec![line(k, n), line(n, x), line(l, v)])
    } else if ch.is('╙') {
        (vec![O, B, D], vec![line(l, o), line(l, b), line(n, d)])
    } else if ch.is('╜') {
        (vec![K, B, D], vec![line(k, n), line(l, b), line(n, d)])
    } else if ch.is('╕') {
        (vec![W, K, P], vec![line(m, w), line(k, m), line(p, r)])
    } else if ch.is('╛') {
        (vec![C, P, K], vec![line(c, r), line(r, p), line(k, m)])
    } else if ch.is('╘') {
        (vec![C, O, T], vec![line(c, r), line(m, o), line(r, t)])
    } else if ch.is('╢') {
        (
            vec![D, B, K, V, X],
            vec![line(d, x), line(b, v), line(k, l)],
        )
    } else if ch.is('╟') {
        (
            vec![D, X, B, V, O],
            vec![line(d, x), line(b, v), line(n, o)],
        )
    } else if ch.is('╪') {
        (
            vec![C, W, K, O, P, T],
            vec![line(c, w), line(k, o), line(p, t)],
        )
    } else if ch.is('╧') {
        (
            vec![K, O, P, T, C],
            vec![line(k, o), line(p, t), line(c, m)],
        )
    } else if ch.is('╫') {
        (
            vec![K, O, B, V, D, X],
            vec![line(k, o), line(b, v), line(d, x)],
        )
    } else if ch.is('╨') {
        (vec![K, O, B, D], vec![line(k, o), line(b, l), line(d, n)])
    } else {
        (vec![], vec![])
    }
}
<|endoftext|>


<commit_before>extern crate hlua;

use hlua::Lua;
use hlua::any::AnyLuaValue;

#[test]
fn read_numbers() {
    let mut lua = Lua::new();

    lua.set("a", "-2");
    lua.set("b", 3.5f32);

    let x: AnyLuaValue = lua.get("a").unwrap();
    assert_eq!(x, AnyLuaValue::LuaNumber(-2.0));

    let y: AnyLuaValue = lua.get("b").unwrap();
    assert_eq!(y, AnyLuaValue::LuaNumber(3.5));
}

#[test]
fn read_strings() {
    let mut lua = Lua::new();

    lua.set("a", "hello");
    lua.set("b", "3x");
    lua.set("c", "false");

    let x: AnyLuaValue = lua.get("a").unwrap();
    assert_eq!(x, AnyLuaValue::LuaString("hello".to_string()));

    let y: AnyLuaValue = lua.get("b").unwrap();
    assert_eq!(y, AnyLuaValue::LuaString("3x".to_string()));

    let z: AnyLuaValue = lua.get("c").unwrap();
    assert_eq!(z, AnyLuaValue::LuaString("false".to_string()));
}

#[test]
fn read_booleans() {
    let mut lua = Lua::new();

    lua.set("a", true);
    lua.set("b", false);

    let x: AnyLuaValue = lua.get("a").unwrap();
    assert_eq!(x, AnyLuaValue::LuaBoolean(true));

    let y: AnyLuaValue = lua.get("b").unwrap();
    assert_eq!(y, AnyLuaValue::LuaBoolean(false));
}

#[test]
fn read_nil() {
    let mut lua = Lua::new();

    let x: AnyLuaValue = lua.get("distinctly_nil_value").unwrap();
    assert_eq!(x, AnyLuaValue::LuaNil);
}

#[test]
fn push_numbers() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaNumber(3.0));

    let x: i32 = lua.get("a").unwrap();
    assert_eq!(x, 3);
}

#[test]
fn push_strings() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaString("hello".to_string()));

    let x: String = lua.get("a").unwrap();
    assert_eq!(x, "hello");
}

#[test]
fn push_booleans() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaBoolean(true));

    let x: bool = lua.get("a").unwrap();
    assert_eq!(x, true);
}

#[test]
fn push_nil() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaNil);

    let x: Option<i32> = lua.get("a");
    assert!(x.is_none(),
            "x is a Some value when it should be a None value. X: {:?}",
            x);
}
<commit_msg>Remove broken read_nil test<commit_after>extern crate hlua;

use hlua::Lua;
use hlua::any::AnyLuaValue;

#[test]
fn read_numbers() {
    let mut lua = Lua::new();

    lua.set("a", "-2");
    lua.set("b", 3.5f32);

    let x: AnyLuaValue = lua.get("a").unwrap();
    assert_eq!(x, AnyLuaValue::LuaNumber(-2.0));

    let y: AnyLuaValue = lua.get("b").unwrap();
    assert_eq!(y, AnyLuaValue::LuaNumber(3.5));
}

#[test]
fn read_strings() {
    let mut lua = Lua::new();

    lua.set("a", "hello");
    lua.set("b", "3x");
    lua.set("c", "false");

    let x: AnyLuaValue = lua.get("a").unwrap();
    assert_eq!(x, AnyLuaValue::LuaString("hello".to_string()));

    let y: AnyLuaValue = lua.get("b").unwrap();
    assert_eq!(y, AnyLuaValue::LuaString("3x".to_string()));

    let z: AnyLuaValue = lua.get("c").unwrap();
    assert_eq!(z, AnyLuaValue::LuaString("false".to_string()));
}

#[test]
fn read_booleans() {
    let mut lua = Lua::new();

    lua.set("a", true);
    lua.set("b", false);

    let x: AnyLuaValue = lua.get("a").unwrap();
    assert_eq!(x, AnyLuaValue::LuaBoolean(true));

    let y: AnyLuaValue = lua.get("b").unwrap();
    assert_eq!(y, AnyLuaValue::LuaBoolean(false));
}

#[test]
fn push_numbers() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaNumber(3.0));

    let x: i32 = lua.get("a").unwrap();
    assert_eq!(x, 3);
}

#[test]
fn push_strings() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaString("hello".to_string()));

    let x: String = lua.get("a").unwrap();
    assert_eq!(x, "hello");
}

#[test]
fn push_booleans() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaBoolean(true));

    let x: bool = lua.get("a").unwrap();
    assert_eq!(x, true);
}

#[test]
fn push_nil() {
    let mut lua = Lua::new();

    lua.set("a", AnyLuaValue::LuaNil);

    let x: Option<i32> = lua.get("a");
    assert!(x.is_none(),
            "x is a Some value when it should be a None value. X: {:?}",
            x);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use darling::{FromDeriveInput, FromField, FromVariant};
use proc_macro2::{Span, TokenStream};
use quote::TokenStreamExt;
use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
use syn::{GenericArgument, GenericParam, Ident, Path};
use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray};
use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
use syn::{Variant, WherePredicate};
use synstructure::{self, BindStyle, BindingInfo, VariantAst, VariantInfo};

/// Given an input type which has some where clauses already, like:
///
/// struct InputType<T>
/// where
///     T: Zero,
/// {
///     ...
/// }
///
/// Add the necessary `where` clauses so that the output type of a trait
/// fulfils them.
///
/// For example:
///
///     <T as ToComputedValue>::ComputedValue: Zero,
///
/// This needs to run before adding other bounds to the type parameters.
pub fn propagate_clauses_to_output_type(
    where_clause: &mut Option<syn::WhereClause>,
    generics: &syn::Generics,
    trait_path: &Path,
    trait_output: &Ident,
) {
    let where_clause = match *where_clause {
        Some(ref mut clause) => clause,
        None => return,
    };
    let mut extra_bounds = vec![];
    for pred in &where_clause.predicates {
        let ty = match *pred {
            syn::WherePredicate::Type(ref ty) => ty,
            ref predicate => panic!("Unhanded complex where predicate: {:?}", predicate),
        };

        let path = match ty.bounded_ty {
            syn::Type::Path(ref p) => &p.path,
            ref ty => panic!("Unhanded complex where type: {:?}", ty),
        };

        assert!(
            ty.lifetimes.is_none(),
            "Unhanded complex lifetime bound: {:?}",
            ty,
        );

        let ident = match path_to_ident(path) {
            Some(i) => i,
            None => panic!("Unhanded complex where type path: {:?}", path),
        };

        if generics.type_params().any(|param| param.ident == *ident) {
            extra_bounds.push(ty.clone());
        }
    }

    for bound in extra_bounds {
        let ty = bound.bounded_ty;
        let bounds = bound.bounds;
        where_clause
            .predicates
            .push(parse_quote!(<#ty as #trait_path>::#trait_output: #bounds))
    }
}

pub fn add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate) {
    where_clause
        .get_or_insert(parse_quote!(where))
        .predicates
        .push(pred);
}

pub fn fmap_match<F>(input: &DeriveInput, bind_style: BindStyle, mut f: F) -> TokenStream
where
    F: FnMut(BindingInfo) -> TokenStream,
{
    let mut s = synstructure::Structure::new(input);
    s.variants_mut().iter_mut().for_each(|v| {
        v.bind_with(|_| bind_style);
    });
    s.each_variant(|variant| {
        let (mapped, mapped_fields) = value(variant, "mapped");
        let fields_pairs = variant.bindings().iter().zip(mapped_fields);
        let mut computations = quote!();
        computations.append_all(fields_pairs.map(|(field, mapped_field)| {
            let expr = f(field.clone());
            quote! { let #mapped_field = #expr; }
        }));
        computations.append_all(mapped);
        Some(computations)
    })
}

pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: &Ident) -> Path {
    let segment = PathSegment {
        ident: input.ident.clone(),
        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
            args: input
                .generics
                .params
                .iter()
                .map(|arg| match arg {
                    &GenericParam::Lifetime(ref data) => {
                        GenericArgument::Lifetime(data.lifetime.clone())
                    },
                    &GenericParam::Type(ref data) => {
                        let ident = &data.ident;
                        GenericArgument::Type(parse_quote!(<#ident as #trait_path>::#trait_output))
                    },
                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
                })
                .collect(),
            colon2_token: Default::default(),
            gt_token: Default::default(),
            lt_token: Default::default(),
        }),
    };
    segment.into()
}

pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
where
    F: FnMut(&Ident) -> Type,
{
    match *ty {
        Type::Slice(ref inner) => Type::from(TypeSlice {
            elem: Box::new(map_type_params(&inner.elem, params, f)),
            ..inner.clone()
        }),
        Type::Array(ref inner) => {
            //ref ty, ref expr) => {
            Type::from(TypeArray {
                elem: Box::new(map_type_params(&inner.elem, params, f)),
                ..inner.clone()
            })
        },
        ref ty @ Type::Never(_) => ty.clone(),
        Type::Tuple(ref inner) => Type::from(TypeTuple {
            elems: inner
                .elems
                .iter()
                .map(|ty| map_type_params(&ty, params, f))
                .collect(),
            ..inner.clone()
        }),
        Type::Path(TypePath {
            qself: None,
            ref path,
        }) => {
            if let Some(ident) = path_to_ident(path) {
                if params.iter().any(|ref param| &param.ident == ident) {
                    return f(ident);
                }
            }
            Type::from(TypePath {
                qself: None,
                path: map_type_params_in_path(path, params, f),
            })
        },
        Type::Path(TypePath {
            ref qself,
            ref path,
        }) => Type::from(TypePath {
            qself: qself.as_ref().map(|qself| QSelf {
                ty: Box::new(map_type_params(&qself.ty, params, f)),
                position: qself.position,
                ..qself.clone()
            }),
            path: map_type_params_in_path(path, params, f),
        }),
        Type::Paren(ref inner) => Type::from(TypeParen {
            elem: Box::new(map_type_params(&inner.elem, params, f)),
            ..inner.clone()
        }),
        ref ty => panic!("type {:?} cannot be mapped yet", ty),
    }
}

fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], f: &mut F) -> Path
where
    F: FnMut(&Ident) -> Type,
{
    Path {
        leading_colon: path.leading_colon,
        segments: path
            .segments
            .iter()
            .map(|segment| PathSegment {
                ident: segment.ident.clone(),
                arguments: match segment.arguments {
                    PathArguments::AngleBracketed(ref data) => {
                        PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                            args: data
                                .args
                                .iter()
                                .map(|arg| match arg {
                                    ty @ &GenericArgument::Lifetime(_) => ty.clone(),
                                    &GenericArgument::Type(ref data) => {
                                        GenericArgument::Type(map_type_params(data, params, f))
                                    },
                                    &GenericArgument::Binding(ref data) => {
                                        GenericArgument::Binding(Binding {
                                            ty: map_type_params(&data.ty, params, f),
                                            ..data.clone()
                                        })
                                    },
                                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
                                })
                                .collect(),
                            ..data.clone()
                        })
                    },
                    ref arg @ PathArguments::None => arg.clone(),
                    ref parameters => panic!("parameters {:?} cannot be mapped yet", parameters),
                },
            })
            .collect(),
    }
}

fn path_to_ident(path: &Path) -> Option<&Ident> {
    match *path {
        Path {
            leading_colon: None,
            ref segments,
        } if segments.len() == 1 => {
            if segments[0].arguments.is_empty() {
                Some(&segments[0].ident)
            } else {
                None
            }
        },
        _ => None,
    }
}

pub fn parse_field_attrs<A>(field: &Field) -> A
where
    A: FromField,
{
    match A::from_field(field) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse field attributes: {}", e),
    }
}

pub fn parse_input_attrs<A>(input: &DeriveInput) -> A
where
    A: FromDeriveInput,
{
    match A::from_derive_input(input) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse input attributes: {}", e),
    }
}

pub fn parse_variant_attrs_from_ast<A>(variant: &VariantAst) -> A
where
    A: FromVariant,
{
    let v = Variant {
        ident: variant.ident.clone(),
        attrs: variant.attrs.to_vec(),
        fields: variant.fields.clone(),
        discriminant: variant.discriminant.clone(),
    };
    parse_variant_attrs(&v)
}

pub fn parse_variant_attrs<A>(variant: &Variant) -> A
where
    A: FromVariant,
{
    match A::from_variant(variant) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse variant attributes: {}", e),
    }
}

pub fn ref_pattern<'a>(
    variant: &'a VariantInfo,
    prefix: &str,
) -> (TokenStream, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bind_with(|_| BindStyle::Ref);
    v.bindings_mut().iter_mut().for_each(|b| {
        b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
    });
    (v.pat(), v.bindings().to_vec())
}

pub fn value<'a>(variant: &'a VariantInfo, prefix: &str) -> (TokenStream, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bindings_mut().iter_mut().for_each(|b| {
        b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
    });
    v.bind_with(|_| BindStyle::Move);
    (v.pat(), v.bindings().to_vec())
}

/// Transforms "FooBar" to "foo-bar".
///
/// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
/// is prepended with "-".
pub fn to_css_identifier(mut camel_case: &str) -> String {
    camel_case = camel_case.trim_end_matches('_');
    let mut first = true;
    let mut result = String::with_capacity(camel_case.len());
    while let Some(segment) = split_camel_segment(&mut camel_case) {
        if first {
            match segment {
                "Moz" | "Webkit" | "Servo" => first = false,
                _ => {},
            }
        }
        if !first {
            result.push_str("-");
        }
        first = false;
        result.push_str(&segment.to_lowercase());
    }
    result
}

/// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar".
fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> {
    let index = match camel_case.chars().next() {
        None => return None,
        Some(ch) => ch.len_utf8(),
    };
    let end_position = camel_case[index..]
        .find(char::is_uppercase)
        .map_or(camel_case.len(), |pos| index + pos);
    let result = &camel_case[..end_position];
    *camel_case = &camel_case[end_position..];
    Some(result)
}
<commit_msg>derive_common: Fix example in documentation<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use darling::{FromDeriveInput, FromField, FromVariant};
use proc_macro2::{Span, TokenStream};
use quote::TokenStreamExt;
use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
use syn::{GenericArgument, GenericParam, Ident, Path};
use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray};
use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
use syn::{Variant, WherePredicate};
use synstructure::{self, BindStyle, BindingInfo, VariantAst, VariantInfo};

/// Given an input type which has some where clauses already, like:
///
/// struct InputType<T>
/// where
///     T: Zero,
/// {
///     ...
/// }
///
/// Add the necessary `where` clauses so that the output type of a trait
/// fulfils them.
///
/// For example:
///
/// ```ignore
///     <T as ToComputedValue>::ComputedValue: Zero,
/// ```
///
/// This needs to run before adding other bounds to the type parameters.
pub fn propagate_clauses_to_output_type(
    where_clause: &mut Option<syn::WhereClause>,
    generics: &syn::Generics,
    trait_path: &Path,
    trait_output: &Ident,
) {
    let where_clause = match *where_clause {
        Some(ref mut clause) => clause,
        None => return,
    };
    let mut extra_bounds = vec![];
    for pred in &where_clause.predicates {
        let ty = match *pred {
            syn::WherePredicate::Type(ref ty) => ty,
            ref predicate => panic!("Unhanded complex where predicate: {:?}", predicate),
        };

        let path = match ty.bounded_ty {
            syn::Type::Path(ref p) => &p.path,
            ref ty => panic!("Unhanded complex where type: {:?}", ty),
        };

        assert!(
            ty.lifetimes.is_none(),
            "Unhanded complex lifetime bound: {:?}",
            ty,
        );

        let ident = match path_to_ident(path) {
            Some(i) => i,
            None => panic!("Unhanded complex where type path: {:?}", path),
        };

        if generics.type_params().any(|param| param.ident == *ident) {
            extra_bounds.push(ty.clone());
        }
    }

    for bound in extra_bounds {
        let ty = bound.bounded_ty;
        let bounds = bound.bounds;
        where_clause
            .predicates
            .push(parse_quote!(<#ty as #trait_path>::#trait_output: #bounds))
    }
}

pub fn add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate) {
    where_clause
        .get_or_insert(parse_quote!(where))
        .predicates
        .push(pred);
}

pub fn fmap_match<F>(input: &DeriveInput, bind_style: BindStyle, mut f: F) -> TokenStream
where
    F: FnMut(BindingInfo) -> TokenStream,
{
    let mut s = synstructure::Structure::new(input);
    s.variants_mut().iter_mut().for_each(|v| {
        v.bind_with(|_| bind_style);
    });
    s.each_variant(|variant| {
        let (mapped, mapped_fields) = value(variant, "mapped");
        let fields_pairs = variant.bindings().iter().zip(mapped_fields);
        let mut computations = quote!();
        computations.append_all(fields_pairs.map(|(field, mapped_field)| {
            let expr = f(field.clone());
            quote! { let #mapped_field = #expr; }
        }));
        computations.append_all(mapped);
        Some(computations)
    })
}

pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: &Ident) -> Path {
    let segment = PathSegment {
        ident: input.ident.clone(),
        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
            args: input
                .generics
                .params
                .iter()
                .map(|arg| match arg {
                    &GenericParam::Lifetime(ref data) => {
                        GenericArgument::Lifetime(data.lifetime.clone())
                    },
                    &GenericParam::Type(ref data) => {
                        let ident = &data.ident;
                        GenericArgument::Type(parse_quote!(<#ident as #trait_path>::#trait_output))
                    },
                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
                })
                .collect(),
            colon2_token: Default::default(),
            gt_token: Default::default(),
            lt_token: Default::default(),
        }),
    };
    segment.into()
}

pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
where
    F: FnMut(&Ident) -> Type,
{
    match *ty {
        Type::Slice(ref inner) => Type::from(TypeSlice {
            elem: Box::new(map_type_params(&inner.elem, params, f)),
            ..inner.clone()
        }),
        Type::Array(ref inner) => {
            //ref ty, ref expr) => {
            Type::from(TypeArray {
                elem: Box::new(map_type_params(&inner.elem, params, f)),
                ..inner.clone()
            })
        },
        ref ty @ Type::Never(_) => ty.clone(),
        Type::Tuple(ref inner) => Type::from(TypeTuple {
            elems: inner
                .elems
                .iter()
                .map(|ty| map_type_params(&ty, params, f))
                .collect(),
            ..inner.clone()
        }),
        Type::Path(TypePath {
            qself: None,
            ref path,
        }) => {
            if let Some(ident) = path_to_ident(path) {
                if params.iter().any(|ref param| &param.ident == ident) {
                    return f(ident);
                }
            }
            Type::from(TypePath {
                qself: None,
                path: map_type_params_in_path(path, params, f),
            })
        },
        Type::Path(TypePath {
            ref qself,
            ref path,
        }) => Type::from(TypePath {
            qself: qself.as_ref().map(|qself| QSelf {
                ty: Box::new(map_type_params(&qself.ty, params, f)),
                position: qself.position,
                ..qself.clone()
            }),
            path: map_type_params_in_path(path, params, f),
        }),
        Type::Paren(ref inner) => Type::from(TypeParen {
            elem: Box::new(map_type_params(&inner.elem, params, f)),
            ..inner.clone()
        }),
        ref ty => panic!("type {:?} cannot be mapped yet", ty),
    }
}

fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], f: &mut F) -> Path
where
    F: FnMut(&Ident) -> Type,
{
    Path {
        leading_colon: path.leading_colon,
        segments: path
            .segments
            .iter()
            .map(|segment| PathSegment {
                ident: segment.ident.clone(),
                arguments: match segment.arguments {
                    PathArguments::AngleBracketed(ref data) => {
                        PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                            args: data
                                .args
                                .iter()
                                .map(|arg| match arg {
                                    ty @ &GenericArgument::Lifetime(_) => ty.clone(),
                                    &GenericArgument::Type(ref data) => {
                                        GenericArgument::Type(map_type_params(data, params, f))
                                    },
                                    &GenericArgument::Binding(ref data) => {
                                        GenericArgument::Binding(Binding {
                                            ty: map_type_params(&data.ty, params, f),
                                            ..data.clone()
                                        })
                                    },
                                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
                                })
                                .collect(),
                            ..data.clone()
                        })
                    },
                    ref arg @ PathArguments::None => arg.clone(),
                    ref parameters => panic!("parameters {:?} cannot be mapped yet", parameters),
                },
            })
            .collect(),
    }
}

fn path_to_ident(path: &Path) -> Option<&Ident> {
    match *path {
        Path {
            leading_colon: None,
            ref segments,
        } if segments.len() == 1 => {
            if segments[0].arguments.is_empty() {
                Some(&segments[0].ident)
            } else {
                None
            }
        },
        _ => None,
    }
}

pub fn parse_field_attrs<A>(field: &Field) -> A
where
    A: FromField,
{
    match A::from_field(field) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse field attributes: {}", e),
    }
}

pub fn parse_input_attrs<A>(input: &DeriveInput) -> A
where
    A: FromDeriveInput,
{
    match A::from_derive_input(input) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse input attributes: {}", e),
    }
}

pub fn parse_variant_attrs_from_ast<A>(variant: &VariantAst) -> A
where
    A: FromVariant,
{
    let v = Variant {
        ident: variant.ident.clone(),
        attrs: variant.attrs.to_vec(),
        fields: variant.fields.clone(),
        discriminant: variant.discriminant.clone(),
    };
    parse_variant_attrs(&v)
}

pub fn parse_variant_attrs<A>(variant: &Variant) -> A
where
    A: FromVariant,
{
    match A::from_variant(variant) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse variant attributes: {}", e),
    }
}

pub fn ref_pattern<'a>(
    variant: &'a VariantInfo,
    prefix: &str,
) -> (TokenStream, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bind_with(|_| BindStyle::Ref);
    v.bindings_mut().iter_mut().for_each(|b| {
        b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
    });
    (v.pat(), v.bindings().to_vec())
}

pub fn value<'a>(variant: &'a VariantInfo, prefix: &str) -> (TokenStream, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bindings_mut().iter_mut().for_each(|b| {
        b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
    });
    v.bind_with(|_| BindStyle::Move);
    (v.pat(), v.bindings().to_vec())
}

/// Transforms "FooBar" to "foo-bar".
///
/// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
/// is prepended with "-".
pub fn to_css_identifier(mut camel_case: &str) -> String {
    camel_case = camel_case.trim_end_matches('_');
    let mut first = true;
    let mut result = String::with_capacity(camel_case.len());
    while let Some(segment) = split_camel_segment(&mut camel_case) {
        if first {
            match segment {
                "Moz" | "Webkit" | "Servo" => first = false,
                _ => {},
            }
        }
        if !first {
            result.push_str("-");
        }
        first = false;
        result.push_str(&segment.to_lowercase());
    }
    result
}

/// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar".
fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> {
    let index = match camel_case.chars().next() {
        None => return None,
        Some(ch) => ch.len_utf8(),
    };
    let end_position = camel_case[index..]
        .find(char::is_uppercase)
        .map_or(camel_case.len(), |pos| index + pos);
    let result = &camel_case[..end_position];
    *camel_case = &camel_case[end_position..];
    Some(result)
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

macro_rules! return_if_some(
    ($arg:expr) => (
        match $arg {
            Some(val) => return val,
            None => {},
        }
    );
)

pub fn pathmatch(pattern: &str, pathstring: &str) -> bool
{
    use std::str::Chars;
    let pattern_chars = pattern.chars();
    let mut path_chars = pathstring.chars();
    return pathmatch_impl(pattern_chars, &mut path_chars, false);

    fn pathmatch_impl(mut pattern_chars: Chars, path_chars: &mut Chars, alt_branch_mode: bool) -> bool
    {
        if char_iter_equals(pattern_chars, "**/", true) {
            // How can I convert Skip<Chars> to Chars to make use of .skip(3) ?
            let mut pattern_chars_copy = pattern_chars;
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            if pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                return true;
            }
        }
        loop {
            if char_iter_equals(pattern_chars, "/**", false) && path_chars.peekable().is_empty() {
                return true;
            }
            match pattern_chars.next() {
                None => return path_chars.next().is_none(),
                Some('?') => match path_chars.next() {
                    None | Some('/') => return false,
                    _ => (),
                },
                Some('*') => match pattern_chars.peekable().peek() {
                    Some(&'*') => {
                        pattern_chars.next();
                        return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, true));
                    },
                    _ => return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, false)),
                },
                Some('/') => {
                    return_if_some!(match_exact('/', path_chars.next(), alt_branch_mode));
                    if char_iter_equals(pattern_chars, "**/", true) && pathmatch_try(pattern_chars, path_chars, alt_branch_mode) {
                        return true;
                    }
                },
                Some('{') => {
                    let mut matched_something = false;
                    loop {
                        if !matched_something && pathmatch_try(pattern_chars, path_chars, true) {
                            matched_something = true;
                        }
                        match skip_alt_branch(&mut pattern_chars) {
                            Some(false) => break,
                            Some(true) => {},
                            None => /* error in pattern */ return false,
                        }
                    }
                    if !matched_something {
                        return false;
                    }
                },
                Some(',') | Some('}') if alt_branch_mode => return true,
                Some(pc) => return_if_some!(match_exact(pc, path_chars.next(), alt_branch_mode)),
            }
        }
    }

    fn pathmatch_try(pattern_chars: Chars, path_chars: &mut Chars, alt_branch_mode: bool) -> bool
    {
        let mut path_chars_copy = path_chars.clone();
        if pathmatch_impl(pattern_chars, &mut path_chars_copy, alt_branch_mode) {
            *path_chars = path_chars_copy;
            return true;
        }
        return false;
    }

    fn skip_alt_branch(pattern_chars: &mut Chars) -> Option<bool>
    {
        loop {
            match pattern_chars.next() {
                Some(',') => return Some(true),
                Some('}') => return Some(false),
                Some('{') => if skip_alt_branch(pattern_chars).is_none() { return None; },
                None => return None,
                _ => {},
            }
        }
    }

    fn match_any(pattern_chars: Chars, path_chars: &mut Chars, alt_branch_mode: bool, allow_pathsep: bool) -> Option<bool>
    {
        loop {
            if pathmatch_try(pattern_chars, path_chars, alt_branch_mode) {
                return Some(true);
            }
            match path_chars.next() {
                None => return None,
                Some('/') if !allow_pathsep => return Some(false),
                _ => {},
            }
        }
    }

    fn match_exact(pattern_char: char, path_char: Option<char>, alt_branch_mode: bool) -> Option<bool>
    {
        match path_char {
            None => return Some(false),
            Some(',') | Some('}') if alt_branch_mode => return Some(false),
            Some(x) if x != pattern_char => return Some(false),
            _ => return None,
        }
    }

    fn char_iter_equals(mut char_iter: Chars, needle: &str, startswith: bool) -> bool
    {
        for needle_char in needle.chars() {
            match char_iter.next() {
                Some(x) if x == needle_char => (),
                _ => return false,
            }
        }
        return if startswith { true } else { char_iter.next().is_none() };
    }
}

#[cfg(test)]
fn assert_pathmatch_many(pattern: &str, paths_yes: &[&str], paths_no: &[&str])
{
    for path in paths_yes.iter() {
        assert!(pathmatch(pattern, *path), "should match: pattern:'{}' path:'{}'", pattern, path);
    }
    for path in paths_no.iter() {
        assert!(!pathmatch(pattern, *path), "must not match: pattern:'{}' path:'{}'", pattern, path);
    }
}

#[test]
fn pathmatch_test_alt_combos()
{
//    assert_pathmatch_many("{foo/**,**/bar}", ["foo", "bar"], ["foobar"]);
    assert_pathmatch_many("a{?,/}c", ["abc", "a/c"], ["ac", "abbc"]);
//    assert_pathmatch_many("{foo/**,bar}baz", ["barbaz", "foo/baz"], ["foobaz"]);
//    assert_pathmatch_many("foo{bar,**/baz}", ["foobar", "foo/baz"], ["foobaz"]);
}

#[test]
fn pathmatch_test_alt()
{
    assert!(pathmatch("{foo}", "foo"));
    assert_pathmatch_many("{foo,bar,baz}", ["foo", "bar", "baz"], ["", "foobarbaz", "qux"]);
    assert_pathmatch_many("{foo,bar}", ["foo", "bar"], ["", "foobar"]);
    assert!(pathmatch("{}", ""));
    assert!(!pathmatch("{}", "{}"));
    assert!(pathmatch("{foo}{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "fooXXbar"));
}

#[test]
fn pathmatch_test_collapse()
{
    // `/**/` may match a single slash.
    assert!(pathmatch("foo/**/bar", "foo/bar"));
    assert!(pathmatch("foo/**/", "foo/"));
    assert!(!pathmatch("foo/**/", "foo"));
    assert!(pathmatch("/**/bar", "/bar"));
    assert!(!pathmatch("/**/bar", "bar"));
    // to prevent this behavior, you would use this
    assert!(!pathmatch("foo/*/**/bar", "foo/bar"));
    assert!(!pathmatch("foo/**/*/bar", "foo/bar"));
    assert!(pathmatch("foo/**/bar", "foo//bar"));
    assert!(pathmatch("foo/*/**/bar", "foo//bar"));
}

#[test]
fn pathmatch_test_anypath_leading()
{
    // `**/` at the beginning of pattern may match nothing.
    assert!(pathmatch("**/bar", "bar"));
    assert!(pathmatch("**/bar", "/bar"));
    assert!(!pathmatch("a**/bar", "abar"));
    assert!(!pathmatch("*/bar", "bar"));
}

#[test]
fn pathmatch_test_anypath_trailing()
{
    // `/**` at the end of pattern may match nothing.
    assert!(pathmatch("foo/**", "foo"));
    assert!(pathmatch("foo/**", "foo/"));
    assert!(!pathmatch("foo/**g", "foog"));
    assert!(!pathmatch("foo/*", "foo"));
}

#[test]
fn pathmatch_test_anypath()
{
    assert!(pathmatch("**", ""));
    assert!(pathmatch("a**", "a/b/c"));
    assert!(pathmatch("**c", "a/b/c"));
    assert!(pathmatch("a**c", "a/b/c"));
    assert!(pathmatch("a/**/c", "a/b/c"));
    assert!(pathmatch("**/c", "a/b/c"));
    assert!(!pathmatch("**/g", "e/fg"));
    assert!(pathmatch("a/**", "a/b/c"));
    assert!(!pathmatch("e/**", "ef/g"));
}

#[test]
fn pathmatch_test_pathsep()
{
    assert!(!pathmatch("a?b", "a/b"));
    assert!(!pathmatch("a*b", "a/b"));
    assert!(pathmatch("a*/b", "a/b"));
    assert!(pathmatch("a/*b", "a/b"));
}

#[test]
fn pathmatch_test_anyname()
{
    assert!(pathmatch("*", ""));
    assert!(pathmatch("*", "?"));
    assert!(pathmatch("*", "d?F"));
    assert!(pathmatch("a*", "a"));
    assert!(pathmatch("a*", "abcdef"));
    assert!(pathmatch("*f", "abcdef"));
    assert!(pathmatch("a*f", "abcdef"));
    assert!(pathmatch("*cd*", "abcdef"));
    assert!(pathmatch("a*cd*f", "abcdef"));
    assert!(pathmatch("acdf", "acdf"));
    assert!(!pathmatch("*a", "abc"));
    assert!(!pathmatch("c*", "abc"));
}

#[test]
fn pathmatch_test_anychar()
{
    assert!(pathmatch("?", "?"));
    assert!(pathmatch("?", "a"));
    assert!(pathmatch("??", "BC"));
    assert!(pathmatch("B?", "BC"));
    assert!(pathmatch("?C", "BC"));
    assert!(!pathmatch("?", ""));
    assert!(!pathmatch("D?", "BC"));
    assert!(!pathmatch("?E", "BC"));
}

#[test]
fn pathmatch_test_exact_equality()
{
    assert!(pathmatch("", ""));
    assert!(pathmatch("a", "a"));
    assert!(pathmatch("BC", "BC"));
    assert!(!pathmatch("a", ""));
    assert!(!pathmatch("", "BC"));
}

<commit_msg>tests for some combinations<commit_after>#![feature(macro_rules)]

macro_rules! return_if_some(
    ($arg:expr) => (
        match $arg {
            Some(val) => return val,
            None => {},
        }
    );
)

pub fn pathmatch(pattern: &str, pathstring: &str) -> bool
{
    use std::str::Chars;
    let pattern_chars = cursor(pattern);
    let mut path_chars = cursor(pathstring);
    return pathmatch_impl(pattern_chars, &mut path_chars, false);

    #[deriving(Clone)]
    struct Cursor<'a>
    {
        chars: Chars<'a>,
        at_the_beginning: bool,
    }

    fn cursor<'a>(arg: &'a str) -> Cursor<'a>
    {
        Cursor { chars: arg.chars(), at_the_beginning: true }
    }

    impl<'a> Iterator<char> for Cursor<'a>
    {
        fn next<'a>(&mut self) -> Option<char>
        {
            self.at_the_beginning = false;
            return self.chars.next();
        }
    }

    fn pathmatch_impl(mut pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool) -> bool
    {
        if path_chars.at_the_beginning && char_iter_equals(pattern_chars, "**/", alt_branch_mode, true) {
            // How can I convert Skip<Cursor> to Cursor to make use of .skip(3) ?
            let mut pattern_chars_copy = pattern_chars;
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            if pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                return true;
            }
        }
        loop {
            if char_iter_equals(pattern_chars, "/**", alt_branch_mode, false) && path_chars.peekable().is_empty() {
                return true;
            }
            match pattern_chars.next() {
                None => return path_chars.next().is_none(),
                Some('?') => match path_chars.next() {
                    None | Some('/') => return false,
                    _ => (),
                },
                Some('*') => match pattern_chars.peekable().peek() {
                    Some(&'*') => {
                        pattern_chars.next();
                        return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, true));
                    },
                    _ => return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, false)),
                },
                Some('/') => {
                    return_if_some!(match_exact('/', path_chars.next(), alt_branch_mode));
                    if char_iter_equals(pattern_chars, "**/", alt_branch_mode, true) {
                        let mut pattern_chars_copy = pattern_chars;
                        pattern_chars_copy.next();
                        pattern_chars_copy.next();
                        pattern_chars_copy.next();
                        if pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                            return true;
                        }
                    }
                },
                Some('{') => {
                    let mut matched_something = false;
                    loop {
                        if !matched_something && pathmatch_try(pattern_chars, path_chars, true) {
                            matched_something = true;
                        }
                        match skip_alt_branch(&mut pattern_chars) {
                            Some(false) => break,
                            Some(true) => {},
                            None => /* error in pattern */ return false,
                        }
                    }
                    if !matched_something {
                        return false;
                    }
                },
                Some(',') | Some('}') if alt_branch_mode => return true,
                Some(pc) => return_if_some!(match_exact(pc, path_chars.next(), alt_branch_mode)),
            }
        }
    }

    fn pathmatch_try(pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool) -> bool
    {
        let mut path_chars_copy = path_chars.clone();
        if pathmatch_impl(pattern_chars, &mut path_chars_copy, alt_branch_mode) {
            *path_chars = path_chars_copy;
            return true;
        }
        return false;
    }

    fn skip_alt_branch(pattern_chars: &mut Cursor) -> Option<bool>
    {
        loop {
            match pattern_chars.next() {
                Some(',') => return Some(true),
                Some('}') => return Some(false),
                Some('{') => if skip_alt_branch(pattern_chars).is_none() { return None; },
                None => return None,
                _ => {},
            }
        }
    }

    fn match_any(pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool, allow_pathsep: bool) -> Option<bool>
    {
        loop {
            if pathmatch_try(pattern_chars, path_chars, alt_branch_mode) {
                return Some(true);
            }
            match path_chars.next() {
                None => return None,
                Some('/') if !allow_pathsep => return Some(false),
                _ => {},
            }
        }
    }

    fn match_exact(pattern_char: char, path_char: Option<char>, alt_branch_mode: bool) -> Option<bool>
    {
        match path_char {
            None => return Some(false),
            Some(',') | Some('}') if alt_branch_mode => return Some(false),
            Some(x) if x != pattern_char => return Some(false),
            _ => return None,
        }
    }

    fn char_iter_equals(mut char_iter: Cursor, needle: &str, alt_branch_mode: bool, startswith: bool) -> bool
    {
        for needle_char in needle.chars() {
            match char_iter.next() {
                Some(x) if x == needle_char => (),
                _ => return false,
            }
        }
        if startswith { true }
        else if alt_branch_mode {
            match char_iter.next() {
                Some(',') | Some('}') => true,
                _ => false,
            }
        } else { char_iter.next().is_none() }
    }
}

#[cfg(test)]
fn assert_pathmatch_many(pattern: &str, paths_yes: &[&str], paths_no: &[&str])
{
    for path in paths_yes.iter() {
        assert!(pathmatch(pattern, *path), "should match: pattern:'{}' path:'{}'", pattern, path);
    }
    for path in paths_no.iter() {
        assert!(!pathmatch(pattern, *path), "must not match: pattern:'{}' path:'{}'", pattern, path);
    }
}

#[test]
fn pathmatch_test_alt_combos()
{
    assert_pathmatch_many("a{?,/}c", ["abc", "a/c"], ["ac", "abbc"]);
    assert_pathmatch_many("{foo/**,**/bar}", ["foo", "bar"], ["foobar"]);
    assert_pathmatch_many("{foo/**,bar}baz", ["barbaz", "foo/baz"], ["foobaz"]);
    assert_pathmatch_many("foo{bar,**/baz}", ["foobar", "foo/baz"], ["foobaz"]);
}

#[test]
fn pathmatch_test_alt()
{
    assert!(pathmatch("{foo}", "foo"));
    assert_pathmatch_many("{foo,bar,baz}", ["foo", "bar", "baz"], ["", "foobarbaz", "qux"]);
    assert_pathmatch_many("{foo,bar}", ["foo", "bar"], ["", "foobar"]);
    assert!(pathmatch("{}", ""));
    assert!(!pathmatch("{}", "{}"));
    assert!(pathmatch("{foo}{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "fooXXbar"));
}

#[test]
fn pathmatch_test_collapse()
{
    // `/**/` may match a single slash.
    assert!(pathmatch("foo/**/bar", "foo/bar"));
    assert!(pathmatch("foo/**/", "foo/"));
    assert!(!pathmatch("foo/**/", "foo"));
    assert!(pathmatch("/**/bar", "/bar"));
    assert!(!pathmatch("/**/bar", "bar"));
    // to prevent this behavior, you would use this
    assert!(!pathmatch("foo/*/**/bar", "foo/bar"));
    assert!(!pathmatch("foo/**/*/bar", "foo/bar"));
    assert!(pathmatch("foo/**/bar", "foo//bar"));
    assert!(pathmatch("foo/*/**/bar", "foo//bar"));
}

#[test]
fn pathmatch_test_anypath_leading()
{
    // `**/` at the beginning of pattern may match nothing.
    assert!(pathmatch("**/bar", "bar"));
    assert!(pathmatch("**/bar", "/bar"));
    assert!(!pathmatch("a**/bar", "abar"));
    assert!(!pathmatch("*/bar", "bar"));
}

#[test]
fn pathmatch_test_anypath_trailing()
{
    // `/**` at the end of pattern may match nothing.
    assert!(pathmatch("foo/**", "foo"));
    assert!(pathmatch("foo/**", "foo/"));
    assert!(!pathmatch("foo/**g", "foog"));
    assert!(!pathmatch("foo/*", "foo"));
}

#[test]
fn pathmatch_test_anypath()
{
    assert!(pathmatch("**", ""));
    assert!(pathmatch("a**", "a/b/c"));
    assert!(pathmatch("**c", "a/b/c"));
    assert!(pathmatch("a**c", "a/b/c"));
    assert!(pathmatch("a/**/c", "a/b/c"));
    assert!(pathmatch("**/c", "a/b/c"));
    assert!(!pathmatch("**/g", "e/fg"));
    assert!(pathmatch("a/**", "a/b/c"));
    assert!(!pathmatch("e/**", "ef/g"));
}

#[test]
fn pathmatch_test_pathsep()
{
    assert!(!pathmatch("a?b", "a/b"));
    assert!(!pathmatch("a*b", "a/b"));
    assert!(pathmatch("a*/b", "a/b"));
    assert!(pathmatch("a/*b", "a/b"));
}

#[test]
fn pathmatch_test_anyname()
{
    assert!(pathmatch("*", ""));
    assert!(pathmatch("*", "?"));
    assert!(pathmatch("*", "d?F"));
    assert!(pathmatch("a*", "a"));
    assert!(pathmatch("a*", "abcdef"));
    assert!(pathmatch("*f", "abcdef"));
    assert!(pathmatch("a*f", "abcdef"));
    assert!(pathmatch("*cd*", "abcdef"));
    assert!(pathmatch("a*cd*f", "abcdef"));
    assert!(pathmatch("acdf", "acdf"));
    assert!(!pathmatch("*a", "abc"));
    assert!(!pathmatch("c*", "abc"));
}

#[test]
fn pathmatch_test_anychar()
{
    assert!(pathmatch("?", "?"));
    assert!(pathmatch("?", "a"));
    assert!(pathmatch("??", "BC"));
    assert!(pathmatch("B?", "BC"));
    assert!(pathmatch("?C", "BC"));
    assert!(!pathmatch("?", ""));
    assert!(!pathmatch("D?", "BC"));
    assert!(!pathmatch("?E", "BC"));
}

#[test]
fn pathmatch_test_exact_equality()
{
    assert!(pathmatch("", ""));
    assert!(pathmatch("a", "a"));
    assert!(pathmatch("BC", "BC"));
    assert!(!pathmatch("a", ""));
    assert!(!pathmatch("", "BC"));
}

<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use regex::Regex;

#[macro_use]
extern crate lazy_static;
pub fn get_number<P: AsRef<Path>>(filename: P) -> io::Result<u32> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    if let Ok(lines) = read_lines(filename) {
        for line in lines {
            if let Some(n) = RE.captures(&line) {
                return Ok(n.get(1).unwrap().as_str().parse().unwrap());
            }
        }
    }
    Ok(0)
}

/*
fn read_lines<P: AsRef<Path>>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}
*/

fn read_lines<P: AsRef<Path>>(filename: P) -> io::Result<impl Iterator<Item = String>> {
    let file = File::open(filename)?;
    Ok(FileReader::new(file))
}

struct FileReader {
    lines: io::Lines<io::BufReader<File>>
}

impl FileReader {
    fn new(file: File) -> FileReader {
        FileReader{ lines: io::BufReader::new(file).lines() }
    }
}

impl Iterator for FileReader {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(line) = self.lines.next() {
            return Some(line.unwrap());
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn get_test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }
}
<commit_msg>Use a map<commit_after>use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use regex::Regex;

#[macro_use]
extern crate lazy_static;
pub fn get_number<P: AsRef<Path>>(filename: P) -> io::Result<u32> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    if let Ok(lines) = read_lines(filename) {
        for line in lines {
            if let Some(n) = RE.captures(&line) {
                return Ok(n.get(1).unwrap().as_str().parse().unwrap());
            }
        }
    }
    Ok(0)
}

fn read_lines<P: AsRef<Path>>(filename: P) -> io::Result<impl Iterator<Item = String>> {
    let file = File::open(filename)?;
    return Ok(io::BufReader::new(file).lines().map(|line|
        line.unwrap()
    ));
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn get_test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }
}
<|endoftext|>


<commit_before>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match int::from_str(input) {
        Some(number) => Int(number),
        None => match float::from_str(input) {
            Some(number) => Float(number),
            None => Symbol(input)
        }
    }
}

#[test]
fn test_that_read_can_read_an_atom() {
    let atom = read( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_read_can_read_a_list() {
    let list = read( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_read_can_read_a_nested_list() {
    let list = read( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn parse( program:&str ) -> Expression {
    read( tokenize( program ) )
}

fn read( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let mut remainder = copy tokens;
        let token = remainder.remove(0);
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                while remainder.len() > 0 && remainder[0] != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator.push(expr);
                    remainder = new_remainder
                }
                // remove the final close paren, this will fail if the parens
                // aren't closed properly due to an assert in remove
                remainder.remove(0);
                (List(accumulator), remainder)
            }
            ~")" => fail,
                _ => (atom(token), remainder)
        }
    }

    let (expression, _remainder) = subexpression( tokens );
    expression
}

enum Expression {
    Int(int),
    Float(float),
    Symbol(~str),
    List(~[Expression])
}

fn stringify_expression( expression:Expression ) -> ~str {
    match expression {
        Int(number) => { fmt!("%d", number) }
        Float(number) => {
            if number == (number as int) as float {
                fmt!("%.1f", number)
            } else {
                fmt!("%f", number)
            }
        }
        Symbol(string) => { string }
        List(expressions) => {
            let strings = expressions.map( | &expr | {stringify_expression(expr)} );
            ~"(" + strings.foldl(~"", |&x, &y| { x + ~" " + y } ).trim() + ~")"
        }
    }
}

#[test]
fn test_eval_returns_number_when_passed_number() {
    let value = eval( Int(1), @Environment::new_global_environment() );
    match value {
        Int(1) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    let value = eval( List( ~[ Symbol(~"quote"), List( ~[ Symbol(~"a") ] ) ] ),
    @Environment::new_global_environment() );
    io::println( stringify_expression( value ) );
    match value {
        List( [ Symbol( ~"a" ) ] ) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    let expression = parse( ~"(begin 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    let expression = parse( ~"(if 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    let expression = parse( ~"(if 0 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = parse( ~"(if 1 (begin 1 2) 7)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the then branch",
        _ => fail fmt!("If returned something unusual (%s)", stringify_expression(value))
    }
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = parse( ~"(if 0 7 (begin 1 2))" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the else branch",
        _ => fail fmt!("If returned something unusual (%s)", stringify_expression(value))
    }
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = parse( ~"(if (begin 1 0) 1 2)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(1) => fail ~"If didn't evaluate the test",
        Int(2) => (),
        _ => fail fmt!("If returned something unusual (%s)", stringify_expression(value))
    }
}

fn eval( expression:Expression, environment:@Environment ) -> Expression {
    fn quote(expressions:~[Expression]) -> Expression {
        match expressions {
            [_, expr] => expr,
            _ => fail ~"Syntax Error: quote must take a single argument"
        }
    }

    fn if_(expressions:~[Expression], environment:@Environment) -> Expression {
        match expressions {
            [_, test, true_expr, false_expr] => {
                eval(if is_truthy( eval(test, environment) ) { true_expr } else { false_expr }, environment)
            }
            _ => fail ~"Syntax Error: if must take three arguments"
        }
    }

    fn begin(expressions:~[Expression], environment:@Environment) -> Expression {
        eval( copy expressions[ expressions.len() - 1], environment )
    }

    match copy expression {
        List( expressions ) => {
            match expressions[0] {
                Symbol(~"quote") => quote(expressions),
                Symbol(~"begin") => begin(expressions, environment),
                Symbol(~"if") => if_(expressions, environment),
                _ => expression
            }
        }
        _ => {
            expression
        }
    }
}

#[test]
fn test_is_truthy_returns_true_for_non_zero_numbers() {
    assert is_truthy( Int(1) );
    assert is_truthy( Int(-1) );
    assert is_truthy( Float(1.0) );
    assert is_truthy( Float(-1.0) );
}

#[test]
fn test_is_truthy_returns_false_for_zero_numbers() {
    assert !is_truthy( Int(0) );
    assert !is_truthy( Float(0.0) );
}

fn is_truthy( expression:Expression ) -> bool {
    match expression {
        Int( number ) => 0 != number,
        Float( number ) => 0.0 != number,
        _ => true
    }
}

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

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

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

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

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

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

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

    static fn new_global_environment() -> Environment {
        let mappings = std::treemap::TreeMap();
        Environment {enclosure:None, mappings:mappings}
    }

    static fn new(enclosure:~Environment) -> Environment {
        let mappings = std::treemap::TreeMap();
        Environment {enclosure:Some(enclosure), mappings:mappings}
    }
}

fn main() {
    io::println(stringify_expression( parse( "(1 2 3 (1 2 3))" ) ));
    io::println(stringify_expression( parse( "((1 2) 3 (1 2 3))" ) ));
    let blah:Expression = List(~[Int(1), List(~[Float(1.0), Symbol(~"xyz")])]);
    io::println(stringify_expression(blah));
    io::println( "(begin 1 2)" )
}
<commit_msg>Add variable resolution<commit_after>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match int::from_str(input) {
        Some(number) => Int(number),
        None => match float::from_str(input) {
            Some(number) => Float(number),
            None => Symbol(input)
        }
    }
}

#[test]
fn test_that_read_can_read_an_atom() {
    let atom = read( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_read_can_read_a_list() {
    let list = read( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_read_can_read_a_nested_list() {
    let list = read( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn parse( program:&str ) -> Expression {
    read( tokenize( program ) )
}

fn read( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let mut remainder = copy tokens;
        let token = remainder.remove(0);
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                while remainder.len() > 0 && remainder[0] != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator.push(expr);
                    remainder = new_remainder
                }
                // remove the final close paren, this will fail if the parens
                // aren't closed properly due to an assert in remove
                remainder.remove(0);
                (List(accumulator), remainder)
            }
            ~")" => fail,
                _ => (atom(token), remainder)
        }
    }

    let (expression, _remainder) = subexpression( tokens );
    expression
}

enum Expression {
    Int(int),
    Float(float),
    Symbol(~str),
    List(~[Expression])
}

fn stringify_expression( expression:Expression ) -> ~str {
    match expression {
        Int(number) => { fmt!("%d", number) }
        Float(number) => {
            if number == (number as int) as float {
                fmt!("%.1f", number)
            } else {
                fmt!("%f", number)
            }
        }
        Symbol(string) => { string }
        List(expressions) => {
            let strings = expressions.map( | &expr | {stringify_expression(expr)} );
            ~"(" + strings.foldl(~"", |&x, &y| { x + ~" " + y } ).trim() + ~")"
        }
    }
}

#[test]
fn test_eval_returns_number_when_passed_number() {
    let value = eval( Int(1), @Environment::new_global_environment() );
    match value {
        Int(1) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    let value = eval( List( ~[ Symbol(~"quote"), List( ~[ Symbol(~"a") ] ) ] ),
    @Environment::new_global_environment() );
    io::println( stringify_expression( value ) );
    match value {
        List( [ Symbol( ~"a" ) ] ) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    let expression = parse( ~"(begin 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    let expression = parse( ~"(if 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    let expression = parse( ~"(if 0 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = parse( ~"(if 1 (begin 1 2) 7)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the then branch",
        _ => fail fmt!("If returned something unusual (%s)", stringify_expression(value))
    }
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = parse( ~"(if 0 7 (begin 1 2))" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the else branch",
        _ => fail fmt!("If returned something unusual (%s)", stringify_expression(value))
    }
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = parse( ~"(if (begin 1 0) 1 2)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(1) => fail ~"If didn't evaluate the test",
        Int(2) => (),
        _ => fail fmt!("If returned something unusual (%s)", stringify_expression(value))
    }
}

#[test]
fn test_that_bare_symbol_is_interpreted_as_variable() {
    let env = @Environment::new_global_environment();
    env.define(~"monkey", Int(10));
    let expression = parse( ~"monkey" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", stringify_expression(value))
    }
}

#[test]
#[should_fail]
fn test_that_undefined_symbol_is_an_error() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"monkey" );
    eval( expression, env );
}

fn eval( expression:Expression, environment:@Environment ) -> Expression {
    fn quote(expressions:~[Expression]) -> Expression {
        match expressions {
            [_, expr] => expr,
            _ => fail ~"Syntax Error: quote must take a single argument"
        }
    }

    fn if_(expressions:~[Expression], environment:@Environment) -> Expression {
        match expressions {
            [_, test, true_expr, false_expr] => {
                eval(if is_truthy( eval(test, environment) ) { true_expr } else { false_expr }, environment)
            }
            _ => fail ~"Syntax Error: if must take three arguments"
        }
    }

    fn begin(expressions:~[Expression], environment:@Environment) -> Expression {
        eval( copy expressions[ expressions.len() - 1], environment )
    }

    match copy expression {
        List( expressions ) => {
            match expressions[0] {
                Symbol(~"quote") => quote(expressions),
                Symbol(~"begin") => begin(expressions, environment),
                Symbol(~"if") => if_(expressions, environment),
                _ => expression
            }
        }
        Symbol( symbol ) => {
            match environment.lookup( copy symbol ) {
                Some( value ) => value,
                None => fail fmt!("Undefined symbol %s",symbol)
            }
        }
        _ => {
            expression
        }
    }
}

#[test]
fn test_is_truthy_returns_true_for_non_zero_numbers() {
    assert is_truthy( Int(1) );
    assert is_truthy( Int(-1) );
    assert is_truthy( Float(1.0) );
    assert is_truthy( Float(-1.0) );
}

#[test]
fn test_is_truthy_returns_false_for_zero_numbers() {
    assert !is_truthy( Int(0) );
    assert !is_truthy( Float(0.0) );
}

fn is_truthy( expression:Expression ) -> bool {
    match expression {
        Int( number ) => 0 != number,
        Float( number ) => 0.0 != number,
        _ => true
    }
}

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

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

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

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

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

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

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

    static fn new_global_environment() -> Environment {
        let mappings = std::treemap::TreeMap();
        Environment {enclosure:None, mappings:mappings}
    }

    static fn new(enclosure:~Environment) -> Environment {
        let mappings = std::treemap::TreeMap();
        Environment {enclosure:Some(enclosure), mappings:mappings}
    }
}

fn main() {
    io::println(stringify_expression( parse( "(1 2 3 (1 2 3))" ) ));
    io::println(stringify_expression( parse( "((1 2) 3 (1 2 3))" ) ));
    let blah:Expression = List(~[Int(1), List(~[Float(1.0), Symbol(~"xyz")])]);
    io::println(stringify_expression(blah));
    io::println( "(begin 1 2)" )
}
<|endoftext|>


<commit_before>use std::io::stdio;
use std::io::Process;
use std::io::process;
use std::path::posix::Path;

struct Shell {
    cmd_prompt: ~str,
    cwd: Path
}

impl Shell {
    fn new(prompt_str: &str, cwd: Path) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd: cwd
        }
    }

    fn start(&mut self) {
        let mut stdin = stdio::stdin();
        loop {
            stdio::print(self.cmd_prompt);
            stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "\u274c"  =>  { return; }
                _       =>  { self.cmd(cmd_line.clone()); }
                // _ => { println!("You just ran {}", cmd_line) }
            }
        }
    }

    fn cmd(&mut self, cmd_line: ~str) {
        let mut arg_vec = ~[];
        let mut cmd = ~"";
        for (index, s) in cmd_line.split_str(" ").enumerate() {
            if index == 0 { cmd = s.to_owned(); } else { arg_vec.push(s.to_owned()); }
        }
        self.run_cmd(cmd, arg_vec);
    }

    fn run_cmd(&mut self, cmd: ~str, argv: ~[~str]) {
        match cmd.as_slice() {
            &"\U0001F697" => self.cd(argv),
            &"\U0001F4CD" => self.pwd(),
            _ => self.execute_program(cmd, argv)
        }
    }

    fn execute_program(&mut self, cmd: ~str, argv: ~[~str]) {
        if self.cmd_exists(cmd) {
            println!("\U0001F3C3 {}", cmd);
            let config = process::ProcessConfig {
                program: cmd,
                args: argv,
                cwd: Some(&self.cwd),
                stdin: process::InheritFd(0),
                stdout: process::InheritFd(1),
                stderr: process::InheritFd(2),
                .. process::ProcessConfig::new()
            };

            let p = Process::configure(config);
            let status = p.unwrap().wait();
            match status {
                process::ExitSignal(st) => println!("Exited with signal {}", st),
                process::ExitStatus(st) => println!("Exited with status {}", st)
            }
        }
        else {
            println!("Command {} not found.", cmd)
        }
    }

    fn cd(&mut self, path: ~[~str]) {
        if path.len() == 0 {
            println!("Please specify a path to \U0001F697  to.");
            return;
        }
        let p = Path::new(path[0]);
        if !p.is_dir() {
            println!("\U0001F697  could not find that, \U0001F62D  ")
        }
        self.cwd = p;
    }

    fn pwd(&mut self) {
        println!("\u27A1 {} \u2B05  \U0001F4CD", self.cwd.as_str().unwrap());
    }

    fn cmd_exists(&mut self, cmd: &str) -> bool {
        let p = Process::new("which", [cmd.to_owned()]);
        let status = p.unwrap().wait();
        match status {
            process::ExitSignal(st) => st == 0,
            process::ExitStatus(st) => st == 0
        }
    }
}

fn main() {
    Shell::new("\U0001f41a  ", std::os::getcwd()).start();
}
<commit_msg>Update cmd to ignore empty parameters<commit_after>use std::io::stdio;
use std::io::Process;
use std::io::process;
use std::path::posix::Path;

struct Shell {
    cmd_prompt: ~str,
    cwd: Path
}

impl Shell {
    fn new(prompt_str: &str, cwd: Path) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd: cwd
        }
    }

    fn start(&mut self) {
        let mut stdin = stdio::stdin();
        loop {
            stdio::print(self.cmd_prompt);
            stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "\u274c"  =>  { return; }
                _       =>  { self.cmd(cmd_line.clone()); }
                // _ => { println!("You just ran {}", cmd_line) }
            }
        }
    }

    fn cmd(&mut self, cmd_line: ~str) {
        let mut arg_vec = ~[];
        let mut cmd = ~"";
        for (index, s) in cmd_line.split_str(" ").enumerate() {
            if s == "" { continue; }
            if index == 0 { cmd = s.to_owned(); } else { arg_vec.push(s.to_owned()); }
        }
        self.run_cmd(cmd, arg_vec);
    }

    fn run_cmd(&mut self, cmd: ~str, argv: ~[~str]) {
        match cmd.as_slice() {
            &"\U0001F697" => self.cd(argv),
            &"\U0001F4CD" => self.pwd(),
            _ => self.execute_program(cmd, argv)
        }
    }

    fn execute_program(&mut self, cmd: ~str, argv: ~[~str]) {
        if self.cmd_exists(cmd) {
            println!("\U0001F3C3 {}", cmd);
            let config = process::ProcessConfig {
                program: cmd,
                args: argv,
                cwd: Some(&self.cwd),
                stdin: process::InheritFd(0),
                stdout: process::InheritFd(1),
                stderr: process::InheritFd(2),
                .. process::ProcessConfig::new()
            };

            let p = Process::configure(config);
            let status = p.unwrap().wait();
            match status {
                process::ExitSignal(st) => println!("Exited with signal {}", st),
                process::ExitStatus(st) => println!("Exited with status {}", st)
            }
        }
        else {
            println!("Command {} not found.", cmd)
        }
    }

    fn cd(&mut self, path: ~[~str]) {
        if path.len() == 0 {
            println!("Please specify a path to \U0001F697  to.");
            return;
        }
        let p = Path::new(path[0]);
        if !p.is_dir() {
            println!("\U0001F697  could not find that, \U0001F62D  ")
        }
        self.cwd = p;
    }

    fn pwd(&mut self) {
        println!("\u27A1 {} \u2B05  \U0001F4CD", self.cwd.as_str().unwrap());
    }

    fn cmd_exists(&mut self, cmd: &str) -> bool {
        let p = Process::new("which", [cmd.to_owned()]);
        let status = p.unwrap().wait();
        match status {
            process::ExitSignal(st) => st == 0,
            process::ExitStatus(st) => st == 0
        }
    }
}

fn main() {
    Shell::new("\U0001f41a  ", std::os::getcwd()).start();
}
<|endoftext|>