<commit_before>use luminance::{Dim2, Flat, RGBA32F, Texture};

/// Time.
pub type Time = f32;

/// A clip is an object that implements a visual sequence.
pub struct Clip<'a> {
  act: Box<Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> + 'a>
}

impl<'a> Clip<'a> {
  pub fn new<F>(act: F) -> Self where F: 'a + Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> {
    Clip {
      act: Box::new(act)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a> {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'a Clip<'a>
}

impl<'a> Cut<'a> {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'a Clip<'a>) -> Self {
    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a> {
  cuts: Vec<Cut<'a>>
}

impl<'a> Track<'a> {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b> From<&'b [Cut<'a>]> for Track<'a> {
  fn from(cuts: &'b [Cut<'a>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a> {
  tracks: Vec<Track<'a>>,
}

impl<'a> Timeline<'a> {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new()
    }
  }

  pub fn add_track(&mut self, track: Track<'a>) {
    self.tracks.push(track);
  }
}

impl<'a, 'b> From<&'b [Track<'a>]> for Timeline<'a> {
  fn from(tracks: &'b [Track<'a>]) -> Self {
    Timeline {
      tracks: tracks.to_vec()
    }
  }
}

<commit_msg>TrackCross.<commit_after>use luminance::{Dim2, Flat, RGBA32F, Texture};

/// Time.
pub type Time = f32;

/// A clip is an object that implements a visual sequence.
pub struct Clip<'a> {
  act: Box<Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> + 'a>
}

impl<'a> Clip<'a> {
  pub fn new<F>(act: F) -> Self where F: 'a + Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> {
    Clip {
      act: Box::new(act)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a> {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'a Clip<'a>
}

impl<'a> Cut<'a> {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'a Clip<'a>) -> Self {
    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a> {
  cuts: Vec<Cut<'a>>
}

impl<'a> Track<'a> {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b> From<&'b [Cut<'a>]> for Track<'a> {
  fn from(cuts: &'b [Cut<'a>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a> {
  tracks: Vec<Track<'a>>,
  crosses: Vec<TrackCross<'a>>
}

impl<'a> Timeline<'a> {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
      crosses: Vec::new()
    }
  }

  pub fn add_track(&mut self, track: Track<'a>) {
    self.tracks.push(track);
  }
}

impl<'a, 'b> From<&'b [Track<'a>]> for Timeline<'a> {
  fn from(tracks: &'b [Track<'a>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
      crosses: Vec::new()
    }
  }
}

/// An optimized structure used to put spanning regions over cuts of several tracks in a timeline in
/// order to know which cuts of which tracks are active at any time in O(1). A track cross
/// represents such a single region, and a list of ascending-ordered track cross can be used to
/// render the demo in an optimized way.
#[derive(Clone)]
struct TrackCross<'a> {
  /// Time at which the track cross begins.
  in_time: Time,
  /// Time at which the track cross ends.
  out_time: Time,
  /// List of cuts that are active at the given time.
  cuts: Vec<&'a Cut<'a>>
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use fixpoint::Fix;

use super::term::{Primitive, Term};
use super::zipper::{Loc, Ctx};

#[derive (Debug, PartialEq, Eq)]
pub enum ReferenceError { NotFound(String) }

#[derive (Debug, PartialEq, Eq)]
pub enum TypeError { NotAFunction(Primitive) }

#[derive (Debug, PartialEq, Eq)]
pub enum EvalError {
    ReferenceError(ReferenceError),
    TypeError(TypeError),
    StackOverflow
}

pub struct Scope(HashMap<String, Term>);

impl Scope {

    pub fn new() -> Scope {
        Scope(HashMap::new())
    }

    pub fn lookup(&mut self, id: String) -> Result<Term, ReferenceError> {
        self.0.remove(&id).ok_or(ReferenceError::NotFound(id))
    }

    pub fn bind(&mut self, id: String, term: Term) {
        self.0.insert(id, term);
    }

}

type EvalResult = Result<Fix<Loc>, EvalError>;

fn eval_shallow(scope: &mut Scope, loc: Loc) -> EvalResult {
    match loc {
        Loc(Term::Val(val), c) => Result::Ok(Fix::Fix(Loc(Term::Val(val), c))),
        Loc(Term::Var(id), c) => match scope.lookup(id) {
            Result::Ok(term) => Result::Ok(Fix::Pro(Loc(term, c))),
            Result::Err(err) => Result::Err(EvalError::ReferenceError(err))
        },
        Loc(Term::Abs(id, term_box), c) => Result::Ok(Fix::Fix(Loc(Term::Abs(id, term_box), c))),
        Loc(Term::App(fun_box, arg_box), c) => {
            let fun: Term = *fun_box;
            match fun {
                Term::Val(val) => {
                    Result::Err(EvalError::TypeError(TypeError::NotAFunction(val)))
                },
                Term::Abs(id, term_box) => {
                    scope.bind(id, *arg_box);
                    Result::Ok(Fix::Pro(Loc(*term_box, c)))
                },
                fun_term => {
                    Result::Ok(Fix::Pro(Loc(fun_term, Ctx::AppL(Box::new(c), *arg_box))))
                }
            }
        }
    }
}

pub fn eval(scope: &mut Scope, term: Term) -> Result<Term, EvalError> {
    // find the head normal form of the term,
    // which is equivalent to the fixpoint of
    // the eval_shallow function
    Loc::top(term).fix_result(|loc| {
        eval_shallow(scope, loc).map(|fix| match fix {
            Fix::Pro(loc) => Fix::Pro(loc),
            Fix::Fix(loc) => Loc::up(loc)
        })
    }).map(Loc::get)
}

#[test]
fn eval_val() {
    let mut scope = Scope::new();
    let x = eval(&mut scope, Term::val_int(42));
    assert_eq!(x, Result::Ok(Term::val_int(42)));
}

#[test]
fn eval_id() {
    let mut scope = Scope::new();
    let x = eval(&mut scope,
        Term::app(
            Term::abs(
                "x".to_string(),
                Term::var("x".to_string())
            ),
            Term::val_int(42)
        )
    );
    assert_eq!(x, Result::Ok(Term::val_int(42)));
}
<commit_msg>simplify fixpoint finding<commit_after>use std::collections::HashMap;

use fixpoint::Fix;

use super::term::{Primitive, Term};
use super::zipper::{Loc, Ctx};

#[derive (Debug, PartialEq, Eq)]
pub enum ReferenceError { NotFound(String) }

#[derive (Debug, PartialEq, Eq)]
pub enum TypeError { NotAFunction(Primitive) }

#[derive (Debug, PartialEq, Eq)]
pub enum EvalError {
    ReferenceError(ReferenceError),
    TypeError(TypeError),
    StackOverflow
}

pub struct Scope(HashMap<String, Term>);

impl Scope {

    pub fn new() -> Scope {
        Scope(HashMap::new())
    }

    pub fn lookup(&mut self, id: String) -> Result<Term, ReferenceError> {
        self.0.remove(&id).ok_or(ReferenceError::NotFound(id))
    }

    pub fn bind(&mut self, id: String, term: Term) {
        self.0.insert(id, term);
    }

}

type EvalResult = Result<Fix<Loc>, EvalError>;

