<commit_before>use std::cmp::{self, Ordering};
use std::f32;
use std::convert::From;
use rand::Rng;
use std::ops::Sub;
use super::selection::tournament_selection_fast;

pub trait Mate<T> {
    fn mate<R: Rng>(&mut self, rng: &mut R, p1: &T, p2: &T) -> T;
}

pub trait Dominate<Rhs=Self> {
    fn dominates(&self, other: &Rhs) -> bool;
}

fn dominates_slices<T: Sized + PartialOrd>(sa: &[T], sb: &[T]) -> bool {
    assert!(sa.len() == sb.len());
    assert!(sa.len() > 0);

    let mut less_cnt = 0;
    for (a, b) in sa.iter().zip(sb.iter()) {
        if a > b {
            return false;
        } else if a < b {
            less_cnt += 1;
        }
    }

    return less_cnt > 0;
}

pub trait MultiObjective {
    fn num_objectives() -> usize;

    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering;

    // Distance between self and other
    fn dist_objective(&self, other: &Self, objective: usize) -> f32;
}

#[derive(Debug, Clone)]
pub struct MultiObjective2<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 2],
}

impl<T: Sized + PartialOrd + Copy + Clone> From<(T, T)> for MultiObjective2<T> {
    fn from(t: (T, T)) -> MultiObjective2<T> {
        MultiObjective2 { objectives: [t.0, t.1] }
    }
}

impl<T, R> MultiObjective for MultiObjective2<T>
    where T: Copy + PartialOrd + Sub<Output = R>,
          R: Into<f32>
{
    fn num_objectives() -> usize {
        2
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

impl<T: Sized + PartialOrd + Copy> Dominate for MultiObjective2<T> {
    fn dominates(&self, other: &Self) -> bool {
        dominates_slices(&self.objectives[..], &other.objectives[..])
    }
}

#[derive(Debug, Clone)]
pub struct MultiObjective3<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 3],
}

impl<T: Sized + PartialOrd + Copy + Clone> From<(T, T, T)> for MultiObjective3<T> {
    fn from(t: (T, T, T)) -> MultiObjective3<T> {
        MultiObjective3 { objectives: [t.0, t.1, t.2] }
    }
}

impl<T, R> MultiObjective for MultiObjective3<T>
    where T: Copy + PartialOrd + Sub<Output = R>,
          R: Into<f32>
{
    fn num_objectives() -> usize {
        3
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

impl<T: Sized + PartialOrd + Copy> Dominate for MultiObjective3<T> {
    fn dominates(&self, other: &Self) -> bool {
        dominates_slices(&self.objectives[..], &other.objectives[..])
    }
}

/// Stop after we have found `n` solutions (we include the whole pareto front, so it are probably more solutions).
fn fast_non_dominated_sort<P: Dominate>(solutions: &[P], n: usize) -> Vec<Vec<usize>> {
    let mut fronts: Vec<Vec<usize>> = Vec::new();
    let mut current_front = Vec::new();

    let mut domination_count: Vec<usize> = (0..solutions.len()).map(|_| 0).collect();
    let mut dominated_solutions: Vec<Vec<usize>> = (0..solutions.len())
                                                       .map(|_| Vec::new())
                                                       .collect();
    let mut found_solutions: usize = 0;

    for (i, p) in solutions.iter().enumerate() {
        for (j, q) in solutions.iter().enumerate() {
            if i == j {
                continue;
            }
            if p.dominates(q) {
                // Add `q` to the set of solutions dominated by `p`.
                dominated_solutions[i].push(j);
            } else if q.dominates(p) {
                // Increment domination counter of `p`.
                domination_count[i] += 1;
            }
        }

        if domination_count[i] == 0 {
            // `p` belongs to the first front as it is not dominated by any
            // other solution.
            current_front.push(i);
        }
    }

    while !current_front.is_empty() {
        found_solutions += current_front.len();
        if found_solutions >= n {
            fronts.push(current_front);
            break;
        } else {
            // we haven't found enough solutions yet.
            let mut next_front = Vec::new();
            for &p_i in current_front.iter() {
                for &q_i in dominated_solutions[p_i].iter() {
                    domination_count[q_i] -= 1;
                    if domination_count[q_i] == 0 {
                        // q belongs to the next front
                        next_front.push(q_i);
                    }
                }
            }
            fronts.push(current_front);
            current_front = next_front;
        }
    }

    return fronts;
}

#[derive(Debug)]
pub struct SolutionRankDist {
    pub idx: usize,
    pub rank: u32,
    pub dist: f32,
}

impl PartialEq for SolutionRankDist {
    #[inline]
    fn eq(&self, other: &SolutionRankDist) -> bool {
        self.rank == other.rank && self.dist == other.dist
    }
}

// Implement the crowding-distance comparison operator.
impl PartialOrd for SolutionRankDist {
    #[inline]
    // compare on rank first (ASC), then on dist (DESC)
    fn partial_cmp(&self, other: &SolutionRankDist) -> Option<Ordering> {
        match self.rank.partial_cmp(&other.rank) {
            Some(Ordering::Equal) => {
                // first criterion equal, second criterion decides
                // reverse ordering
                self.dist.partial_cmp(&other.dist).map(|i| i.reverse())
            }
            other => other,
        }
    }
}

fn crowding_distance_assignment<P: MultiObjective>(solutions: &[P],
                                                   common_rank: u32,
                                                   individuals_idx: &[usize])
                                                   -> Vec<SolutionRankDist> {
    let l = individuals_idx.len();
    let mut distance: Vec<f32> = (0..l).map(|_| 0.0).collect();
    let mut indices: Vec<usize> = (0..l).map(|i| i).collect();

    for m in 0..P::num_objectives() {
        // sort using objective `m`
        indices.sort_by(|&a, &b| {
            solutions[individuals_idx[a]].cmp_objective(&solutions[individuals_idx[b]], m)
        });
        distance[indices[0]] = f32::INFINITY;
        distance[indices[l - 1]] = f32::INFINITY;

        let min_idx = individuals_idx[indices[0]];
        let max_idx = individuals_idx[indices[l - 1]];

        let dist_max_min = solutions[max_idx].dist_objective(&solutions[min_idx], m);
        if dist_max_min != 0.0 {
            let norm = P::num_objectives() as f32 * dist_max_min;
            debug_assert!(norm != 0.0);
            for i in 1..(l - 1) {
                let next_idx = individuals_idx[indices[i + 1]];
                let prev_idx = individuals_idx[indices[i - 1]];
                distance[indices[i]] += solutions[next_idx]
                                            .dist_objective(&solutions[prev_idx], m) /
                                        norm;
            }
        }
    }

    return indices.iter()
                  .map(|&i| {
                      SolutionRankDist {
                          idx: individuals_idx[i],
                          rank: common_rank,
                          dist: distance[i],
                      }
                  })
                  .collect();
}

/// Select `n` out of the `solutions`, assigning rank and distance.
pub fn select<P: Dominate + MultiObjective>(solutions: &[P], n: usize) -> Vec<SolutionRankDist> {
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front[..]);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

pub trait FitnessEval<I, F:Dominate+MultiObjective+Clone> {
    fn fitness(&mut self, &[I]) -> Vec<F>;
}

pub fn iterate<R: Rng,
               I: Clone,
               F: Dominate + MultiObjective + Clone,
               T: Mate<I> + FitnessEval<I, F>>
    (rng: &mut R,
     population: Vec<I>,
     fitness: Vec<F>,
     pop_size: usize,
     offspring_size: usize,
     tournament_k: usize,
     toolbox: &mut T)
     -> (Vec<I>, Vec<F>) {
    assert!(tournament_k > 0);
    assert!(population.len() == fitness.len());

    // evaluate rank and crowding distance (using select()).
    let rank_dist = select(&fitness[..], pop_size);
    assert!(rank_dist.len() == pop_size);

    // create `offspring_size` new offspring using k-tournament (
    // select the best individual out of k randomly choosen individuals)
    let offspring: Vec<_> = (0..offspring_size)
                                .map(|_| {

                                    // first parent. k candidates
                                    let p1 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // second parent. k candidates
                                    let p2 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // cross-over the two parents and produce one child (throw away
                                    // second child XXX)

                                    // The potentially dominating individual is gives as first
                                    // parameter.
                                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                                        (p1, p2)
                                    } else if rank_dist[p2] < rank_dist[p1] {
                                        (p2, p1)
                                    } else {
                                        (p1, p2)
                                    };

                                    toolbox.mate(rng, &population[p1], &population[p2])
                                })
                                .collect();

    assert!(offspring.len() == offspring_size);

    // evaluate fitness of offspring
    let fitness_offspring = toolbox.fitness(&offspring[..]);
    assert!(fitness_offspring.len() == offspring.len());

    // merge population and offspring, then select
    let mut new_pop = Vec::with_capacity(rank_dist.len() + offspring.len());
    let mut new_fit = Vec::with_capacity(rank_dist.len() + offspring.len());
    for rd in rank_dist {
        new_pop.push(population[rd.idx].clone());
        new_fit.push(fitness[rd.idx].clone());
    }

    new_pop.extend(offspring);
    new_fit.extend(fitness_offspring);

    assert!(new_pop.len() == pop_size + offspring_size);
    assert!(new_fit.len() == pop_size + offspring_size);

    return (new_pop, new_fit);
}

#[test]
fn test_dominates() {
    let a = MultiObjective2 { objectives: [1.0, 0.1] };
    let b = MultiObjective2 { objectives: [0.1, 0.1] };
    let c = MultiObjective2 { objectives: [0.1, 1.0] };

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2 { objectives: [1.0, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 1.0] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });

    println!("solutions: {:?}", solutions);
    let selection = select(&solutions[..], 5);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..]);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<commit_msg>Generically implement Dominate for every MultiObjective<commit_after>use std::cmp::{self, Ordering};