fn eval_shallow(scope: &mut Scope, loc: Loc) -> EvalResult {
    match loc {
        Loc(Term::Val(val), c) => Result::Ok(Fix::Fix(Loc(Term::Val(val), c))),
        Loc(Term::Var(id), c) => match scope.lookup(id) {
            Result::Ok(term) => Result::Ok(Fix::Pro(Loc(term, c))),
            Result::Err(err) => Result::Err(EvalError::ReferenceError(err))
        },
        Loc(Term::Abs(id, term_box), c) => Result::Ok(Fix::Fix(Loc(Term::Abs(id, term_box), c))),
        Loc(Term::App(fun_box, arg_box), c) => {
            let fun: Term = *fun_box;
            match fun {
                Term::Val(val) => {
                    Result::Err(EvalError::TypeError(TypeError::NotAFunction(val)))
                },
                Term::Abs(id, term_box) => {
                    scope.bind(id, *arg_box);
                    Result::Ok(Fix::Pro(Loc(*term_box, c)))
                },
                fun_term => {
                    Result::Ok(Fix::Pro(Loc(fun_term, Ctx::AppL(Box::new(c), *arg_box))))
                }
            }
        }
    }
}

pub fn eval(scope: &mut Scope, term: Term) -> Result<Term, EvalError> {
    // find the head normal form of the term,
    // which is equivalent to the fixpoint of
    // the eval_shallow function
    Loc::top(term).fix_result(|loc| {
        eval_shallow(scope, loc)
    }).map(Loc::get)
}

#[test]
fn eval_val() {
    let mut scope = Scope::new();
    let x = eval(&mut scope, Term::val_int(42));
    assert_eq!(x, Result::Ok(Term::val_int(42)));
}