use std::f32;
use std::convert::From;
use rand::Rng;
use std::ops::Sub;
use super::selection::tournament_selection_fast;

pub trait Mate<T> {
    fn mate<R: Rng>(&mut self, rng: &mut R, p1: &T, p2: &T) -> T;
}

pub trait Dominate<Rhs=Self> {
    fn dominates(&self, other: &Rhs) -> bool;
}

pub trait MultiObjective {
    fn num_objectives() -> usize;

    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering;

    // Distance between self and other
    fn dist_objective(&self, other: &Self, objective: usize) -> f32;

}

impl<T: MultiObjective> Dominate<T> for T {
    fn dominates(&self, other: &Self) -> bool {
        let mut less_cnt = 0;
        for i in 0..Self::num_objectives() {
            match self.cmp_objective(other, i) {
                Ordering::Greater => {
                    return false;
                }
                Ordering::Less => {
                    less_cnt += 1;
                }
                Ordering::Equal => {
                }
            }
        }
        return less_cnt > 0;
    }
}

#[derive(Debug, Clone)]
pub struct MultiObjective2<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 2],
}

impl<T: Sized + PartialOrd + Copy + Clone> From<(T, T)> for MultiObjective2<T> {
    fn from(t: (T, T)) -> MultiObjective2<T> {
        MultiObjective2 { objectives: [t.0, t.1] }
    }
}

impl<T, R> MultiObjective for MultiObjective2<T>
    where T: Copy + PartialOrd + Sub<Output = R>,
          R: Into<f32>
{
    fn num_objectives() -> usize {
        2
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

#[derive(Debug, Clone)]
pub struct MultiObjective3<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 3],
}

impl<T: Sized + PartialOrd + Copy + Clone> From<(T, T, T)> for MultiObjective3<T> {
    fn from(t: (T, T, T)) -> MultiObjective3<T> {
        MultiObjective3 { objectives: [t.0, t.1, t.2] }
    }
}

impl<T, R> MultiObjective for MultiObjective3<T>
    where T: Copy + PartialOrd + Sub<Output = R>,
          R: Into<f32>
{
    fn num_objectives() -> usize {
        3
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

/// Stop after we have found `n` solutions (we include the whole pareto front, so it are probably more solutions).
fn fast_non_dominated_sort<P: Dominate>(solutions: &[P], n: usize) -> Vec<Vec<usize>> {
    let mut fronts: Vec<Vec<usize>> = Vec::new();
    let mut current_front = Vec::new();

    let mut domination_count: Vec<usize> = (0..solutions.len()).map(|_| 0).collect();
    let mut dominated_solutions: Vec<Vec<usize>> = (0..solutions.len())
                                                       .map(|_| Vec::new())
                                                       .collect();
    let mut found_solutions: usize = 0;

    for (i, p) in solutions.iter().enumerate() {
        for (j, q) in solutions.iter().enumerate() {
            if i == j {
                continue;
            }
            if p.dominates(q) {
                // Add `q` to the set of solutions dominated by `p`.
                dominated_solutions[i].push(j);
            } else if q.dominates(p) {
                // Increment domination counter of `p`.
                domination_count[i] += 1;
            }
        }

        if domination_count[i] == 0 {
            // `p` belongs to the first front as it is not dominated by any
            // other solution.
            current_front.push(i);
        }
    }

    while !current_front.is_empty() {
        found_solutions += current_front.len();
        if found_solutions >= n {
            fronts.push(current_front);
            break;
        } else {
            // we haven't found enough solutions yet.
            let mut next_front = Vec::new();
            for &p_i in current_front.iter() {
                for &q_i in dominated_solutions[p_i].iter() {
                    domination_count[q_i] -= 1;
                    if domination_count[q_i] == 0 {
                        // q belongs to the next front
                        next_front.push(q_i);
                    }
                }
            }
            fronts.push(current_front);
            current_front = next_front;
        }
    }

    return fronts;
}

#[derive(Debug)]
pub struct SolutionRankDist {
    pub idx: usize,
    pub rank: u32,
    pub dist: f32,
}

impl PartialEq for SolutionRankDist {
    #[inline]
    fn eq(&self, other: &SolutionRankDist) -> bool {
        self.rank == other.rank && self.dist == other.dist
    }
}

// Implement the crowding-distance comparison operator.
impl PartialOrd for SolutionRankDist {
    #[inline]
    // compare on rank first (ASC), then on dist (DESC)
    fn partial_cmp(&self, other: &SolutionRankDist) -> Option<Ordering> {
        match self.rank.partial_cmp(&other.rank) {
            Some(Ordering::Equal) => {
                // first criterion equal, second criterion decides
                // reverse ordering
                self.dist.partial_cmp(&other.dist).map(|i| i.reverse())
            }
            other => other,
        }
    }
}

fn crowding_distance_assignment<P: MultiObjective>(solutions: &[P],
                                                   common_rank: u32,
                                                   individuals_idx: &[usize])
                                                   -> Vec<SolutionRankDist> {
    let l = individuals_idx.len();
    let mut distance: Vec<f32> = (0..l).map(|_| 0.0).collect();
    let mut indices: Vec<usize> = (0..l).map(|i| i).collect();

    for m in 0..P::num_objectives() {
        // sort using objective `m`
        indices.sort_by(|&a, &b| {
            solutions[individuals_idx[a]].cmp_objective(&solutions[individuals_idx[b]], m)
        });
        distance[indices[0]] = f32::INFINITY;
        distance[indices[l - 1]] = f32::INFINITY;

        let min_idx = individuals_idx[indices[0]];
        let max_idx = individuals_idx[indices[l - 1]];

        let dist_max_min = solutions[max_idx].dist_objective(&solutions[min_idx], m);
        if dist_max_min != 0.0 {
            let norm = P::num_objectives() as f32 * dist_max_min;
            debug_assert!(norm != 0.0);
            for i in 1..(l - 1) {
                let next_idx = individuals_idx[indices[i + 1]];
                let prev_idx = individuals_idx[indices[i - 1]];
                distance[indices[i]] += solutions[next_idx]
                                            .dist_objective(&solutions[prev_idx], m) /
                                        norm;
            }
        }
    }

    return indices.iter()
                  .map(|&i| {
                      SolutionRankDist {
                          idx: individuals_idx[i],
                          rank: common_rank,
                          dist: distance[i],
                      }
                  })
                  .collect();
}

/// Select `n` out of the `solutions`, assigning rank and distance.
pub fn select<P: Dominate + MultiObjective>(solutions: &[P], n: usize) -> Vec<SolutionRankDist> {
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front[..]);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

pub trait FitnessEval<I, F:Dominate+MultiObjective+Clone> {
    fn fitness(&mut self, &[I]) -> Vec<F>;
}

pub fn iterate<R: Rng,
               I: Clone,
               F: Dominate + MultiObjective + Clone,
               T: Mate<I> + FitnessEval<I, F>>
    (rng: &mut R,
     population: Vec<I>,
     fitness: Vec<F>,
     pop_size: usize,
     offspring_size: usize,
     tournament_k: usize,
     toolbox: &mut T)
     -> (Vec<I>, Vec<F>) {
    assert!(tournament_k > 0);
    assert!(population.len() == fitness.len());

    // evaluate rank and crowding distance (using select()).
    let rank_dist = select(&fitness[..], pop_size);
    assert!(rank_dist.len() == pop_size);

    // create `offspring_size` new offspring using k-tournament (
    // select the best individual out of k randomly choosen individuals)
    let offspring: Vec<_> = (0..offspring_size)
                                .map(|_| {

                                    // first parent. k candidates
                                    let p1 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // second parent. k candidates
                                    let p2 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // cross-over the two parents and produce one child (throw away
                                    // second child XXX)

                                    // The potentially dominating individual is gives as first
                                    // parameter.
                                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                                        (p1, p2)
                                    } else if rank_dist[p2] < rank_dist[p1] {
                                        (p2, p1)
                                    } else {
                                        (p1, p2)
                                    };

                                    toolbox.mate(rng, &population[p1], &population[p2])
                                })
                                .collect();

    assert!(offspring.len() == offspring_size);

    // evaluate fitness of offspring
    let fitness_offspring = toolbox.fitness(&offspring[..]);
    assert!(fitness_offspring.len() == offspring.len());

    // merge population and offspring, then select
    let mut new_pop = Vec::with_capacity(rank_dist.len() + offspring.len());
    let mut new_fit = Vec::with_capacity(rank_dist.len() + offspring.len());
    for rd in rank_dist {
        new_pop.push(population[rd.idx].clone());
        new_fit.push(fitness[rd.idx].clone());
    }

    new_pop.extend(offspring);
    new_fit.extend(fitness_offspring);

    assert!(new_pop.len() == pop_size + offspring_size);
    assert!(new_fit.len() == pop_size + offspring_size);

    return (new_pop, new_fit);
}

#[test]
fn test_dominates() {
    let a = MultiObjective2 { objectives: [1.0f32, 0.1] };
    let b = MultiObjective2 { objectives: [0.1f32, 0.1] };
    let c = MultiObjective2 { objectives: [0.1f32, 1.0] };

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2 { objectives: [1.0, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 1.0] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });

    println!("solutions: {:?}", solutions);
    let selection = select(&solutions[..], 5);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..]);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::path::Path;

#[allow(dead_code)]
pub enum Policy {
    Left, Right
}

pub struct Dict {
    wlst: Vec<Vec<char>>
}

impl Dict {
    pub fn default_path() -> &'static Path {
        Path::new(
            concat!(env!("CARGO_MANIFEST_DIR"),
                    "/data/tdict-std.txt"))
    }

    pub fn create<'a>(words: &Vec<String>) -> Result<Dict, &'a str> {
        Ok(Dict{wlst:words.iter().map(|w| w.chars().collect()).collect()})
    }

    pub fn load<'a>(path: &Path) -> Result<Dict, &'a str> {
        let mut f = match File::open(path) {
            Ok(f) => f,
            Err(_) => return Err("Cannot open dict")
        };
        let mut s = String::new();
        match f.read_to_string(&mut s) {
            Ok(_) => (),
            Err(_) => return Err("Cannot read dict")
        };
        let words = s.lines();
        let wlst: Vec<Vec<char>> = words.map(|w| w.chars().collect()).collect();
        Ok(Dict{wlst:wlst})
    }

    pub fn seek(&self, policy: Policy, _l: usize, _r: usize, offset: usize, ch: char) -> Option<usize> {
        let mut ans: usize = 0;
        let mut found = false;
        let mut m: usize;
        let mut l = _l as i64;
        let mut r = _r as i64;

        while l <= r {
            m = ((l + r) / 2) as usize;
            let w = &self.wlst[m];
            let wlen = w.len();
            if wlen <= offset {
                l = (m as i64) + 1;
            } else {
                let ch_ = w[offset];
                if ch_ < ch {
                    l = (m as i64) + 1;
                } else if ch_ > ch {
                    r = (m as i64) - 1;
                } else {
                    ans = m;
                    found = true;
                    match policy {
                        Policy::Left => r = (m as i64) - 1,
                        Policy::Right => l = (m as i64) + 1
                    }
                }
            }
        }
        if found {
            Some(ans)
        } else {
            None
        }
    }

    pub fn is_final(&self, len: usize, m: usize) -> bool {
        let w = &self.wlst[m];
        let wlen = w.len();
        wlen == len
    }

    pub fn r(&self) -> usize {
        self.wlst.len() - 1
    }
}
<commit_msg>lao path<commit_after>use std::fs::File;
use std::io::Read;
use std::path::Path;

#[allow(dead_code)]
pub enum Policy {
    Left, Right
}

pub struct Dict {
    wlst: Vec<Vec<char>>
}

impl Dict {
    pub fn default_path() -> &'static Path {
        Path::new(
            concat!(env!("CARGO_MANIFEST_DIR"),
                    "/data/tdict-std.txt"))
    }

    pub fn lao_path() -> &'static Path {
        Path::new(
            concat!(env!("CARGO_MANIFEST_DIR"),
                    "/data/laowords.txt"))
    }

    pub fn create<'a>(words: &Vec<String>) -> Result<Dict, &'a str> {
        Ok(Dict{wlst:words.iter().map(|w| w.chars().collect()).collect()})
    }

    pub fn load<'a>(path: &Path) -> Result<Dict, &'a str> {
        let mut f = match File::open(path) {
            Ok(f) => f,
            Err(_) => return Err("Cannot open dict")
        };
        let mut s = String::new();
        match f.read_to_string(&mut s) {
            Ok(_) => (),
            Err(_) => return Err("Cannot read dict")
        };
        let words = s.lines();
        let wlst: Vec<Vec<char>> = words.map(|w| w.chars().collect()).collect();
        Ok(Dict{wlst:wlst})
    }

    pub fn seek(&self, policy: Policy, _l: usize, _r: usize, offset: usize, ch: char) -> Option<usize> {
        let mut ans: usize = 0;
        let mut found = false;
        let mut m: usize;
        let mut l = _l as i64;
        let mut r = _r as i64;

        while l <= r {
            m = ((l + r) / 2) as usize;
            let w = &self.wlst[m];
            let wlen = w.len();
            if wlen <= offset {
                l = (m as i64) + 1;
            } else {
                let ch_ = w[offset];
                if ch_ < ch {
                    l = (m as i64) + 1;
                } else if ch_ > ch {
                    r = (m as i64) - 1;
                } else {
                    ans = m;
                    found = true;
                    match policy {
                        Policy::Left => r = (m as i64) - 1,
                        Policy::Right => l = (m as i64) + 1
                    }
                }
            }
        }
        if found {
            Some(ans)
        } else {
            None
        }
    }

    pub fn is_final(&self, len: usize, m: usize) -> bool {
        let w = &self.wlst[m];
        let wlen = w.len();
        wlen == len
    }

    pub fn r(&self) -> usize {
        self.wlst.len() - 1
    }
}
<|endoftext|>


<commit_before>use super::object::Object;
use super::object::Env;
use super::object::NULL;
use super::object::TRUE;
use super::object::FALSE;
use super::ast::Program;
use super::ast::Statement;
use super::ast::Expression;

fn to_boolean_object(val: bool) -> Object {
    if val {
        TRUE
    } else {
        FALSE
    }
}

pub struct Eval {
    env: Env,
}

impl Eval {
    pub fn new(env: Env) -> Self {
        Eval { env: env }
    }

    pub fn env(self) -> Env {
        self.env
    }

    pub fn eval(&mut self, program: Program) -> Object {
        self.eval_statements(&program.statements, false)
    }

    fn eval_statements(&mut self, stmts: &Vec<Statement>, nested: bool) -> Object {
        let mut result = NULL;

        for stmt in stmts {
            result = self.eval_statement(&stmt);

            match result {
                Object::ReturnValue(val) => {
                    if nested {
                        return Object::ReturnValue(val);
                    } else {
                        return *val;
                    }
                }
                r @ Object::Error(..) => {
                    return r;
                }
                _ => {
                    continue;
                }
            }
        }

        result
    }

    fn eval_statement(&mut self, stmt: &Statement) -> Object {
        match *stmt {
            Statement::Expression { ref expression, .. } => self.eval_expr(expression),
            Statement::Block { ref statements, .. } => self.eval_statements(statements, true),
            Statement::Return { ref value, .. } => {
                let mut return_val = NULL;
                if let Some(ref v) = *value {
                    return_val = self.eval_expr(v);
                }

                if return_val.is_error() {
                    return return_val;
                } else {
                    return Object::ReturnValue(Box::new(return_val));
                }
            }
            Statement::Let { ref value, ref name, .. } => {
                let val = self.eval_expr(value);
                if val.is_error() {
                    return val;
                }
                if let Expression::Identifier { ref value, .. } = *name {
                    self.env.set(value, val);
                    return NULL;
                } else {
                    return Object::Error("Internal interpreter error. Not an \
                                          Expression::Identifier in Statement::Let::expression."
                        .to_string());
                }
            }
        }
    }

    fn eval_expr(&mut self, expr: &Expression) -> Object {
        match *expr {
            Expression::IntegerLiteral { value, .. } => Object::Integer(value),
            Expression::Boolean { value, .. } => to_boolean_object(value),
            Expression::Prefix { ref operator, ref right, .. } => {
                let right = self.eval_expr(right);

                if right.is_error() {
                    return right;
                }

                self.eval_prefix_expr(operator, right)
            }
            Expression::Infix { ref left, ref right, ref operator, .. } => {
                let left = self.eval_expr(left);

                if left.is_error() {
                    return left;
                }

                let right = self.eval_expr(right);

                if right.is_error() {
                    return right;
                }

                self.eval_infix_expr(operator, left, right)
            }
            Expression::If { ref condition, ref consequence, ref alternative, .. } => {
                let cond = self.eval_expr(condition);

                if cond.is_error() {
                    return cond;
                }

                if cond.is_truthy() {
                    self.eval_statement(consequence)
                } else if let Some(ref alt) = *alternative {
                    self.eval_statement(alt)
                } else {
                    NULL
                }
            }
            Expression::Identifier { ref value, .. } => self.env.get(value),
            _ => NULL,
        }
    }