#[test]
fn eval_id() {
    let mut scope = Scope::new();
    let x = eval(&mut scope,
        Term::app(
            Term::abs(
                "x".to_string(),
                Term::var("x".to_string())
            ),
            Term::val_int(42)
        )
    );
    assert_eq!(x, Result::Ok(Term::val_int(42)));
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::iter::Map;
use parser::Node;

#[derive(Debug, Clone)]
pub struct EvalError(String);

pub struct Eval;

// TODO: Reduce memory copy...
impl Eval {
    pub fn new() -> Self {
        Eval {}
    }

    fn calc_integer<F>(&self,
                       env: &mut HashMap<String, Node>,
                       f: &F,
                       args: &[Node], node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> i64 {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok(aa)) => Some(Ok(f(aa, i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok(i)),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(i)) => Ok(Node::Integer(i)),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn cond<F>(&self,
               env: &mut HashMap<String, Node>,
               f: &F,
               args: &[Node],
               node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> bool {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok((result, prev))) => Some(Ok((result && f(prev, i), i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok((true, i))),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(result)) => Ok(if result.0 { Node::True } else { Node::False }),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn if_then_else(&self,
                    env: &mut HashMap<String, Node>,
                    args: &[Node],
                    node: &Node) -> Result<Node, EvalError> {

        if args.len() < 2 || args.len() > 3 {
            return Err(EvalError(format!("`if` takes 2 or 3 arguments, but got {:?}", args)));
        }

        Ok(match &try!(self.eval(env, args[0].clone())) {
            &Node::True => try!(self.eval(env, args[1].clone())),
            &Node::False => {
                if args.len() == 3 {
                    try!(self.eval(env, args[2].clone()))
                }
                else {
                    Node::List(Vec::new())
                }
            },
            _ => return Err(EvalError(format!("The 1st parameter of `if` should be boolean, but got {:?}", args)))
        })
    }

    fn car(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((hd, _)) => hd.clone(),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`car` takes only a quoted list, but got {:?}", args)))
    }

    fn cdr(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((_, tl)) => Node::QuotedList(tl.to_vec()),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`cdr` takes only a quoted list, but got {:?}", args)))
    }

    fn setq(&self,
            env: &mut HashMap<String, Node>,
            args: &[Node],
            node: &Node) -> Result<Node, EvalError> {

        if args.len() % 2 == 0 {
            let mut key = None;
            for arg in args {
                if let Some(k) = key {
                    let evalated_node = try!(self.eval(env, arg.clone()));
                    env.insert(k, evalated_node);
                    key = None;
                }
                else {
                    if let &Node::Keyword(ref k) = arg {
                        key = Some(k.clone())
                    }
                    else {
                        return Err(EvalError(format!("`setq` accepts only Node::Keyword as a key, but got {:?}", arg)));
                    }
                }
            }
            return Ok(node.clone())
        }

        Err(EvalError(format!("`setq` takes only key value pairs, but got {:?}", args)))
    }

    fn lambda(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        if args.len() == 2 {
            match (&args[0], &args[1]) {
                (&Node::List(ref xs), &Node::List(ref body)) => {
                    let mut fargs = Vec::new();
                    let mut errors = Vec::new();

                    for x in xs {
                        match x {
                            &Node::Keyword(ref kwd) => fargs.push(kwd.clone()),
                            _ => errors.push(
                                EvalError(format!("The 2nd parameter of `lambda` should be a list of keywords, but got {:?}", args))
                                ),
                        }
                    }

                    if ! errors.is_empty() {
                        return Err(errors[0].clone())
                    }

                    return Ok(Node::Func(fargs, body.clone()))
                },
                _ => ()
            }
        }

        Err(EvalError(format!("`lambda` takes only (name:keyword args:list body:list), but got {:?}", args)))
    }

    fn call(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        match node {
            &Node::Func(ref xs, ref body) => {
                let cloned_env = env.clone();

                let saved_env_kvs = xs.iter().
                    map(|k| (k, cloned_env.get(k))).
                    collect::<Vec<(&String, Option<&Node>)>>();

                for (i, x) in xs.iter().enumerate() {
                    let evaled_arg = try!(self.eval(env, args[i].clone()));
                    env.insert(x.clone(), evaled_arg);
                }

                // Dynamic scope, not lexical scope
                let result = try!(self.eval(env, Node::List(body.clone())));
                for x in xs {
                    env.remove(x);
                }
                for (k, v) in saved_env_kvs {
                    if let Some(saved_node) = v {
                        env.insert(k.clone(), saved_node.clone());
                    }
                }
                return Ok(result)
            },
            _ => ()
        }

        Err(EvalError(format!("Failed to call a function due to unexpected arguments: node is {:?} and arguments are {:?}", node, args)))
    }

    pub fn eval(&self, env: &mut HashMap<String, Node>, node: Node) -> Result<Node, EvalError> {
        match node {
            Node::Integer(_) => Ok(node),
            Node::Keyword(kwd) => {
                let cloned_env = env.clone();
                Ok(match cloned_env.get(&kwd) {
                    Some(x) => try!(self.eval(env, x.clone())),
                    None => Node::Keyword(kwd),
                })
            },
            Node::List(ref xs) => self.eval_func(env, &node, xs),
            Node::QuotedList(x) => Ok(Node::List(x)),
            _ => Ok(node),
        }
    }

    fn eval_func(&self, env: &mut HashMap<String, Node>, node: &Node, xs: &Vec<Node>) -> Result<Node, EvalError> {
        let (hd, tl) = xs.split_first().unwrap();
        if let &Node::Keyword(ref kwd) = hd {
            Ok(match kwd.as_str() {
                "+" => try!(self.calc_integer(env, &|a, i| a + i, tl, node)),
                "-" => try!(self.calc_integer(env, &|a, i| a - i, tl, node)),
                "*" => try!(self.calc_integer(env, &|a, i| a * i, tl, node)),
                "/" => try!(self.calc_integer(env, &|a, i| a / i, tl, node)),
                "=" => try!(self.cond(env, &|a, i| a == i, tl, node)),
                ">" => try!(self.cond(env, &|a, i| a > i, tl, node)),
                ">=" => try!(self.cond(env, &|a, i| a >= i, tl, node)),
                "<" => try!(self.cond(env, &|a, i| a < i, tl, node)),
                "<=" => try!(self.cond(env, &|a, i| a <= i, tl, node)),
                "/=" => try!(self.cond(env, &|a, i| a != i, tl, node)),
                "if" => try!(self.if_then_else(env, tl, node)),
                "car" => try!(self.car(env, tl, node)),
                "cdr" => try!(self.cdr(env, tl, node)),
                "setq" => try!(self.setq(env, tl, node)),
                "lambda" => try!(self.lambda(env, tl, node)),
                _ =>  {
                    let cloned_env = env.clone();
                    match cloned_env.get(kwd) {
                        Some(f) => try!(self.call(env, &tl, &f)),
                        None => return Err(EvalError(format!("Unknown keyword: {:?}", kwd)))
                    }
                }
            })
        }
        else {
            Err(EvalError(format!("Unexpected node: {:?}", node)))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use super::Eval;
    use parser::Node;

    #[test]
    fn eval() {
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Integer(40),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("*")),
                        Node::Integer(6),
                        Node::List(
                            vec![
                                Node::Keyword(String::from("-")),
                                Node::Integer(42),
                                Node::Integer(35),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("car")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(42),
                                Node::Integer(-123),
                                Node::Integer(0),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::QuotedList(
                vec![
                    Node::Integer(4),
                    Node::Integer(2),
                ]
            ),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("cdr")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(0),
                                Node::Integer(4),
                                Node::Integer(2),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        let env0 = &mut HashMap::new();
        env0.insert(String::from("x"), Node::Integer(40));
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env0,
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Keyword(String::from("x"))
                    ]
                )
            ).unwrap()
        );

        let env1 = &mut HashMap::new();
        Eval::new().eval(
            env1,
            Node::List(
                vec![
                    Node::Keyword(String::from("setq")),
                    Node::Keyword(String::from("add")),
                    Node::List(
                        vec![
                            Node::Keyword(String::from("lambda")),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("+")),
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                        ]
                    )
                ]
            )
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env1,
                Node::List(
                    vec![
                        Node::Keyword(String::from("add")),
                        Node::Integer(40),
                        Node::Integer(2),
                    ]
                )
            ).unwrap()
        );
    }
}

<commit_msg>Reduce clone<commit_after>use std::collections::HashMap;
use std::iter::Map;
use parser::Node;

#[derive(Debug, Clone)]
pub struct EvalError(String);

pub struct Eval;

// TODO: Reduce memory copy...
impl Eval {
    pub fn new() -> Self {
        Eval {}
    }

    fn calc_integer<F>(&self,
                       env: &mut HashMap<String, Node>,
                       f: &F,
                       args: &[Node], node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> i64 {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok(aa)) => Some(Ok(f(aa, i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok(i)),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(i)) => Ok(Node::Integer(i)),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn cond<F>(&self,
               env: &mut HashMap<String, Node>,
               f: &F,
               args: &[Node],
               node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> bool {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok((result, prev))) => Some(Ok((result && f(prev, i), i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok((true, i))),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(result)) => Ok(if result.0 { Node::True } else { Node::False }),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn if_then_else(&self,
                    env: &mut HashMap<String, Node>,
                    args: &[Node],
                    node: &Node) -> Result<Node, EvalError> {

        if args.len() < 2 || args.len() > 3 {
            return Err(EvalError(format!("`if` takes 2 or 3 arguments, but got {:?}", args)));
        }

        Ok(match &try!(self.eval(env, args[0].clone())) {
            &Node::True => try!(self.eval(env, args[1].clone())),
            &Node::False => {
                if args.len() == 3 {
                    try!(self.eval(env, args[2].clone()))
                }
                else {
                    Node::List(Vec::new())
                }
            },
            _ => return Err(EvalError(format!("The 1st parameter of `if` should be boolean, but got {:?}", args)))
        })
    }

    fn car(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((hd, _)) => hd.clone(),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`car` takes only a quoted list, but got {:?}", args)))
    }

    fn cdr(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((_, tl)) => Node::QuotedList(tl.to_vec()),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`cdr` takes only a quoted list, but got {:?}", args)))
    }

    fn setq(&self,
            env: &mut HashMap<String, Node>,
            args: &[Node],
            node: &Node) -> Result<Node, EvalError> {

        if args.len() % 2 == 0 {
            let mut key = None;
            for arg in args {
                if let Some(k) = key {
                    let evalated_node = try!(self.eval(env, arg.clone()));
                    env.insert(k, evalated_node);
                    key = None;
                }
                else {
                    if let &Node::Keyword(ref k) = arg {
                        key = Some(k.clone())
                    }
                    else {
                        return Err(EvalError(format!("`setq` accepts only Node::Keyword as a key, but got {:?}", arg)));
                    }
                }
            }
            return Ok(node.clone())
        }

        Err(EvalError(format!("`setq` takes only key value pairs, but got {:?}", args)))
    }

    fn lambda(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        if args.len() == 2 {
            match (&args[0], &args[1]) {
                (&Node::List(ref xs), &Node::List(ref body)) => {
                    let mut fargs = Vec::new();
                    let mut errors = Vec::new();

                    for x in xs {
                        match x {
                            &Node::Keyword(ref kwd) => fargs.push(kwd.clone()),
                            _ => errors.push(
                                EvalError(format!("The 2nd parameter of `lambda` should be a list of keywords, but got {:?}", args))
                                ),
                        }
                    }

                    if ! errors.is_empty() {
                        return Err(errors[0].clone())
                    }

                    return Ok(Node::Func(fargs, body.clone()))
                },
                _ => ()
            }
        }

        Err(EvalError(format!("`lambda` takes only (name:keyword args:list body:list), but got {:?}", args)))
    }

    fn call(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        match node {
            &Node::Func(ref xs, ref body) => {
                let cloned_env = env.clone();

                let saved_env_kvs = xs.iter().
                    map(|k| (k, cloned_env.get(k))).
                    collect::<Vec<(&String, Option<&Node>)>>();

                for (i, x) in xs.iter().enumerate() {
                    let evaled_arg = try!(self.eval(env, args[i].clone()));
                    env.insert(x.clone(), evaled_arg);
                }

                // Dynamic scope, not lexical scope
                let result = try!(self.eval(env, Node::List(body.clone())));
                for x in xs {
                    env.remove(x);
                }
                for (k, v) in saved_env_kvs {
                    if let Some(saved_node) = v {
                        env.insert(k.clone(), saved_node.clone());
                    }
                }
                return Ok(result)
            },
            _ => ()
        }

        Err(EvalError(format!("Failed to call a function due to unexpected arguments: node is {:?} and arguments are {:?}", node, args)))
    }

    pub fn eval(&self, env: &mut HashMap<String, Node>, node: Node) -> Result<Node, EvalError> {
        match node {
            Node::Integer(_) => Ok(node),
            Node::Keyword(kwd) => {
                let nd = match env.get(&kwd) {
                    Some(x) => x.clone(),
                    None => return Ok(Node::Keyword(kwd)),
                };
                self.eval(env, nd)
            },
            Node::List(ref xs) => self.eval_func(env, &node, xs),
            Node::QuotedList(x) => Ok(Node::List(x)),
            _ => Ok(node),
        }
    }

    fn eval_func(&self, env: &mut HashMap<String, Node>, node: &Node, xs: &Vec<Node>) -> Result<Node, EvalError> {
        let (hd, tl) = xs.split_first().unwrap();
        if let &Node::Keyword(ref kwd) = hd {
            match kwd.as_str() {
                "+" => self.calc_integer(env, &|a, i| a + i, tl, node),
                "-" => self.calc_integer(env, &|a, i| a - i, tl, node),
                "*" => self.calc_integer(env, &|a, i| a * i, tl, node),
                "/" => self.calc_integer(env, &|a, i| a / i, tl, node),
                "=" => self.cond(env, &|a, i| a == i, tl, node),
                ">" => self.cond(env, &|a, i| a > i, tl, node),
                ">=" => self.cond(env, &|a, i| a >= i, tl, node),
                "<" => self.cond(env, &|a, i| a < i, tl, node),
                "<=" => self.cond(env, &|a, i| a <= i, tl, node),
                "/=" => self.cond(env, &|a, i| a != i, tl, node),
                "if" => self.if_then_else(env, tl, node),
                "car" => self.car(env, tl, node),
                "cdr" => self.cdr(env, tl, node),
                "setq" => self.setq(env, tl, node),
                "lambda" => self.lambda(env, tl, node),
                _ =>  {
                    let f = match env.get(kwd) {
                        Some(f) => f.clone(),
                        None => return Err(EvalError(format!("Unknown keyword: {:?}", kwd)))
                    };
                    self.call(env, &tl, &f)
                }
            }
        }
        else {
            Err(EvalError(format!("Unexpected node: {:?}", node)))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use super::Eval;
    use parser::Node;

    #[test]
    fn eval() {
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Integer(40),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("*")),
                        Node::Integer(6),
                        Node::List(
                            vec![
                                Node::Keyword(String::from("-")),
                                Node::Integer(42),
                                Node::Integer(35),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("car")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(42),
                                Node::Integer(-123),
                                Node::Integer(0),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::QuotedList(
                vec![
                    Node::Integer(4),
                    Node::Integer(2),
                ]
            ),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("cdr")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(0),
                                Node::Integer(4),
                                Node::Integer(2),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        let env0 = &mut HashMap::new();
        env0.insert(String::from("x"), Node::Integer(40));
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env0,
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Keyword(String::from("x"))
                    ]
                )
            ).unwrap()
        );

        let env1 = &mut HashMap::new();
        Eval::new().eval(
            env1,
            Node::List(
                vec![
                    Node::Keyword(String::from("setq")),
                    Node::Keyword(String::from("add")),
                    Node::List(
                        vec![
                            Node::Keyword(String::from("lambda")),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("+")),
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                        ]
                    )
                ]
            )
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env1,
                Node::List(
                    vec![
                        Node::Keyword(String::from("add")),
                        Node::Integer(40),
                        Node::Integer(2),
                    ]
                )
            ).unwrap()
        );
    }
}

<|endoftext|>


<commit_before>use parser::{parse};
use ast::Expr::*;
use ast::UnOp::*;
use ast::BinOp::*;
use ast::Dec::*;
use ast::*;
use state::*;

fn subst(e: Expr, x: Expr, v: Expr) -> Expr {
  let sub = |e1: Expr| subst(e1.clone(), x.clone(), v.clone());

  match (e.clone(), x.clone()) {
    (Var(ref s1), Var(ref s2)) if s1 == s2 => v.clone(),
    (FnCall(v1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();

      FnCall(Box::new(sub(*v1)), xs2)
    },
    (Var(_), _) => e,
    (Int(_), _) => e,
    (Bool(_), _) => e,
    (Undefined, _) => e,
    (Scope(e1, a), _) => Scope(Box::new(sub(*e1)), a),
    (Bop(op, e1, e2), _) => {
      Bop(
        op,
        Box::new(sub(*e1)),
        Box::new(sub(*e2))
      )
    },
    (Uop(op, e1), _) => Uop(op, Box::new(sub(*e1))),
    (Ternary(e1, e2, e3), _) => {
      Ternary(
        Box::new(sub(*e1)),
        Box::new(sub(*e2)),
        Box::new(sub(*e3))
      )
    },
    (While(e1, e1o, e2, e2o, e3), _) => {
      While(
        Box::new(sub(*e1)),
        Box::new(sub(*e1o)),
        Box::new(sub(*e2)),
        Box::new(sub(*e2o)),
        Box::new(sub(*e3))
      )
    },
    (Decl(d, y, e1, e2), _) => {
      let e2s = if *y == x {
        *e2
      } else {
        sub(*e2)
      };

      Decl(
        d,
        Box::new(*y),
        Box::new(sub(*e1)),
        Box::new(e2s)
      )
    },
    (Func(name, e1, xs), _) => {
      match xs.iter().find(|y| **y == x) {
        Some(_) => e,
        None if name == Some(Box::new(x.clone())) => e,
        None => Func(name, Box::new(sub(*e1)), xs)
      }
    }
  }
}

pub fn step(mut state: State) -> State {
  let st_step = |s: &mut State, e1: &Expr| {
    let s2 = step(s.clone().with(e1.clone()));
    s.merge_mem(s2.clone());
    s2.expr.clone()
  };

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

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Int(result)
    },
    Bop(Lt, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Bool(e1.to_int() < e2.to_int())
    },
    Bop(Gt, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Bool(e1.to_int() > e2.to_int())
    },
    Bop(Leq, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Bool(e1.to_int() <= e2.to_int())
    },
    Bop(Geq, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Bool(e1.to_int() >= e2.to_int())
    },
    Bop(Plus, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Int(e1.to_int() + e2.to_int())
    },
    Bop(Minus, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Int(e1.to_int() - e2.to_int())
    },
    Bop(Times, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Int(e1.to_int() * e2.to_int())
    },
    Bop(Div, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
      Int(e1.to_int() / e2.to_int())
    },
    Bop(Seq, ref v1, ref e2) if v1.is_value() => {
      *e2.clone()
    },
    Bop(Assign, ref v1, ref v2) if v1.is_var() && v2.is_value() => {
      let x = v1.to_var();
      state.assign(x, *v2.clone());
      debug!("done assigning {:?}", state.mem);
      *v2.clone()
    },
    Ternary(ref v1, ref e2, ref e3) if v1.is_value() => {
      match v1.to_bool() {
        true => *e2.clone(),
        false => *e3.clone(),
      }
    },
    Decl(DConst, ref x, ref v1, ref e2) if v1.is_value() => {
      subst(*e2.clone(), *x.clone(), *v1.clone())
    },
    Decl(DVar, ref x, ref v1, ref e2) if x.is_var() && v1.is_value() => {
      debug!("allocing {:?}", v1);
      state.alloc(x.to_var(), *v1.clone());
      Scope(Box::new(*e2.clone()), x.to_var())
    },
    Scope(ref v1, ref x) if v1.is_value() => {
      debug!("freeing {:?}", x);
      state.free(x.clone());
      *v1.clone()
    },
    // lambda lift so we can use iter() in guard
    // https://github.com/rust-lang/rfcs/issues/1006
    FnCall(ref v1, ref es) if v1.is_func() && (|| es.iter().all(|v| v.is_value()))() => {
      match **v1 {
        Func(ref name, ref e1, ref xs) => {
          // sub the params
          let exp = xs.iter().zip(es.iter())
            .fold(*e1.clone(), |exp, (xn, en)| subst(exp, xn.clone(), en.clone()));

          // sub the fn body for named functions
          match *name {
            None => exp,
            Some(ref s) => subst(exp, *s.clone(), *v1.clone())
          }
        },
        _ => {
          debug!("expected a Func, got {:?}", v1);
          panic!()
        },
      }
    },
    /**
     * Search Cases
     */
    Bop(ref op, ref v1, ref e2) if v1.is_value() => {
      Bop(
        op.clone(),
        Box::new(*v1.clone()),
        Box::new(st_step(&mut state, e2))
      )
    },
    Bop(Assign, ref v1, ref e2) if v1.is_var() => {
      Bop(
        Assign,
        Box::new(*v1.clone()),
        Box::new(st_step(&mut state, e2))
      )
    },
    Bop(op, e1, e2) => {
      Bop(op, Box::new(st_step(&mut state, &*e1)), e2)
    },
    Scope(e1, addr) => {
      Scope(Box::new(st_step(&mut state, &*e1)), addr)
    },
    Uop(op, e1) => {
      Uop(op, Box::new(st_step(&mut state, &*e1)))
    },
    Ternary(e1, e2, e3) => {
      Ternary(Box::new(st_step(&mut state, &*e1)), e2, e3)
    },
    While(ref v1, ref e1o, _, ref e2o, ref e3) if v1.is_value() => {
      match v1.to_bool() {
        true => While(Box::new(*e1o.clone()), e1o.clone(), e2o.clone(), e2o.clone(), e3.clone()),
        false => *e3.clone(),
      }
    },
    While(ref e1, ref e1o, ref v2, ref e2o, ref e3) if v2.is_value() => {
      While(Box::new(st_step(&mut state, &*e1)), e1o.clone(), v2.clone(), e2o.clone(), e3.clone())
    },
    While(e1, e1o, e2, e2o, e3) => {
      While(e1, e1o, Box::new(st_step(&mut state, &*e2)), e2o, e3)
    },
    Decl(dt, addr, e1, e2) => {
      Decl(dt, Box::new(*addr.clone()), Box::new(st_step(&mut state, &*e1)), e2)
    },
    FnCall(ref v1, ref args) if v1.is_value() => {
      let mut found_nonvalue = false;

      let args2 = args.iter().map(|e| {
        if !found_nonvalue && !e.is_value() {
          found_nonvalue = true;
          st_step(&mut state, e)
        } else {
          e.clone()
        }
      }).collect();

      FnCall(v1.clone(), args2)
    },
    FnCall(e1, args) => {
      FnCall(Box::new(st_step(&mut state, &*e1)), args)
    },
  };

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

pub fn boxx(input: &str) -> Expr {
  let mut state = State::from(parse(input));

  let mut num_iterations = 0;

  loop {
    if num_iterations > 500 {
      panic!("too many step iterations");
    }

    debug!("-----------------");
    debug!("--- iterating on e {:?} ", state.expr);
    debug!("--- iterating on m {:?} ", state.mem);
    num_iterations += 1;
    if state.expr.is_value() {
      debug!("--- iterations: {}", num_iterations);
      return state.expr
    } else {
      state = step(state);
    }
  }
}
<commit_msg>pull expr into repl instance<commit_after>use parser::{parse};
use ast::Expr::*;
use ast::UnOp::*;
use ast::BinOp::*;
use ast::Dec::*;
use ast::*;
use state::*;

fn subst(e: Expr, x: Expr, v: Expr) -> Expr {
  let sub = |e1: Expr| subst(e1.clone(), x.clone(), v.clone());

  match (e.clone(), x.clone()) {
    (Var(ref s1), Var(ref s2)) if s1 == s2 => v.clone(),
    (FnCall(v1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();

      FnCall(Box::new(sub(*v1)), xs2)
    },
    (Var(_), _) => e,
    (Int(_), _) => e,
    (Bool(_), _) => e,
    (Undefined, _) => e,
    (Scope(e1, a), _) => Scope(Box::new(sub(*e1)), a),
    (Bop(op, e1, e2), _) => {
      Bop(
        op,
        Box::new(sub(*e1)),
        Box::new(sub(*e2))
      )
    },
    (Uop(op, e1), _) => Uop(op, Box::new(sub(*e1))),
    (Ternary(e1, e2, e3), _) => {
      Ternary(
        Box::new(sub(*e1)),
        Box::new(sub(*e2)),
        Box::new(sub(*e3))
      )
    },
    (While(e1, e1o, e2, e2o, e3), _) => {
      While(
        Box::new(sub(*e1)),
        Box::new(sub(*e1o)),
        Box::new(sub(*e2)),
        Box::new(sub(*e2o)),
        Box::new(sub(*e3))
      )
    },
    (Decl(d, y, e1, e2), _) => {
      let e2s = if *y == x {
        *e2
      } else {
        sub(*e2)
      };

      Decl(
        d,
        Box::new(*y),
        Box::new(sub(*e1)),
        Box::new(e2s)
      )
    },
    (Func(name, e1, xs), _) => {
      match xs.iter().find(|y| **y == x) {
        Some(_) => e,
        None if name == Some(Box::new(x.clone())) => e,
        None => Func(name, Box::new(sub(*e1)), xs)
      }
    }
  }
}

pub struct Repl {
  pub state: State,
}

impl Repl {
  pub fn new(e: Expr) -> Repl {
    Repl {
      state: State::from(e),
    }
  }

  fn st_step(&mut self, e1: &Expr) -> Expr {
    let s2 = self.step(e1.clone());
    self.state.merge_mem(s2.clone());
    s2.expr.clone()
  }

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

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

        // rust % gives the remainder, not modulus
        let result = ((n1 % n2) + n2) % n2;

        Int(result)
      },
      Bop(Lt, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Bool(e1.to_int() < e2.to_int())
      },
      Bop(Gt, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Bool(e1.to_int() > e2.to_int())
      },
      Bop(Leq, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Bool(e1.to_int() <= e2.to_int())
      },
      Bop(Geq, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Bool(e1.to_int() >= e2.to_int())
      },
      Bop(Plus, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Int(e1.to_int() + e2.to_int())
      },
      Bop(Minus, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Int(e1.to_int() - e2.to_int())
      },
      Bop(Times, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Int(e1.to_int() * e2.to_int())
      },
      Bop(Div, ref e1, ref e2) if e1.is_int() && e2.is_int() => {
        Int(e1.to_int() / e2.to_int())
      },
      Bop(Seq, ref v1, ref e2) if v1.is_value() => {
        *e2.clone()
      },
      Bop(Assign, ref v1, ref v2) if v1.is_var() && v2.is_value() => {
        let x = v1.to_var();
        self.state.assign(x, *v2.clone());
        debug!("done assigning {:?}", self.state.mem);
        *v2.clone()
      },
      Ternary(ref v1, ref e2, ref e3) if v1.is_value() => {
        match v1.to_bool() {
          true => *e2.clone(),
          false => *e3.clone(),
        }
      },
      Decl(DConst, ref x, ref v1, ref e2) if v1.is_value() => {
        subst(*e2.clone(), *x.clone(), *v1.clone())
      },
      Decl(DVar, ref x, ref v1, ref e2) if x.is_var() && v1.is_value() => {
        debug!("allocing {:?}", v1);
        self.state.alloc(x.to_var(), *v1.clone());
        Scope(Box::new(*e2.clone()), x.to_var())
      },
      Scope(ref v1, ref x) if v1.is_value() => {
        debug!("freeing {:?}", x);
        self.state.free(x.clone());
        *v1.clone()
      },
      // lambda lift so we can use iter() in guard
      // https://github.com/rust-lang/rfcs/issues/1006
      FnCall(ref v1, ref es) if v1.is_func() && (|| es.iter().all(|v| v.is_value()))() => {
        match **v1 {
          Func(ref name, ref e1, ref xs) => {
            // sub the params
            let exp = xs.iter().zip(es.iter())
              .fold(*e1.clone(), |exp, (xn, en)| subst(exp, xn.clone(), en.clone()));

            // sub the fn body for named functions
            match *name {
              None => exp,
              Some(ref s) => subst(exp, *s.clone(), *v1.clone())
            }
          },
          _ => {
            debug!("expected a Func, got {:?}", v1);
            panic!()
          },
        }
      },
      /**
       * Search Cases
       */
      Bop(ref op, ref v1, ref e2) if v1.is_value() => {
        Bop(
          op.clone(),
          Box::new(*v1.clone()),
          Box::new(self.st_step(e2))
          )
      },
      Bop(Assign, ref v1, ref e2) if v1.is_var() => {
        Bop(
          Assign,
          Box::new(*v1.clone()),
          Box::new(self.st_step(e2))
          )
      },
      Bop(op, e1, e2) => {
        Bop(op, Box::new(self.st_step(&*e1)), e2)
      },
      Scope(e1, addr) => {
        Scope(Box::new(self.st_step(&*e1)), addr)
      },
      Uop(op, e1) => {
        Uop(op, Box::new(self.st_step(&*e1)))
      },
      Ternary(e1, e2, e3) => {
        Ternary(Box::new(self.st_step(&*e1)), e2, e3)
      },
      While(ref v1, ref e1o, _, ref e2o, ref e3) if v1.is_value() => {
        match v1.to_bool() {
          true => While(Box::new(*e1o.clone()), e1o.clone(), e2o.clone(), e2o.clone(), e3.clone()),
          false => *e3.clone(),
        }
      },
      While(ref e1, ref e1o, ref v2, ref e2o, ref e3) if v2.is_value() => {
        While(Box::new(self.st_step(&*e1)), e1o.clone(), v2.clone(), e2o.clone(), e3.clone())
      },
      While(e1, e1o, e2, e2o, e3) => {
        While(e1, e1o, Box::new(self.st_step(&*e2)), e2o, e3)
      },
      Decl(dt, addr, e1, e2) => {
        Decl(dt, Box::new(*addr.clone()), Box::new(self.st_step(&*e1)), e2)
      },
      FnCall(ref v1, ref args) if v1.is_value() => {
        let mut found_nonvalue = false;

        let args2 = args.iter().map(|e| {
          if !found_nonvalue && !e.is_value() {
            found_nonvalue = true;
            self.st_step(e)
          } else {
            e.clone()
          }
        }).collect();

        FnCall(v1.clone(), args2)
      },
      FnCall(e1, args) => {
        FnCall(Box::new(self.st_step(&*e1)), args)
      },
    };

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

  pub fn eval(&mut self) -> Expr {
    let mut num_iterations = 0;

    loop {
      if num_iterations > 500 {
        panic!("too many step iterations");
      }

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

pub fn boxx(input: &str) -> Expr {
  let mut repl = Repl::new(parse(input));
  repl.eval()
}
<|endoftext|>


<commit_before>use ffi::types::{hid_t, hsize_t, hbool_t};
use ffi::h5i::H5I_INVALID_HID;
use ffi::h5p::{H5P_FILE_CREATE, H5P_FILE_ACCESS, H5Pcreate, H5Pset_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fclose, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist, H5Fget_create_plist};
use ffi::drivers::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use object::{Handle, Object};
use error::Result;
use plist::PropertyList;
use ffi::util::string_to_cstr;
use std::path::{Path, PathBuf};

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl File {
    /// Create a new file object.
    ///
    /// | `mode`    | File access mode
    /// |-----------|-----------------
    /// | `r`       | Read-only, file must exist
    /// | `r+`      | Read/write, file must exist
    /// | `w`       | Create file, truncate if exists
    /// | `w-`, `x` | Create file, fail if exists
    /// | `a`       | Read/write if exists, create otherwise
    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new(filename).mode(mode).open()
    }

    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    /// Returns true if the file was opened in a read-only mode.
    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode != H5F_ACC_RDWR
        }
    }

    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    fn fcpl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_create_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }
}

impl Drop for File {
    fn drop(&mut self) {
        if self.refcount() == 1 {
            h5lock!(H5Fclose(self.id()));
        }
    }
}

pub struct FileBuilder {
    filename: PathBuf,
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new<P: AsRef<Path>>(filename: P) -> FileBuilder {
        FileBuilder {
            filename: filename.as_ref().to_path_buf(),
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file(&self, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            match self.filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", self.filename)
            }
        })
    }

    fn create_file(&self, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            match self.filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", self.filename)
            }
        })
    }

    pub fn open(&self) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(false),
            "r+"       => self.open_file(true),
            "w"        => self.create_file(false),
            "w-" | "x" => self.create_file(true),
            "a"        => match self.open_file(true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::path::PathBuf;
    use tempdir::TempDir;

    fn with_tmpdir<F: Fn(PathBuf)>(f: F) {
        let dir = TempDir::new_in(".", "tmp").unwrap();
        let path = dir.path().to_path_buf();
        f(path);
    }

    #[test]
    pub fn test_invalid_mode() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        with_tmpdir(|dir| {
            let path = dir.join("foo.h5");
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_invalid_filename() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });
    }
}
<commit_msg>Move `filename` argument from FileBuilder::new() to FileBuilder::open().<commit_after>use ffi::types::{hid_t, hsize_t, hbool_t};
use ffi::h5i::H5I_INVALID_HID;
use ffi::h5p::{H5P_FILE_CREATE, H5P_FILE_ACCESS, H5Pcreate, H5Pset_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fclose, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist, H5Fget_create_plist};
use ffi::drivers::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use object::{Handle, Object};
use error::Result;
use plist::PropertyList;
use ffi::util::string_to_cstr;
use std::path::{Path, PathBuf};

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl File {
    /// Create a new file object.
    ///
    /// | `mode`    | File access mode
    /// |-----------|-----------------
    /// | `r`       | Read-only, file must exist
    /// | `r+`      | Read/write, file must exist
    /// | `w`       | Create file, truncate if exists
    /// | `w-`, `x` | Create file, fail if exists
    /// | `a`       | Read/write if exists, create otherwise
    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new().mode(mode).open(filename)
    }

    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    /// Returns true if the file was opened in a read-only mode.
    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode != H5F_ACC_RDWR
        }
    }

    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    fn fcpl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_create_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }
}