    fn eval_prefix_expr(&self, op: &str, right: Object) -> Object {
        match op {
            "!" => self.eval_bang_operator_expr(right),
            "-" => self.eval_minus_prefix_operator_expr(right),
            _ => Object::Error(format!("Unknown operator: {}{}", op, right)),
        }
    }

    fn eval_bang_operator_expr(&self, right: Object) -> Object {
        match right {
            Object::Boolean(true) => FALSE,
            Object::Boolean(false) => TRUE,
            Object::Null => TRUE,
            _ => FALSE,
        }
    }

    fn eval_minus_prefix_operator_expr(&self, right: Object) -> Object {
        match right {
            Object::Integer(val) => Object::Integer(-val),
            r @ _ => Object::Error(format!("Unknown operator: -{}", r)),
        }
    }

    fn eval_infix_expr(&self, op: &str, left: Object, right: Object) -> Object {
        match (op, left, right) {
            (_, Object::Integer(lval), Object::Integer(rval)) => {
                match op {
                    "+" => Object::Integer(lval + rval),
                    "-" => Object::Integer(lval - rval),
                    "*" => Object::Integer(lval * rval),
                    "/" => Object::Integer(lval / rval),
                    "<" => to_boolean_object(lval < rval),
                    ">" => to_boolean_object(lval > rval),
                    "==" => to_boolean_object(lval == rval),
                    "!=" => to_boolean_object(lval != rval),
                    _ => {
                        Object::Error(format!("Unknown operator: {} {} {}",
                                              Object::Integer(lval),
                                              op,
                                              Object::Integer(rval)))
                    }
                }
            }
            ("==", Object::Boolean(lval), Object::Boolean(rval)) => to_boolean_object(lval == rval),
            ("!=", Object::Boolean(lval), Object::Boolean(rval)) => to_boolean_object(lval != rval),
            (_, l @ Object::Integer(..), r @ Object::Boolean(..)) |
            (_, l @ Object::Boolean(..), r @ Object::Integer(..)) => {
                Object::Error(format!("Type mismatch: {} {} {}", l, op, r))
            }
            (_, l, r) => Object::Error(format!("Unknown operator: {} {} {}", l, op, r)),
        }
    }
}

#[cfg(test)]
use super::lexer::Lexer;
#[cfg(test)]
use super::parser::Parser;

#[cfg(test)]
fn test_eval(input: &str) -> Object {
    let mut l = Lexer::new(input.to_string());
    let mut p = Parser::new(&mut l);
    let program = p.parse_program();
    let mut eval = Eval::new(Env::new());

    eval.eval(program)
}

#[cfg(test)]
fn check_integer_object(obj: Object, expected: i64) {
    match obj {
        Object::Integer(val) => {
            assert!(val == expected, "Object has wrong value. Got {}, want {}", val, expected);
        }
        _ => panic!("Object is not an Integer. Got {:?}", obj),
    }
}

#[cfg(test)]
fn check_boolean_object(obj: Object, expected: bool) {
    match obj {
        Object::Boolean(val) => {
            assert!(val == expected, "Object has wrong value. Got {}, want {}", val, expected);
        }
        _ => panic!("Object is not an Boolean. Got {:?}", obj),
    }
}

#[cfg(test)]
fn check_null_object(obj: Object) {
    assert!(obj.is_null(), "obj is not NULL. Got {:?}", obj);
}