impl Drop for File {
    fn drop(&mut self) {
        if self.refcount() == 1 {
            h5lock!(H5Fclose(self.id()));
        }
    }
}

pub struct FileBuilder {
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new() -> FileBuilder {
        FileBuilder {
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file<P: AsRef<Path>>(&self, filename: P, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    fn create_file<P: AsRef<Path>>(&self, filename: P, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    pub fn open<P: AsRef<Path>>(&self, filename: P) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(&filename, false),
            "r+"       => self.open_file(&filename, true),
            "w"        => self.create_file(&filename, false),
            "w-" | "x" => self.create_file(&filename, true),
            "a"        => match self.open_file(&filename, true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(&filename, true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::path::PathBuf;
    use tempdir::TempDir;

    fn with_tmpdir<F: Fn(PathBuf)>(f: F) {
        let dir = TempDir::new_in(".", "tmp").unwrap();
        let path = dir.path().to_path_buf();
        f(path);
    }

    #[test]
    pub fn test_invalid_mode() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        with_tmpdir(|dir| {
            let path = dir.join("foo.h5");
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_invalid_filename() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });
    }
}
<|endoftext|>


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

use capnp::Error;
use capnp::primitive_list;

use capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;

use calculator_capnp::calculator;
use gj::{EventLoop, Promise, TaskReaper, TaskSet};
use gj::io::tcp;

struct ValueImpl {
    value: f64
}

impl ValueImpl {
    fn new(value: f64) -> ValueImpl {
        ValueImpl { value: value }
    }
}

impl calculator::value::Server for ValueImpl {
    fn read(&mut self,
            _params: calculator::value::ReadParams,
            mut results: calculator::value::ReadResults)
            -> Promise<calculator::value::ReadResults, Error>
    {
        results.get().set_value(self.value);
        Promise::ok(results)
    }
}

fn evaluate_impl(expression: calculator::expression::Reader,
                 params: Option<primitive_list::Reader<f64>>)
                 -> Promise<f64, Error>
{
    match pry!(expression.which()) {
        calculator::expression::Literal(v) => {
            Promise::ok(v)
        },
        calculator::expression::PreviousResult(p) => {
            pry!(p).read_request().send().promise.map(|v| {
                Ok(try!(v.get()).get_value())
            })
        }
        calculator::expression::Parameter(p) => {
            match params {
                Some(params) if p < params.len() => {
                    Promise::ok(params.get(p))
                }
                _ => {
                    Promise::err(Error::failed(format!("bad parameter: {}", p)))
                }
            }
        }
        calculator::expression::Call(call) => {
            let func = pry!(call.get_function());
            let mut param_promises = Vec::new();
            for param in pry!(call.get_params()).iter() {
                param_promises.push(evaluate_impl(param, params));
            }
            Promise::all(param_promises.into_iter()).then(move |param_values| {
                let mut request = func.call_request();
                {
                    let mut params = request.get().init_params(param_values.len() as u32);
                    for ii in 0..param_values.len() {
                        params.set(ii as u32, param_values[ii]);
                    }
                }
                request.send().promise.map(|result| {
                    Ok(try!(result.get()).get_value())
                })
            })
        }
    }
}

struct FunctionImpl {
    param_count: u32,
    body: ::capnp::message::Builder<::capnp::message::HeapAllocator>,
}

impl FunctionImpl {
    fn new(param_count: u32, body: calculator::expression::Reader) -> FunctionImpl {
        let mut result = FunctionImpl {
            param_count: param_count,
            body: ::capnp::message::Builder::new_default()
        };
        result.body.set_root(body).unwrap();
        result
    }
}

impl calculator::function::Server for FunctionImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != self.param_count {
            Promise::err(Error::failed(
                format!("Expect {} parameters but got {}.", self.param_count, params.len())))
        } else {
            evaluate_impl(
                pry!(self.body.get_root::<calculator::expression::Builder>()).as_reader(),
                Some(params)).map(move |v| {
                    results.get().set_value(v);
                    Ok(results)
                })
        }
    }
}

#[derive(Clone, Copy)]
pub struct OperatorImpl {
    op: calculator::Operator,
}

impl calculator::function::Server for OperatorImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
            -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(Error::failed("Wrong number of paramters.".to_string()))
        } else {
            let v = match self.op {
                calculator::Operator::Add =>       params.get(0) + params.get(1),
                calculator::Operator::Subtract =>  params.get(0) - params.get(1),
                calculator::Operator::Multiply =>  params.get(0) * params.get(1),
                calculator::Operator::Divide =>    params.get(0) / params.get(1),
            };
            results.get().set_value(v);
            Promise::ok(results)
        }
    }
}

struct CalculatorImpl;

impl calculator::Server for CalculatorImpl {
    fn evaluate(&mut self,
                params: calculator::EvaluateParams,
                mut results: calculator::EvaluateResults)
                -> Promise<calculator::EvaluateResults, Error>
    {
        evaluate_impl(pry!(params.get().get_expression()), None).map(move |v| {
            results.get().set_value(
                calculator::value::ToClient::new(ValueImpl::new(v)).from_server::<LocalClient>());
            Ok(results)
        })
    }
    fn def_function(&mut self,
                    params: calculator::DefFunctionParams,
                    mut results: calculator::DefFunctionResults)
                    -> Promise<calculator::DefFunctionResults, Error>
    {
        results.get().set_func(
            calculator::function::ToClient::new(
                FunctionImpl::new(params.get().get_param_count() as u32, pry!(params.get().get_body())))
                .from_server::<LocalClient>());
        Promise::ok(results)
    }
    fn get_operator(&mut self,
                    params: calculator::GetOperatorParams,
                    mut results: calculator::GetOperatorResults)
                    -> Promise<calculator::GetOperatorResults, Error>
    {
        let op = pry!(params.get().get_op());
        results.get().set_func(
            calculator::function::ToClient::new(OperatorImpl {op : op}).from_server::<LocalClient>());
        Promise::ok(results)
    }
}