#[test]
fn test_eval_integer_expression() {
    let tests = vec![
        ("5", 5),
        ("10", 10),
        ("-5", -5),
        ("-10", -10),
        ("5 + 5 + 5 + 5 - 10", 10),
        ("-50 + 100 + -50", 0),
        ("5 * 2 + 10", 20),
        ("5 + 2 * 10", 25),
        ("2 * 2 * 2 * 2 * 2", 32),
        ("20 + 2 * -10", 0),
        ("50 / 2 * 2 + 10", 60),
        ("2 * (5 + 10)", 30),
        ("3 * 3 * 3 + 10", 37),
        ("3 * (3 * 3) + 10", 37),
        ("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}

#[test]
fn test_eval_boolean_expression() {
    let tests = vec![
        ("true", true),
        ("false", false),
        ("1 < 2", true),
        ("1 > 2", false),
        ("1 < 1", false),
        ("1 > 1", false),
        ("1 == 1", true),
        ("1 != 1", false),
        ("1 == 2", false),
        ("1 != 2", true),
        ("true == true", true),
        ("false == false", true),
        ("true == false", false),
        ("true != false", true),
        ("false!= true", true),
        ("(1 < 2) == true", true),
        ("(1 < 2) == false", false),
        ("(1 > 2) == true", false),
        ("(1 > 2) == false", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_bang_operator() {
    let tests = vec![
        ("!true", false),
        ("!false", true),
        ("!5", false),
        ("!!true", true),
        ("!!false", false),
        ("!!5", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_if_else_expressions() {
    let tests = vec![
        ("if (true) { 10 }", Object::Integer(10)),
        ("if (false) { 10 }", NULL),
        ("if (1) { 10 }", Object::Integer(10)),
        ("if (1 < 2) { 10 }", Object::Integer(10)),
        ("if (1 > 2) { 10 }", NULL),
        ("if (1 > 2) { 10 } else { 20 }", Object::Integer(20)),
        ("if (1 < 2) { 10 } else { 20 }", Object::Integer(10)),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        match expected {
            Object::Integer(val) => check_integer_object(evaluated, val),
            Object::Null => check_null_object(evaluated),
            _ => panic!("Fix the test."),
        }
    }
}

#[test]
fn test_return_statements() {
    let tests = vec![
        ("return 10;", 10),
        ("return 10; 9;", 10),
        ("return 2 * 5; 9;", 10),
        ("9; return 2 * 5; 9;", 10),
        ("if (10 > 1) {
            if (10 > 1) {
              return 10;
            }

            return 1;
         }", 10),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}

#[test]
fn test_error_handling() {
    let tests = vec![("5 + true;", "Type mismatch: Integer + Boolean"),
                     ("5 + true; 5;", "Type mismatch: Integer + Boolean"),
                     ("-true", "Unknown operator: -Boolean"),
                     ("true + false;", "Unknown operator: Boolean + Boolean"),
                     ("5; true + false; 5", "Unknown operator: Boolean + Boolean"),
                     ("if (10 > 1) { true + false; }", "Unknown operator: Boolean + Boolean"),
                     ("if (10 > 1) {
                if (10 > 1) {
                    return \
                       true + false;
                }
                return 1;
            }",
                      "Unknown operator: Boolean + Boolean"),
                     ("foobar", "Identifier not found: foobar")];

    for (input, expected) in tests {
        let evaluated = test_eval(input);

        if let Object::Error(ref msg) = evaluated {
            assert!(msg == expected, "Wrong error message. Expected\n{}\nGot\n{}", expected, msg);
        } else {
            panic!("Evaluated object is not Object::Error. Got {:?}", evaluated);
        }
    }
}

#[test]
fn test_let_statements() {
    let tests = vec![
        ("let a = 5; a;", 5),
        ("let a = 5 * 5; a;", 25),
        ("let a = 5; let b = a; b;", 5),
        ("let a = 5; let b = a; let c = a + b + 5; c;", 15),
    ];

    for (input, expected) in tests {
        check_integer_object(test_eval(input), expected);
    }
}
<commit_msg>Evaluating function literals.<commit_after>use super::object::Object;
use super::object::Env;
use super::object::NULL;
use super::object::TRUE;
use super::object::FALSE;
use super::ast::Program;
use super::ast::Statement;
use super::ast::Expression;

fn to_boolean_object(val: bool) -> Object {
    if val {
        TRUE
    } else {
        FALSE
    }
}

pub struct Eval {
    env: Env,
}

impl Eval {
    pub fn new(env: Env) -> Self {
        Eval { env: env }
    }

    pub fn env(self) -> Env {
        self.env
    }

    pub fn eval(&mut self, program: Program) -> Object {
        self.eval_statements(&program.statements, false)
    }

    fn eval_statements(&mut self, stmts: &Vec<Statement>, nested: bool) -> Object {
        let mut result = NULL;

        for stmt in stmts {
            result = self.eval_statement(&stmt);

            match result {
                Object::ReturnValue(val) => {
                    if nested {
                        return Object::ReturnValue(val);
                    } else {
                        return *val;
                    }
                }
                r @ Object::Error(..) => {
                    return r;
                }
                _ => {
                    continue;
                }
            }
        }

        result
    }

    fn eval_statement(&mut self, stmt: &Statement) -> Object {
        match *stmt {
            Statement::Expression { ref expression, .. } => self.eval_expr(expression),
            Statement::Block { ref statements, .. } => self.eval_statements(statements, true),
            Statement::Return { ref value, .. } => {
                let mut return_val = NULL;
                if let Some(ref v) = *value {
                    return_val = self.eval_expr(v);
                }

                if return_val.is_error() {
                    return return_val;
                } else {
                    return Object::ReturnValue(Box::new(return_val));
                }
            }
            Statement::Let { ref value, ref name, .. } => {
                let val = self.eval_expr(value);
                if val.is_error() {
                    return val;
                }
                if let Expression::Identifier { ref value, .. } = *name {
                    self.env.set(value, val);
                    return NULL;
                } else {
                    return Object::Error("Internal interpreter error. Not an \
                                          Expression::Identifier in Statement::Let::expression."
                        .to_string());
                }
            }
        }
    }

    fn eval_expr(&mut self, expr: &Expression) -> Object {
        match *expr {
            Expression::IntegerLiteral { value, .. } => Object::Integer(value),
            Expression::Boolean { value, .. } => to_boolean_object(value),
            Expression::Prefix { ref operator, ref right, .. } => {
                let right = self.eval_expr(right);

                if right.is_error() {
                    return right;
                }

                self.eval_prefix_expr(operator, right)
            }
            Expression::Infix { ref left, ref right, ref operator, .. } => {
                let left = self.eval_expr(left);

                if left.is_error() {
                    return left;
                }

                let right = self.eval_expr(right);

                if right.is_error() {
                    return right;
                }

                self.eval_infix_expr(operator, left, right)
            }
            Expression::If { ref condition, ref consequence, ref alternative, .. } => {
                let cond = self.eval_expr(condition);

                if cond.is_error() {
                    return cond;
                }

                if cond.is_truthy() {
                    self.eval_statement(consequence)
                } else if let Some(ref alt) = *alternative {
                    self.eval_statement(alt)
                } else {
                    NULL
                }
            }
            Expression::Identifier { ref value, .. } => self.env.get(value),
            Expression::FunctionLiteral { ref parameters, ref body, .. } => {
                Object::Function {
                    parameters: parameters.clone(),
                    body: *body.clone(),
                    env: self.env.clone(),
                }
            }
            _ => NULL,
        }
    }

    fn eval_prefix_expr(&self, op: &str, right: Object) -> Object {
        match op {
            "!" => self.eval_bang_operator_expr(right),
            "-" => self.eval_minus_prefix_operator_expr(right),
            _ => Object::Error(format!("Unknown operator: {}{}", op, right)),
        }
    }

    fn eval_bang_operator_expr(&self, right: Object) -> Object {
        match right {
            Object::Boolean(true) => FALSE,
            Object::Boolean(false) => TRUE,
            Object::Null => TRUE,
            _ => FALSE,
        }
    }

    fn eval_minus_prefix_operator_expr(&self, right: Object) -> Object {
        match right {
            Object::Integer(val) => Object::Integer(-val),
            r @ _ => Object::Error(format!("Unknown operator: -{}", r)),
        }
    }

    fn eval_infix_expr(&self, op: &str, left: Object, right: Object) -> Object {
        match (op, left, right) {
            (_, Object::Integer(lval), Object::Integer(rval)) => {
                match op {
                    "+" => Object::Integer(lval + rval),
                    "-" => Object::Integer(lval - rval),
                    "*" => Object::Integer(lval * rval),
                    "/" => Object::Integer(lval / rval),
                    "<" => to_boolean_object(lval < rval),
                    ">" => to_boolean_object(lval > rval),
                    "==" => to_boolean_object(lval == rval),
                    "!=" => to_boolean_object(lval != rval),
                    _ => {
                        Object::Error(format!("Unknown operator: {} {} {}",
                                              Object::Integer(lval),
                                              op,
                                              Object::Integer(rval)))
                    }
                }
            }
            ("==", Object::Boolean(lval), Object::Boolean(rval)) => to_boolean_object(lval == rval),
            ("!=", Object::Boolean(lval), Object::Boolean(rval)) => to_boolean_object(lval != rval),
            (_, l @ Object::Integer(..), r @ Object::Boolean(..)) |
            (_, l @ Object::Boolean(..), r @ Object::Integer(..)) => {
                Object::Error(format!("Type mismatch: {} {} {}", l, op, r))
            }
            (_, l, r) => Object::Error(format!("Unknown operator: {} {} {}", l, op, r)),
        }
    }
}

#[cfg(test)]
use super::lexer::Lexer;
#[cfg(test)]
use super::parser::Parser;
#[cfg(test)]
use super::ast::Node;

#[cfg(test)]
fn test_eval(input: &str) -> Object {
    let mut l = Lexer::new(input.to_string());
    let mut p = Parser::new(&mut l);
    let program = p.parse_program();
    let mut eval = Eval::new(Env::new());

    eval.eval(program)
}

#[cfg(test)]
fn check_integer_object(obj: Object, expected: i64) {
    match obj {
        Object::Integer(val) => {
            assert!(val == expected, "Object has wrong value. Got {}, want {}", val, expected);
        }
        _ => panic!("Object is not an Integer. Got {:?}", obj),
    }
}

#[cfg(test)]
fn check_boolean_object(obj: Object, expected: bool) {
    match obj {
        Object::Boolean(val) => {
            assert!(val == expected, "Object has wrong value. Got {}, want {}", val, expected);
        }
        _ => panic!("Object is not an Boolean. Got {:?}", obj),
    }
}

#[cfg(test)]
fn check_null_object(obj: Object) {
    assert!(obj.is_null(), "obj is not NULL. Got {:?}", obj);
}

#[test]
fn test_eval_integer_expression() {
    let tests = vec![
        ("5", 5),
        ("10", 10),
        ("-5", -5),
        ("-10", -10),
        ("5 + 5 + 5 + 5 - 10", 10),
        ("-50 + 100 + -50", 0),
        ("5 * 2 + 10", 20),
        ("5 + 2 * 10", 25),
        ("2 * 2 * 2 * 2 * 2", 32),
        ("20 + 2 * -10", 0),
        ("50 / 2 * 2 + 10", 60),
        ("2 * (5 + 10)", 30),
        ("3 * 3 * 3 + 10", 37),
        ("3 * (3 * 3) + 10", 37),
        ("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}

#[test]
fn test_eval_boolean_expression() {
    let tests = vec![
        ("true", true),
        ("false", false),
        ("1 < 2", true),
        ("1 > 2", false),
        ("1 < 1", false),
        ("1 > 1", false),
        ("1 == 1", true),
        ("1 != 1", false),
        ("1 == 2", false),
        ("1 != 2", true),
        ("true == true", true),
        ("false == false", true),
        ("true == false", false),
        ("true != false", true),
        ("false!= true", true),
        ("(1 < 2) == true", true),
        ("(1 < 2) == false", false),
        ("(1 > 2) == true", false),
        ("(1 > 2) == false", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_bang_operator() {
    let tests = vec![
        ("!true", false),
        ("!false", true),
        ("!5", false),
        ("!!true", true),
        ("!!false", false),
        ("!!5", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_if_else_expressions() {
    let tests = vec![
        ("if (true) { 10 }", Object::Integer(10)),
        ("if (false) { 10 }", NULL),
        ("if (1) { 10 }", Object::Integer(10)),
        ("if (1 < 2) { 10 }", Object::Integer(10)),
        ("if (1 > 2) { 10 }", NULL),
        ("if (1 > 2) { 10 } else { 20 }", Object::Integer(20)),
        ("if (1 < 2) { 10 } else { 20 }", Object::Integer(10)),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        match expected {
            Object::Integer(val) => check_integer_object(evaluated, val),
            Object::Null => check_null_object(evaluated),
            _ => panic!("Fix the test."),
        }
    }
}

#[test]
fn test_return_statements() {
    let tests = vec![
        ("return 10;", 10),
        ("return 10; 9;", 10),
        ("return 2 * 5; 9;", 10),
        ("9; return 2 * 5; 9;", 10),
        ("if (10 > 1) {
            if (10 > 1) {
              return 10;
            }

            return 1;
         }", 10),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}

#[test]
fn test_error_handling() {
    let tests = vec![("5 + true;", "Type mismatch: Integer + Boolean"),
                     ("5 + true; 5;", "Type mismatch: Integer + Boolean"),
                     ("-true", "Unknown operator: -Boolean"),
                     ("true + false;", "Unknown operator: Boolean + Boolean"),
                     ("5; true + false; 5", "Unknown operator: Boolean + Boolean"),
                     ("if (10 > 1) { true + false; }", "Unknown operator: Boolean + Boolean"),
                     ("if (10 > 1) {
                if (10 > 1) {
                    return \
                       true + false;
                }
                return 1;
            }",
                      "Unknown operator: Boolean + Boolean"),
                     ("foobar", "Identifier not found: foobar")];

    for (input, expected) in tests {
        let evaluated = test_eval(input);

        if let Object::Error(ref msg) = evaluated {
            assert!(msg == expected, "Wrong error message. Expected\n{}\nGot\n{}", expected, msg);
        } else {
            panic!("Evaluated object is not Object::Error. Got {:?}", evaluated);
        }
    }
}

#[test]
fn test_let_statements() {
    let tests = vec![
        ("let a = 5; a;", 5),
        ("let a = 5 * 5; a;", 25),
        ("let a = 5; let b = a; b;", 5),
        ("let a = 5; let b = a; let c = a + b + 5; c;", 15),
    ];

    for (input, expected) in tests {
        check_integer_object(test_eval(input), expected);
    }
}

#[test]
fn test_function_object() {
    let input = "fn(x) { x + 2; };";

    let evaluated = test_eval(input);

    if let Object::Function { parameters, body, .. } = evaluated {
        assert!(parameters.len() == 1, "Function has wrong parameters - {:?}", parameters);
        assert!(parameters[0].string() == "x", "parameter is not 'x'. Got {:?}", parameters[0]);

        let expected_body = "(x + 2)";
        assert!(body.string() == expected_body,
                "Body is not {}. Got {}",
                expected_body,
                body.string());
    } else {
        panic!("Object is not a Function. Got {:?}", evaluated);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use ring::digest::Algorithm;

use hashutils::HashUtils;
use tree::Tree;

/// An inclusion proof represent the fact that a `value` is a member
/// of a `MerkleTree` with root hash `root_hash`, and hash function `algorithm`.
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct Proof<T> {
    /// The hashing algorithm used in the original `MerkleTree`
    #[cfg_attr(feature = "serialization-serde", serde(with = "algorithm_serde"))]
    pub algorithm: &'static Algorithm,

    /// The hash of the root of the original `MerkleTree`
    pub root_hash: Vec<u8>,

    /// The first `Lemma` of the `Proof`
    pub lemma: Lemma,

    /// The value concerned by this `Proof`
    pub value: T,
}

#[cfg(feature = "serialization-serde")]
mod algorithm_serde {
    use ring::digest::{self, Algorithm};
    use serde::de::Error;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    pub fn serialize<S: Serializer>(
        algorithm: &'static Algorithm,
        se: S,
    ) -> Result<S::Ok, S::Error> {
        // The `Debug` implementation of `Algorithm` prints its ID.
        format!("{:?}", algorithm).serialize(se)
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<&'static Algorithm, D::Error> {
        match Deserialize::deserialize(de)? {
            "SHA1" => Ok(&digest::SHA1),
            "SHA256" => Ok(&digest::SHA256),
            "SHA384" => Ok(&digest::SHA384),
            "SHA512" => Ok(&digest::SHA512),
            "SHA512_256" => Ok(&digest::SHA512_256),
            _ => Err(D::Error::custom("unknown hash algorithm")),
        }
    }

    mod test {
        use super::*;
        use ring::digest::{
            SHA1 as sha1, SHA256 as sha256, SHA384 as sha384, SHA512 as sha512,
            SHA512_256 as sha512_256,
        };

        static SHA1: &Algorithm = &sha1;
        static SHA256: &Algorithm = &sha256;
        static SHA384: &Algorithm = &sha384;
        static SHA512: &Algorithm = &sha512;
        static SHA512_256: &Algorithm = &sha512_256;

        #[test]
        fn test_serialize_known_algorithms() {
            extern crate serde_json;

            for alg in [SHA1, SHA256, SHA384, SHA512, SHA512_256].iter() {
                let mut serializer = serde_json::Serializer::with_formatter(
                    vec![],
                    serde_json::ser::PrettyFormatter::new(),
                );

                let _ = serialize(alg, &mut serializer).expect(&format!("{:?}", alg));
                let alg_ = deserialize(&mut serde_json::Deserializer::from_slice(
                    &serializer.into_inner()[..],
                )).expect(&format!("{:?}", alg));

                assert_eq!(*alg, alg_);
            }
        }

        #[test]
        #[should_panic(expected = "unknown hash algorithm")]
        fn test_serialize_unknown_algorithm() {
            extern crate serde_json;
            {
                let alg_str = "\"BLAKE2b\"";
                let mut deserializer = serde_json::Deserializer::from_str(alg_str);
                let _ = deserialize(&mut deserializer).expect(&format!("{:?}", alg_str));
            }
        }
    }
}

impl<T: PartialEq> PartialEq for Proof<T> {
    fn eq(&self, other: &Proof<T>) -> bool {
        self.root_hash == other.root_hash && self.lemma == other.lemma && self.value == other.value
    }
}

impl<T: Eq> Eq for Proof<T> {}

impl<T: Ord> PartialOrd for Proof<T> {
    fn partial_cmp(&self, other: &Proof<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: Ord> Ord for Proof<T> {
    fn cmp(&self, other: &Proof<T>) -> Ordering {
        self.root_hash
            .cmp(&other.root_hash)
            .then(self.value.cmp(&other.value))
            .then_with(|| self.lemma.cmp(&other.lemma))
    }
}

impl<T: Hash> Hash for Proof<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.root_hash.hash(state);
        self.lemma.hash(state);
        self.value.hash(state);
    }
}

impl<T> Proof<T> {
    /// Constructs a new `Proof`
    pub fn new(algorithm: &'static Algorithm, root_hash: Vec<u8>, lemma: Lemma, value: T) -> Self {
        Proof {
            algorithm,
            root_hash,
            lemma,
            value,
        }
    }

    /// Checks whether this inclusion proof is well-formed,
    /// and whether its root hash matches the given `root_hash`.
    pub fn validate(&self, root_hash: &[u8]) -> bool {
        if self.root_hash != root_hash || self.lemma.node_hash != root_hash {
            return false;
        }

        self.validate_lemma(&self.lemma)
    }

    fn validate_lemma(&self, lemma: &Lemma) -> bool {
        match lemma.sub_lemma {
            None => lemma.sibling_hash.is_none(),

            Some(ref sub) => match lemma.sibling_hash {
                None => false,

                Some(Positioned::Left(ref hash)) => {
                    let combined = self.algorithm.hash_nodes(hash, &sub.node_hash);
                    let hashes_match = combined.as_ref() == lemma.node_hash.as_slice();
                    hashes_match && self.validate_lemma(sub)
                }

                Some(Positioned::Right(ref hash)) => {
                    let combined = self.algorithm.hash_nodes(&sub.node_hash, hash);
                    let hashes_match = combined.as_ref() == lemma.node_hash.as_slice();
                    hashes_match && self.validate_lemma(sub)
                }
            },
        }
    }
}

/// A `Lemma` holds the hash of a node, the hash of its sibling node,
/// and a sub lemma, whose `node_hash`, when combined with this `sibling_hash`
/// must be equal to this `node_hash`.
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Lemma {
    pub node_hash: Vec<u8>,
    pub sibling_hash: Option<Positioned<Vec<u8>>>,
    pub sub_lemma: Option<Box<Lemma>>,
}

impl Lemma {
    /// Attempts to generate a proof that the a value with hash `needle` is a member of the given `tree`.
    pub fn new<T>(tree: &Tree<T>, needle: &[u8]) -> Option<Lemma> {
        match *tree {
            Tree::Empty { .. } => None,

            Tree::Leaf { ref hash, .. } => Lemma::new_leaf_proof(hash, needle),

            Tree::Node {
                ref hash,
                ref left,
                ref right,
            } => Lemma::new_tree_proof(hash, needle, left, right),
        }
    }

    fn new_leaf_proof(hash: &[u8], needle: &[u8]) -> Option<Lemma> {
        if *hash == *needle {
            Some(Lemma {
                node_hash: hash.into(),
                sibling_hash: None,
                sub_lemma: None,
            })
        } else {
            None
        }
    }

    fn new_tree_proof<T>(
        hash: &[u8],
        needle: &[u8],
        left: &Tree<T>,
        right: &Tree<T>,
    ) -> Option<Lemma> {
        Lemma::new(left, needle)
            .map(|lemma| {
                let right_hash = right.hash().clone();
                let sub_lemma = Some(Positioned::Right(right_hash));
                (lemma, sub_lemma)
            })
            .or_else(|| {
                let sub_lemma = Lemma::new(right, needle);
                sub_lemma.map(|lemma| {
                    let left_hash = left.hash().clone();
                    let sub_lemma = Some(Positioned::Left(left_hash));
                    (lemma, sub_lemma)
                })
            })
            .map(|(sub_lemma, sibling_hash)| Lemma {
                node_hash: hash.into(),
                sibling_hash,
                sub_lemma: Some(Box::new(sub_lemma)),
            })
    }
}

/// Tags a value so that we know from which branch of a `Tree` (if any) it was found.
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Positioned<T> {
    /// The value was found in the left branch
    Left(T),

    /// The value was found in the right branch
    Right(T),
}
<commit_msg>Move Proof::validate_lemma to Lemma::validate<commit_after>use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use ring::digest::Algorithm;

use hashutils::HashUtils;
use tree::Tree;

/// An inclusion proof represent the fact that a `value` is a member
/// of a `MerkleTree` with root hash `root_hash`, and hash function `algorithm`.
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct Proof<T> {
    /// The hashing algorithm used in the original `MerkleTree`
    #[cfg_attr(feature = "serialization-serde", serde(with = "algorithm_serde"))]
    pub algorithm: &'static Algorithm,

    /// The hash of the root of the original `MerkleTree`
    pub root_hash: Vec<u8>,

    /// The first `Lemma` of the `Proof`
    pub lemma: Lemma,

    /// The value concerned by this `Proof`
    pub value: T,
}

#[cfg(feature = "serialization-serde")]
mod algorithm_serde {
    use ring::digest::{self, Algorithm};
    use serde::de::Error;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    pub fn serialize<S: Serializer>(
        algorithm: &'static Algorithm,
        se: S,
    ) -> Result<S::Ok, S::Error> {
        // The `Debug` implementation of `Algorithm` prints its ID.
        format!("{:?}", algorithm).serialize(se)
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<&'static Algorithm, D::Error> {
        match Deserialize::deserialize(de)? {
            "SHA1" => Ok(&digest::SHA1),
            "SHA256" => Ok(&digest::SHA256),
            "SHA384" => Ok(&digest::SHA384),
            "SHA512" => Ok(&digest::SHA512),
            "SHA512_256" => Ok(&digest::SHA512_256),
            _ => Err(D::Error::custom("unknown hash algorithm")),
        }
    }

    mod test {
        use super::*;
        use ring::digest::{
            SHA1 as sha1, SHA256 as sha256, SHA384 as sha384, SHA512 as sha512,
            SHA512_256 as sha512_256,
        };

        static SHA1: &Algorithm = &sha1;
        static SHA256: &Algorithm = &sha256;
        static SHA384: &Algorithm = &sha384;
        static SHA512: &Algorithm = &sha512;
        static SHA512_256: &Algorithm = &sha512_256;

        #[test]
        fn test_serialize_known_algorithms() {
            extern crate serde_json;

            for alg in [SHA1, SHA256, SHA384, SHA512, SHA512_256].iter() {
                let mut serializer = serde_json::Serializer::with_formatter(
                    vec![],
                    serde_json::ser::PrettyFormatter::new(),
                );

                let _ = serialize(alg, &mut serializer).expect(&format!("{:?}", alg));
                let alg_ = deserialize(&mut serde_json::Deserializer::from_slice(
                    &serializer.into_inner()[..],
                )).expect(&format!("{:?}", alg));

                assert_eq!(*alg, alg_);
            }
        }

        #[test]
        #[should_panic(expected = "unknown hash algorithm")]
        fn test_serialize_unknown_algorithm() {
            extern crate serde_json;
            {
                let alg_str = "\"BLAKE2b\"";
                let mut deserializer = serde_json::Deserializer::from_str(alg_str);
                let _ = deserialize(&mut deserializer).expect(&format!("{:?}", alg_str));
            }
        }
    }
}

impl<T: PartialEq> PartialEq for Proof<T> {
    fn eq(&self, other: &Proof<T>) -> bool {
        self.root_hash == other.root_hash && self.lemma == other.lemma && self.value == other.value
    }
}

impl<T: Eq> Eq for Proof<T> {}

impl<T: Ord> PartialOrd for Proof<T> {
    fn partial_cmp(&self, other: &Proof<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: Ord> Ord for Proof<T> {
    fn cmp(&self, other: &Proof<T>) -> Ordering {
        self.root_hash
            .cmp(&other.root_hash)
            .then(self.value.cmp(&other.value))
            .then_with(|| self.lemma.cmp(&other.lemma))
    }
}

impl<T: Hash> Hash for Proof<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.root_hash.hash(state);
        self.lemma.hash(state);
        self.value.hash(state);
    }
}

impl<T> Proof<T> {
    /// Constructs a new `Proof`
    pub fn new(algorithm: &'static Algorithm, root_hash: Vec<u8>, lemma: Lemma, value: T) -> Self {
        Proof {
            algorithm,
            root_hash,
            lemma,
            value,
        }
    }

    /// Checks whether this inclusion proof is well-formed,
    /// and whether its root hash matches the given `root_hash`.
    pub fn validate(&self, root_hash: &[u8]) -> bool {
        if self.root_hash != root_hash || self.lemma.node_hash != root_hash {
            return false;
        }

        self.lemma.validate(self.algorithm)
    }

}

/// A `Lemma` holds the hash of a node, the hash of its sibling node,
/// and a sub lemma, whose `node_hash`, when combined with this `sibling_hash`
/// must be equal to this `node_hash`.
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Lemma {
    pub node_hash: Vec<u8>,
    pub sibling_hash: Option<Positioned<Vec<u8>>>,
    pub sub_lemma: Option<Box<Lemma>>,
}

impl Lemma {
    /// Attempts to generate a proof that the a value with hash `needle` is a member of the given `tree`.
    pub fn new<T>(tree: &Tree<T>, needle: &[u8]) -> Option<Lemma> {
        match *tree {
            Tree::Empty { .. } => None,

            Tree::Leaf { ref hash, .. } => Lemma::new_leaf_proof(hash, needle),

            Tree::Node {
                ref hash,
                ref left,
                ref right,
            } => Lemma::new_tree_proof(hash, needle, left, right),
        }
    }

    fn new_leaf_proof(hash: &[u8], needle: &[u8]) -> Option<Lemma> {
        if *hash == *needle {
            Some(Lemma {
                node_hash: hash.into(),
                sibling_hash: None,
                sub_lemma: None,
            })
        } else {
            None
        }
    }

    fn new_tree_proof<T>(
        hash: &[u8],
        needle: &[u8],
        left: &Tree<T>,
        right: &Tree<T>,
    ) -> Option<Lemma> {
        Lemma::new(left, needle)
            .map(|lemma| {
                let right_hash = right.hash().clone();
                let sub_lemma = Some(Positioned::Right(right_hash));
                (lemma, sub_lemma)
            })
            .or_else(|| {
                let sub_lemma = Lemma::new(right, needle);
                sub_lemma.map(|lemma| {
                    let left_hash = left.hash().clone();
                    let sub_lemma = Some(Positioned::Left(left_hash));
                    (lemma, sub_lemma)
                })
            })
            .map(|(sub_lemma, sibling_hash)| Lemma {
                node_hash: hash.into(),
                sibling_hash,
                sub_lemma: Some(Box::new(sub_lemma)),
            })
    }

    fn validate(&self, algorithm: &'static Algorithm) -> bool {
        match self.sub_lemma {
            None => self.sibling_hash.is_none(),

            Some(ref sub) => match self.sibling_hash {
                None => false,

                Some(Positioned::Left(ref hash)) => {
                    let combined = algorithm.hash_nodes(hash, &sub.node_hash);
                    let hashes_match = combined.as_ref() == self.node_hash.as_slice();
                    hashes_match && sub.validate(algorithm)
                }

                Some(Positioned::Right(ref hash)) => {
                    let combined = algorithm.hash_nodes(&sub.node_hash, hash);
                    let hashes_match = combined.as_ref() == self.node_hash.as_slice();
                    hashes_match && sub.validate(algorithm)
                }
            },
        }
    }
}

/// Tags a value so that we know from which branch of a `Tree` (if any) it was found.
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Positioned<T> {
    /// The value was found in the left branch
    Left(T),

    /// The value was found in the right branch
    Right(T),
}
<|endoftext|>


<commit_before>extern mod std;
use task::spawn;
use io::{Reader,ReaderUtil};

mod environment;
use environment::Environment;
mod expression;
use expression::Expression;
use expression::{Int,Float,Symbol,List,Proc};
mod parse;
use parse::parse;

#[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() );
    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)", value.to_str())
    }
}

#[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)", value.to_str())
    }
}

#[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)", value.to_str())
    }
}

#[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", value.to_str())
    }
}

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

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

#[test]
#[should_fail]
fn test_that_set_cannot_create_a_variable() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(set! x 10)" );
    eval( expression, env );
}

#[test]
fn test_that_set_can_change_a_variable() {
    let env = @Environment::new_global_environment();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_set_returns_the_value_not_the_key() {
    let env = @Environment::new_global_environment();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        Symbol(~"x") => fail ~"set! returned the key, not the value",
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

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

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

#[test]
fn test_that_other_symbols_are_evaluated_as_procs() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(+ 1 2)" );
    let value = eval( expression, env );
    match value {
        Int(3) => (),
        _ => fail fmt!("(+ 1 2) became %s", value.to_str())
    }
}

#[test]
fn test_that_proc_params_are_evaluated() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"(+ (+ 1 2) 3)" );
    let value = eval (expression, env);
    match value {
        Int(6) => (),
        _ => fail fmt!("(+ (+ 1 2) 3) became %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_evaluates_to_a_proc() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"(lambda (x) (* x x))" );
    let value = eval(expression, env);
    match value {
        Proc(_) => (),
        _ => fail ~"lambda doesn't turn into a Proc"
    }
}

#[test]
fn test_that_lambda_without_variables_evals() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"( (lambda () (+ 1 1))  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_with_a_variable_evals() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"( (lambda (x) (+ x 1)) 1  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

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 begin(expressions:~[Expression], environment:@Environment) -> Expression {
        for expressions.tail().init().each() |&expression| {
            eval( expression, environment );
        }
        eval( expressions.last(), environment )
    }

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

    fn reset_variable(expressions:~[Expression], environment:@Environment, function:~str) -> Expression {
        match expressions {
            [_, symbol, value] => {
                match copy symbol {
                    Symbol( key ) => {
                        environment.define(key, eval(value, environment));
                        symbol
                    }
                    _ => fail fmt!("Syntax Error: %s takes a symbol as its first argument", function)
                }
            }
            _ => fail fmt!("Syntax Error: %s must take two arguments", function)
        }
    }

    fn define(expressions:~[Expression], environment:@Environment) -> Expression {
        reset_variable(expressions, environment, ~"define")
    }

    fn set_bang(expressions:~[Expression], environment:@Environment) -> Expression {
        match copy expressions {
            [_, symbol, _] => {
                match copy symbol {
                    Symbol( key ) => {
                        match environment.lookup( copy key )  {
                            None => fail ~"Syntax Error: set! cannot create a variable",
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
            _ => ()
        }
        let symbol = reset_variable(expressions, environment, ~"set!");
        match copy symbol {
            Symbol( key ) => {
                match environment.lookup( copy key ) {
                    Some( value ) => value,
                    None => fail
                }
            }
            _ => fail
        }
    }

    fn proc(expressions:~[Expression], environment:@Environment) -> Expression {
        let exprs = expressions.map(|&expr| eval(expr, environment));
        match exprs.head() {
            Proc( procedure ) => procedure( exprs.tail(), environment ),
            _ => fail fmt!("\"%s\" is not a procedure", exprs.head().to_str())
        }
    }

    fn lambda(expressions:~[Expression], _:@Environment) -> Expression {
        match copy expressions {
            [_, List(param_names), expression] => Proc( |param_values, env| {
                    let local_env = @Environment::new( env );
                    for vec::zip(copy param_names, param_values).each |param| {
                        match param.first() {
                            Symbol(key) => local_env.define( key, param.second() ),
                            _ => fail ~"lambda params list must be list of symbols"
                        }
                    }
                    eval(copy expression, local_env)
                } ),
            _ => fail fmt!("Syntax Error: lambda requires 2 arguments, got \"%u\"", expressions.len()-1 )
        }
    }

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

fn main() {
    fn evaluate( expr:~str ) {
        let sent_expr = copy expr;
        let result = do task::try {
            let env = @Environment::new_global_environment();
            eval( parse(sent_expr), env )
        };
        if result.is_ok() {
            io::println( fmt!("%s -> %s", expr, result.unwrap().to_str()) );
        } else {
            io::println( fmt!("%s gave an error.", expr) );
        }
    }

    evaluate( ~"(* 4 99)" );
    evaluate( ~"(begin (define square (lambda (x) (* x x))) (square 4))" );
    evaluate( ~"(7 7)" );

    loop {
        io::print("rusty> ");
        let in = io::stdin().read_line();
        evaluate( in );
    }
}
<commit_msg>refactor some tests of eval<commit_after>extern mod std;
use task::spawn;
use io::{Reader,ReaderUtil};

mod environment;
use environment::Environment;
mod expression;
use expression::Expression;
use expression::{Int,Float,Symbol,List,Proc};
mod parse;
use parse::parse;

fn test_env() -> @Environment {
    @Environment::new_global_environment()
}

fn test_eval( expr:&str, result:&str ) {
    let evaluated = eval(parse(expr), test_env());
    let expected = parse(result);
    if expected != evaluated {
        fail fmt!("Expected: %s -> Got %s", expected.to_str(), evaluated.to_str())
    }
}

fn test_eval_fails( expr:&str, result:&str, reason:&str ) {
    let evaluated = eval(parse(expr), test_env());
    let expected = parse(result);
    if expected == evaluated {
        fail fmt!("%s should not have evaluated to %s (%s)", expr, result, reason)
    }
}

#[test]
fn test_eval_returns_number_when_passed_number() {
    test_eval( ~"1", ~"1" );
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    test_eval( ~"(quote (a))", ~"(a)" );
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    test_eval( ~"(begin 1 2 3)", ~"3" );
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    test_eval( ~"(if 1 2 3)", ~"2" );
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    test_eval( ~"(if 0 2 3)", ~"3" );
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = ~"(if 1 (begin 1 2) 7)";
    test_eval_fails( expression, ~"(begin 1 2)", ~"if just returned the raw then" );
    test_eval( expression, ~"2" );
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = ~"(if 0 7 (begin 1 2))";
    test_eval_fails( expression, ~"(begin 1 2)", ~"if just returned the else branch" );
    test_eval( expression, ~"2");
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = ~"(if (begin 1 0) 1 2)";
    test_eval_fails( expression, ~"1", ~"if didn't evaluate the test" );
    test_eval( expression, ~"2" );
}

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

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

#[test]
fn test_that_define_can_add_a_variable() {
    let env = test_env();
    let expression = parse( ~"(define x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
#[should_fail]
fn test_that_set_cannot_create_a_variable() {
    let env = test_env();
    let expression = parse( ~"(set! x 10)" );
    eval( expression, env );
}

#[test]
fn test_that_set_can_change_a_variable() {
    let env = test_env();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_set_returns_the_value_not_the_key() {
    let env = test_env();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        Symbol(~"x") => fail ~"set! returned the key, not the value",
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_begin_can_handle_one_argument() {
    let env = test_env();
    let expression = parse( ~"(begin 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_begin_evaluates_all_arguments() {
    let env = test_env();
    let expression = parse( ~"(begin (define x 10) x)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_other_symbols_are_evaluated_as_procs() {
    let env = test_env();
    let expression = parse( ~"(+ 1 2)" );
    let value = eval( expression, env );
    match value {
        Int(3) => (),
        _ => fail fmt!("(+ 1 2) became %s", value.to_str())
    }
}

#[test]
fn test_that_proc_params_are_evaluated() {
    let env=test_env();
    let expression = parse( ~"(+ (+ 1 2) 3)" );
    let value = eval (expression, env);
    match value {
        Int(6) => (),
        _ => fail fmt!("(+ (+ 1 2) 3) became %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_evaluates_to_a_proc() {
    let env=test_env();
    let expression = parse( ~"(lambda (x) (* x x))" );
    let value = eval(expression, env);
    match value {
        Proc(_) => (),
        _ => fail ~"lambda doesn't turn into a Proc"
    }
}

#[test]
fn test_that_lambda_without_variables_evals() {
    let env=test_env();
    let expression = parse( ~"( (lambda () (+ 1 1))  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_with_a_variable_evals() {
    let env=test_env();
    let expression = parse( ~"( (lambda (x) (+ x 1)) 1  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

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 begin(expressions:~[Expression], environment:@Environment) -> Expression {
        for expressions.tail().init().each() |&expression| {
            eval( expression, environment );
        }
        eval( expressions.last(), environment )
    }

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

    fn reset_variable(expressions:~[Expression], environment:@Environment, function:~str) -> Expression {
        match expressions {
            [_, symbol, value] => {
                match copy symbol {
                    Symbol( key ) => {
                        environment.define(key, eval(value, environment));
                        symbol
                    }
                    _ => fail fmt!("Syntax Error: %s takes a symbol as its first argument", function)
                }
            }
            _ => fail fmt!("Syntax Error: %s must take two arguments", function)
        }
    }

    fn define(expressions:~[Expression], environment:@Environment) -> Expression {
        reset_variable(expressions, environment, ~"define")
    }

    fn set_bang(expressions:~[Expression], environment:@Environment) -> Expression {
        match copy expressions {
            [_, symbol, _] => {
                match copy symbol {
                    Symbol( key ) => {
                        match environment.lookup( copy key )  {
                            None => fail ~"Syntax Error: set! cannot create a variable",
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
            _ => ()
        }
        let symbol = reset_variable(expressions, environment, ~"set!");
        match copy symbol {
            Symbol( key ) => {
                match environment.lookup( copy key ) {
                    Some( value ) => value,
                    None => fail
                }
            }
            _ => fail
        }
    }

    fn proc(expressions:~[Expression], environment:@Environment) -> Expression {
        let exprs = expressions.map(|&expr| eval(expr, environment));
        match exprs.head() {
            Proc( procedure ) => procedure( exprs.tail(), environment ),
            _ => fail fmt!("\"%s\" is not a procedure", exprs.head().to_str())
        }
    }

    fn lambda(expressions:~[Expression], _:@Environment) -> Expression {
        match copy expressions {
            [_, List(param_names), expression] => Proc( |param_values, env| {
                    let local_env = @Environment::new( env );
                    for vec::zip(copy param_names, param_values).each |param| {
                        match param.first() {
                            Symbol(key) => local_env.define( key, param.second() ),
                            _ => fail ~"lambda params list must be list of symbols"
                        }
                    }
                    eval(copy expression, local_env)
                } ),
            _ => fail fmt!("Syntax Error: lambda requires 2 arguments, got \"%u\"", expressions.len()-1 )
        }
    }

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

fn main() {
    fn evaluate( expr:~str ) {
        let sent_expr = copy expr;
        let result = do task::try {
            let env = @Environment::new_global_environment();
            eval( parse(sent_expr), env )
        };
        if result.is_ok() {
            io::println( fmt!("%s -> %s", expr, result.unwrap().to_str()) );
        } else {
            io::println( fmt!("%s gave an error.", expr) );
        }
    }

    evaluate( ~"(* 4 99)" );
    evaluate( ~"(begin (define square (lambda (x) (* x x))) (square 4))" );
    evaluate( ~"(7 7)" );

    loop {
        io::print("rusty> ");
        let in = io::stdin().read_line();
        evaluate( in );
    }
}
<|endoftext|>