pub fn accept_loop(listener: tcp::Listener,
                   mut task_set: TaskSet<(), Box<::std::error::Error>>,
                   calc: calculator::Client,
                   )
                   -> Promise<(), ::std::io::Error>
{
    listener.accept().lift().then(move |(listener, stream)| {
        let stream2 = pry!(stream.try_clone());
        let mut network =
            twoparty::VatNetwork::new(stream, stream2,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        // Should put in the calculator for the bootstrap.
        let rpc_system = rpc::System::new(Box::new(network), Some(calc.clone().client));

        task_set.add(disconnect_promise.attach(rpc_system).lift());
        accept_loop(listener, task_set, calc)
    })
}

struct Reaper;

impl TaskReaper<(), Box<::std::error::Error>> for Reaper {
    fn task_failed(&mut self, error: Box<::std::error::Error>) {
        println!("Task failed: {}", error);
    }
}

pub fn main() {
    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server ADDRESS[:PORT]", args[0]);
        return;
    }

    EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let listener = try!(tcp::Listener::bind(addr));

        let calc =
            calculator::ToClient::new(CalculatorImpl).from_server::<LocalClient>();

        let task_set = TaskSet::new(Box::new(Reaper));
        try!(accept_loop(listener, task_set, calc).wait(wait_scope));

        Ok(())
    }).expect("top level error");

    //let rpc_server = EzRpcServer::new(&*args[2]).unwrap();

    // There's got to be a better way to do this.
    //let calculator = Box::new(calculator::ServerDispatch { server : Box::new(CalculatorImpl)});

    //let _ = rpc_server.serve(calculator);
}
<commit_msg>delete some old commented-out code<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use capnp::Error;
use capnp::primitive_list;

use capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;

use calculator_capnp::calculator;
use gj::{EventLoop, Promise, TaskReaper, TaskSet};
use gj::io::tcp;

struct ValueImpl {
    value: f64
}

impl ValueImpl {
    fn new(value: f64) -> ValueImpl {
        ValueImpl { value: value }
    }
}

impl calculator::value::Server for ValueImpl {
    fn read(&mut self,
            _params: calculator::value::ReadParams,
            mut results: calculator::value::ReadResults)
            -> Promise<calculator::value::ReadResults, Error>
    {
        results.get().set_value(self.value);
        Promise::ok(results)
    }
}

fn evaluate_impl(expression: calculator::expression::Reader,
                 params: Option<primitive_list::Reader<f64>>)
                 -> Promise<f64, Error>
{
    match pry!(expression.which()) {
        calculator::expression::Literal(v) => {
            Promise::ok(v)
        },
        calculator::expression::PreviousResult(p) => {
            pry!(p).read_request().send().promise.map(|v| {
                Ok(try!(v.get()).get_value())
            })
        }
        calculator::expression::Parameter(p) => {
            match params {
                Some(params) if p < params.len() => {
                    Promise::ok(params.get(p))
                }
                _ => {
                    Promise::err(Error::failed(format!("bad parameter: {}", p)))
                }
            }
        }
        calculator::expression::Call(call) => {
            let func = pry!(call.get_function());
            let mut param_promises = Vec::new();
            for param in pry!(call.get_params()).iter() {
                param_promises.push(evaluate_impl(param, params));
            }
            Promise::all(param_promises.into_iter()).then(move |param_values| {
                let mut request = func.call_request();
                {
                    let mut params = request.get().init_params(param_values.len() as u32);
                    for ii in 0..param_values.len() {
                        params.set(ii as u32, param_values[ii]);
                    }
                }
                request.send().promise.map(|result| {
                    Ok(try!(result.get()).get_value())
                })
            })
        }
    }
}

struct FunctionImpl {
    param_count: u32,
    body: ::capnp::message::Builder<::capnp::message::HeapAllocator>,
}

impl FunctionImpl {
    fn new(param_count: u32, body: calculator::expression::Reader) -> FunctionImpl {
        let mut result = FunctionImpl {
            param_count: param_count,
            body: ::capnp::message::Builder::new_default()
        };
        result.body.set_root(body).unwrap();
        result
    }
}

impl calculator::function::Server for FunctionImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != self.param_count {
            Promise::err(Error::failed(
                format!("Expect {} parameters but got {}.", self.param_count, params.len())))
        } else {
            evaluate_impl(
                pry!(self.body.get_root::<calculator::expression::Builder>()).as_reader(),
                Some(params)).map(move |v| {
                    results.get().set_value(v);
                    Ok(results)
                })
        }
    }
}

#[derive(Clone, Copy)]
pub struct OperatorImpl {
    op: calculator::Operator,
}

impl calculator::function::Server for OperatorImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
            -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(Error::failed("Wrong number of paramters.".to_string()))
        } else {
            let v = match self.op {
                calculator::Operator::Add =>       params.get(0) + params.get(1),
                calculator::Operator::Subtract =>  params.get(0) - params.get(1),
                calculator::Operator::Multiply =>  params.get(0) * params.get(1),
                calculator::Operator::Divide =>    params.get(0) / params.get(1),
            };
            results.get().set_value(v);
            Promise::ok(results)
        }
    }
}

struct CalculatorImpl;

impl calculator::Server for CalculatorImpl {
    fn evaluate(&mut self,
                params: calculator::EvaluateParams,
                mut results: calculator::EvaluateResults)
                -> Promise<calculator::EvaluateResults, Error>
    {
        evaluate_impl(pry!(params.get().get_expression()), None).map(move |v| {
            results.get().set_value(
                calculator::value::ToClient::new(ValueImpl::new(v)).from_server::<LocalClient>());
            Ok(results)
        })
    }
    fn def_function(&mut self,
                    params: calculator::DefFunctionParams,
                    mut results: calculator::DefFunctionResults)
                    -> Promise<calculator::DefFunctionResults, Error>
    {
        results.get().set_func(
            calculator::function::ToClient::new(
                FunctionImpl::new(params.get().get_param_count() as u32, pry!(params.get().get_body())))
                .from_server::<LocalClient>());
        Promise::ok(results)
    }
    fn get_operator(&mut self,
                    params: calculator::GetOperatorParams,
                    mut results: calculator::GetOperatorResults)
                    -> Promise<calculator::GetOperatorResults, Error>
    {
        let op = pry!(params.get().get_op());
        results.get().set_func(
            calculator::function::ToClient::new(OperatorImpl {op : op}).from_server::<LocalClient>());
        Promise::ok(results)
    }
}

pub fn accept_loop(listener: tcp::Listener,
                   mut task_set: TaskSet<(), Box<::std::error::Error>>,
                   calc: calculator::Client,
                   )
                   -> Promise<(), ::std::io::Error>
{
    listener.accept().lift().then(move |(listener, stream)| {
        let stream2 = pry!(stream.try_clone());
        let mut network =
            twoparty::VatNetwork::new(stream, stream2,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        // Should put in the calculator for the bootstrap.
        let rpc_system = rpc::System::new(Box::new(network), Some(calc.clone().client));

        task_set.add(disconnect_promise.attach(rpc_system).lift());
        accept_loop(listener, task_set, calc)
    })
}

struct Reaper;

impl TaskReaper<(), Box<::std::error::Error>> for Reaper {
    fn task_failed(&mut self, error: Box<::std::error::Error>) {
        println!("Task failed: {}", error);
    }
}

pub fn main() {
    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server ADDRESS[:PORT]", args[0]);
        return;
    }

    EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let listener = try!(tcp::Listener::bind(addr));

        let calc =
            calculator::ToClient::new(CalculatorImpl).from_server::<LocalClient>();

        let task_set = TaskSet::new(Box::new(Reaper));
        try!(accept_loop(listener, task_set, calc).wait(wait_scope));

        Ok(())
    }).expect("top level error");
}
<|endoftext|>


<commit_before>
use std::fmt;
use std::error::Error;

use bitreader::{BitReader,BitReaderError};

pub type DeserializationResult<T> = Result<T, DeserializationError>;

#[derive(Debug,Clone,Copy)]
pub enum DeserializationError {
    InvalidSectionHeader,
    UnexpectedValue {
        position: u64,
        expected: i64,
        got: i64,
    },
    BitReaderError(BitReaderError)
}

impl Error for DeserializationError {
    fn description(&self) -> &str {
        match *self {
            DeserializationError::InvalidSectionHeader => "Invalid section header",
            DeserializationError::UnexpectedValue{..} => "Invalid value in the source data",
            DeserializationError::BitReaderError(ref err) => err.description(),
        }
    }
}

impl fmt::Display for DeserializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DeserializationError::InvalidSectionHeader => self.description().fmt(fmt),
            DeserializationError::UnexpectedValue{ position, expected, got } =>
                write!(fmt, "Expected {} at position {}, but got {}", expected, position, got),
            DeserializationError::BitReaderError(ref err) => err.fmt(fmt),
        }
    }
}

impl From<BitReaderError> for DeserializationError {
    fn from(err: BitReaderError) -> DeserializationError {
        DeserializationError::BitReaderError(err)
    }
}

pub trait Deserialize: Sized {
    fn deserialize(reader: &mut BitReader) -> DeserializationResult<Self>;

    fn from_bytes(bytes: &[u8]) -> DeserializationResult<Self> {
        let mut reader = BitReader::new(bytes);
        Deserialize::deserialize(&mut reader)
    }
}

pub fn reserved(reader: &mut BitReader, bits: u8) -> DeserializationResult<()> {
    expect(reader, bits, -1)
}

pub fn expect(reader: &mut BitReader, bits: u8, reference_value: i64) -> DeserializationResult<()> {
    let value = try!(reader.read_i64(bits));
    if value != reference_value {
        return Err(DeserializationError::UnexpectedValue {
            position: reader.position(),
            expected: reference_value,
            got: value,
        });
    }
    Ok(())
}
<commit_msg>Change the 'expect' special field to be unsigned.<commit_after>
use std::fmt;
use std::error::Error;

use bitreader::{BitReader,BitReaderError};

pub type DeserializationResult<T> = Result<T, DeserializationError>;

#[derive(Debug,Clone,Copy)]
pub enum DeserializationError {
    InvalidSectionHeader,
    UnexpectedValue {
        position: u64,
        expected: u64,
        got: u64,
    },
    BitReaderError(BitReaderError)
}

impl Error for DeserializationError {
    fn description(&self) -> &str {
        match *self {
            DeserializationError::InvalidSectionHeader => "Invalid section header",
            DeserializationError::UnexpectedValue{..} => "Invalid value in the source data",
            DeserializationError::BitReaderError(ref err) => err.description(),
        }
    }
}

impl fmt::Display for DeserializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DeserializationError::InvalidSectionHeader => self.description().fmt(fmt),
            DeserializationError::UnexpectedValue{ position, expected, got } =>
                write!(fmt, "Expected {} at position {}, but got {}", expected, position, got),
            DeserializationError::BitReaderError(ref err) => err.fmt(fmt),
        }
    }
}

impl From<BitReaderError> for DeserializationError {
    fn from(err: BitReaderError) -> DeserializationError {
        DeserializationError::BitReaderError(err)
    }
}

pub trait Deserialize: Sized {
    fn deserialize(reader: &mut BitReader) -> DeserializationResult<Self>;

    fn from_bytes(bytes: &[u8]) -> DeserializationResult<Self> {
        let mut reader = BitReader::new(bytes);
        Deserialize::deserialize(&mut reader)
    }
}

pub fn reserved(reader: &mut BitReader, bits: u8) -> DeserializationResult<()> {
    let all_on: u64 = !0;
    let expected = all_on >> (64 - bits);
    expect(reader, bits, expected)
}

pub fn expect(reader: &mut BitReader, bits: u8, reference_value: u64) -> DeserializationResult<()> {
    let value = try!(reader.read_u64(bits));
    if value != reference_value {
        return Err(DeserializationError::UnexpectedValue {
            position: reader.position(),
            expected: reference_value,
            got: value,
        });
    }
    Ok(())
}
<|endoftext|>