<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::borrow::BorrowMut;
use std::fmt;
use std::fmt::Display;
use std::cmp;

type Id = String;

/// Returns an `Id` with prefix `x` that is not in the set `vars`
fn fresh_var_like(x: &Id, vars: HashSet<Id>) -> Id {
    let mut suffix = 0;
    let mut result = x.clone();
    let len = result.len();
    loop {
        result.push_str(&suffix.to_string());

        if !vars.contains(&result) {
            return result;
        }

        suffix += 1;
        result.truncate(len);
    }
}

#[derive(Debug)]
pub enum EvaluationError {
    UnboundVariable(String),
    IllformedExpression,
}

impl fmt::Display for EvaluationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::EvaluationError::*;
        match *self {
            UnboundVariable(ref id) => write!(f, "Encountered unbound variable: {}", id),
            IllformedExpression => write!(f, "Illformed expression"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Type {
    Var(Id),
    Fun(Box<Type>, Box<Type>),
    Forall(Id, Box<Type>),
}

impl PartialEq for Type {
    /// Equality is defined as alpha-equivalence of types
    fn eq(&self, other: &Type) -> bool {
        use self::Type::*;

        match (self,other) {
            (&Var(ref x),&Var(ref y)) => {
                *x == *y
            },
            (&Fun(ref t1, ref t2),&Fun(ref t3, ref t4)) => {
                *t1 == *t3 && *t2 == *t4
            },
            (&Forall(ref A, ref t1),&Forall(ref B, ref t2)) => {
                t1.subst(&Var(B.clone()), &A) == **t2
            },
            _ => false,
        }
    }
}

impl Eq for Type { }

impl Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Var(ref x) => write!(f,"{}",x),
            Type::Fun(ref a, ref b) => write!(f,"({}) -> {}",a,b),
            Type::Forall(ref x, ref t) => write!(f,"(forall {}. {})", x, t),
        }
    }
}

impl Type {
    /// Returns the result of the capture avoiding substitution `self` {`t`/`X`}
    fn subst(&self, t: &Type, X: &str) -> Type {
        match *self {
            Type::Var(ref Y) => {
                if X == *Y {
                    t.clone()
                } else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.subst(t,X)), Box::new(t2.subst(t,X)))
            },
            Type::Forall(ref Y, ref tau) => {
                if X == *Y {
                    self.clone()
                } else {
                    let mut fvs = t.free_vars();
                    if fvs.contains(Y) {
                        let mut vars = self.vars();
                        vars.extend(fvs.drain());
                        vars.insert(String::from(X));
                        let fresh_id = fresh_var_like(Y, vars);
                        let renamed = self.rename(Y, &fresh_id);
                        renamed.subst(t, X)
                    } else {
                        Type::Forall(Y.clone(), Box::new(tau.subst(t,X)))
                    }
                }
            },
        }
    }

    /// Returns an identical type with `var` renamed into `into`
    fn rename(&self, var: &str, into: &str) -> Type {
        match *self {
            Type::Var(ref X) => {
                if *X == var {
                    Type::Var(String::from(into))
                } else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.rename(var, into)),
                        Box::new(t2.rename(var,into)))
            },
            Type::Forall(ref X, ref tau) => {
                let binder = {
                    if *X == var {
                        String::from(into)
                    } else {
                        X.clone()
                    }
                };
                Type::Forall(binder, Box::new(tau.rename(var, into)))
            },
        }
    }

    /// Returns a set the free variables contained in `self`
    fn free_vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut fvs = HashSet::new();
                fvs.insert(X.clone());
                fvs
            },
            Type::Fun(ref t1, ref t2) => {
                let mut fvs = t1.free_vars();
                let mut t2_fvs = t2.free_vars();
                fvs.extend(t2_fvs.drain());
                fvs
            }
            Type::Forall(ref X, ref t) => {
                let mut fvs = t.free_vars();
                fvs.remove(X);
                fvs
            }
        }
    }

    /// Returns a set containing all of the variables contained in `self`
    fn vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut vars = HashSet::new();
                vars.insert(X.clone());
                vars
            },
            Type::Fun(ref t1, ref t2) => {
                let mut vars = t1.vars();
                let mut t2_vars = t2.vars();
                vars.extend(t2_vars.drain());
                vars
            }
            Type::Forall(ref X, ref t) => {
                let mut vars = t.vars();
                vars.insert(X.clone());
                vars
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
    Var(Id),
    Lam(Id, Box<Type>, Box<Expr>),
    App(Box<Expr>, Box<Expr>),
    TLam(Id, Box<Expr>),
    TApp(Box<Expr>, Box<Type>),
    Let(Id, Box<Type>, Box<Expr>, Box<Expr>),
    TLet(Id, Box<Type>, Box<Expr>),
}

impl Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Var(ref x) => write!(f,"{}",x),
            Expr::Lam(ref x, ref t, ref e) => write!(f,"(\\{}:{}.{})",x,t,e),
            Expr::App(ref e1, ref e2) => write!(f,"({} {})",e1,e2),
            Expr::TLam(ref X, ref e) => write!(f,"(/\\{}.{})",X,e),
            Expr::TApp(ref e, ref t) => write!(f,"({} [{}])",e,t),
            Expr::Let(ref x, ref t, ref e1, ref e2) => write!(f,"(let {}:{} = {} in {})",x,t,e1,e2),
            Expr::TLet(ref X, ref t, ref e) => write!(f,"(Let {} = {} in {})",X,t,e),
        }
    }
}

impl Expr {
    /// Returns the normal form of `self` under call-by-value semantics
    pub fn eval(&self) -> Result<Expr,EvaluationError> {
        match *self {
            Expr::Var(ref x) => {
                Err(EvaluationError::UnboundVariable(x.clone()))
            },
            Expr::Lam(_,_,_) | Expr::TLam(_,_) => Ok(self.clone()),
            Expr::App(ref e1, ref e2) => {
                let v1 = e1.eval()?;
                let v2 = e2.eval()?;
                if let Expr::Lam(x,t,e3) = v1 {
                    let new_expr = e3.subst(&v2, &x);
                    new_expr.eval()
                } else {
                    Err(EvaluationError::IllformedExpression)
                }
            },
            Expr::TApp(ref e, ref t) => {
                let v = e.eval()?;
                if let Expr::TLam(X,e) = v {
                    let new_expr = e.subst_type(t, &X);
                    new_expr.eval()
                } else {
                    Err(EvaluationError::IllformedExpression)
                }
            },
            Expr::Let(ref x, ref t, ref e1, ref e2) => {
                Expr::App(
                    Box::new(Expr::Lam(
                        x.clone(),
                        t.clone(),
                        e2.clone())),
                    e1.clone()).eval()
            },
            Expr::TLet(ref X, ref t, ref e) => {
                Expr::TApp(
                    Box::new(Expr::TLam(
                        X.clone(),
                        e.clone())),
                    t.clone()).eval()
            },
        }
    }

    /// Returns the result of the capture avoiding substitution `self` {`e`/`x`}
    fn subst(&self, e: &Expr, x: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                if x == *y {
                    e.clone()
                } else {
                    self.clone()
                }
            },
            Expr::Lam(ref y,ref t,ref e1) => {
                if x == *y {
                    self.clone()
                } else {
                    // TODO: check freshness
                    unimplemented!()
                }
            },
            Expr::App(ref e1,ref e2) => {
                Expr::App(Box::new(e1.subst(e,x)), Box::new(e2.subst(e,x)))
            },
            Expr::TLam(ref X,ref e1) => {
                Expr::TLam(X.clone(), Box::new(e1.subst(e,x)))
            },
            Expr::TApp(ref e1,ref t) => {
                Expr::TApp(Box::new(e1.subst(e,x)), t.clone())
            },
            Expr::Let(ref y,ref t,ref e1,ref e2) => {
                let new_e1 = e1.subst(e, x);
                // Unclear
                unimplemented!()
            },
            Expr::TLet(ref X,ref t,ref e1) => {
                Expr::TLet(X.clone(), t.clone(), Box::new(e1.subst(e,x)))
            },
        }
    }

    fn subst_type(&self, to: &Type, from: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                self.clone()
            },
            Expr::Lam(ref y,ref t,ref e1) => {
                let new_t = t.subst(to, from);
                Expr::Lam(y.clone(), Box::new(new_t), Box::new(e1.subst_type(to,from)))
            },
            Expr::App(ref e1,ref e2) => {
                Expr::App(Box::new(e1.subst_type(to,from)), Box::new(e2.subst_type(to,from)))
            },
            Expr::TLam(ref X,ref e1) => {
                if *X == from {
                    self.clone()
                } else {
                    unimplemented!()
                }
            },
            Expr::TApp(ref e1,ref t) => {
                let new_t = t.subst(to, from);
                let new_e1 = e1.subst_type(to, from);
                Expr::TApp(Box::new(new_e1), Box::new(new_t))
            },
            Expr::Let(ref y,ref t,ref e1,ref e2) => {
                let new_t = t.subst(to, from);
                let new_e1 = e1.subst_type(to, from);
                let new_e2 = e2.subst_type(to, from);
                Expr::Let(y.clone(), Box::new(new_t), Box::new(new_e1), Box::new(new_e2))
            },
            Expr::TLet(ref X,ref t,ref e1) => {
                let new_t = t.subst(to, from);
                if *X == from {
                    Expr::TLet(X.clone(), Box::new(new_t), e1.clone())
                }
                else {
                    unimplemented!()
                }
            },
        }
    }

    /// Returns an identical expression with expression variable `var` renamed into `into`
    fn rename(&self, var: &str, into: &str) -> Expr {
        unimplemented!()
    }

    /// Returns an identical expression with type variable `var` renamed into `into`
    fn rename_type(&self, var: &str, into: &str) -> Expr {
        unimplemented!()
    }

    /// Returns a set the free variables contained in `self`
    fn free_vars(&self) -> HashSet<Id> {
        unimplemented!()
    }

    /// Returns a set containing all of the variables contained in `self`
    fn vars(&self) -> HashSet<Id> {
        match *self {
            Expr::Var(ref x) => {
                let mut vars = HashSet::new();
                vars.insert(x.clone());
                vars
            },
            Expr::Lam(ref x, _, ref e) => {
                let mut vars = e.vars();
                vars.insert(x.clone());
                vars
            },
            Expr::App(ref e1, ref e2) => {
                let mut vars = e1.vars();
                let mut e2_vars = e2.vars();
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLam(_, ref e) => {
                e.vars()
            },
            Expr::TApp(ref e, _) => {
                e.vars()
            },
            Expr::Let(ref x, _, ref e1, ref e2) => {
                let mut vars = e1.vars();
                let mut e2_vars = e2.vars();
                vars.extend(e2_vars.drain());
                vars.insert(x.clone());
                vars
            },
            Expr::TLet(_, _, ref e) => {
                e.vars()
            }
        }
    }

    /// Returns a set the free type variables contained in `self`
    fn free_type_vars(&self) -> HashSet<Id> {
        unimplemented!()
    }

    /// Returns a set containing all of the type variables contained in `self`
    fn type_vars(&self) -> HashSet<Id> {
        match *self {
            Expr::Var(_) => {
                HashSet::new()
            },
            Expr::Lam(_, ref t, ref e) => {
                let mut vars = t.vars();
                let mut e_vars = e.type_vars();
                vars.extend(e_vars.drain());
                vars
            },
            Expr::App(ref e1, ref e2) => {
                let mut vars = e1.type_vars();
                let mut e2_vars = e2.type_vars();
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLam(ref X, ref e) => {
                let mut vars = e.type_vars();
                vars.insert(X.clone());
                vars
            },
            Expr::TApp(ref e, ref t) => {
                let mut vars = e.type_vars();
                let mut t_vars = e.vars();
                vars.extend(t_vars.drain());
                vars
            },
            Expr::Let(_, ref t, ref e1, ref e2) => {
                let mut vars = t.vars();
                let mut e1_vars = e1.type_vars();
                let mut e2_vars = e2.type_vars();
                vars.extend(e1_vars.drain());
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLet(ref X, ref t, ref e) => {
                let mut vars = t.vars();
                let mut e_vars = e.type_vars();
                vars.extend(e_vars.drain());
                vars.insert(X.clone());
                vars
            }
        }
    }
}<commit_msg>Implement free type vars for expressions<commit_after>use std::collections::HashMap;
use std::collections::HashSet;
use std::borrow::BorrowMut;
use std::fmt;
use std::fmt::Display;
use std::cmp;

type Id = String;

/// Returns an `Id` with prefix `x` that is not in the set `vars`
fn fresh_var_like(x: &Id, vars: HashSet<Id>) -> Id {
    let mut suffix = 0;
    let mut result = x.clone();
    let len = result.len();
    loop {
        result.push_str(&suffix.to_string());

        if !vars.contains(&result) {
            return result;
        }

        suffix += 1;
        result.truncate(len);
    }
}

#[derive(Debug)]
pub enum EvaluationError {
    UnboundVariable(String),
    IllformedExpression,
}

impl fmt::Display for EvaluationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::EvaluationError::*;
        match *self {
            UnboundVariable(ref id) => write!(f, "Encountered unbound variable: {}", id),
            IllformedExpression => write!(f, "Illformed expression"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Type {
    Var(Id),
    Fun(Box<Type>, Box<Type>),
    Forall(Id, Box<Type>),
}

impl PartialEq for Type {
    /// Equality is defined as alpha-equivalence of types
    fn eq(&self, other: &Type) -> bool {
        use self::Type::*;

        match (self,other) {
            (&Var(ref x),&Var(ref y)) => {
                *x == *y
            },
            (&Fun(ref t1, ref t2),&Fun(ref t3, ref t4)) => {
                *t1 == *t3 && *t2 == *t4
            },
            (&Forall(ref A, ref t1),&Forall(ref B, ref t2)) => {
                t1.subst(&Var(B.clone()), &A) == **t2
            },
            _ => false,
        }
    }
}

impl Eq for Type { }

impl Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Var(ref x) => write!(f,"{}",x),
            Type::Fun(ref a, ref b) => write!(f,"({}) -> {}",a,b),
            Type::Forall(ref x, ref t) => write!(f,"(forall {}. {})", x, t),
        }
    }
}

impl Type {
    /// Returns the result of the capture avoiding substitution `self` {`t`/`X`}
    fn subst(&self, t: &Type, X: &str) -> Type {
        match *self {
            Type::Var(ref Y) => {
                if X == *Y {
                    t.clone()
                } else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.subst(t,X)), Box::new(t2.subst(t,X)))
            },
            Type::Forall(ref Y, ref tau) => {
                if X == *Y {
                    self.clone()
                } else {
                    let mut fvs = t.free_vars();
                    if fvs.contains(Y) {
                        let mut vars = self.vars();
                        vars.extend(fvs.drain());
                        vars.insert(String::from(X));
                        let fresh_id = fresh_var_like(Y, vars);
                        let renamed = self.rename(Y, &fresh_id);
                        renamed.subst(t, X)
                    } else {
                        Type::Forall(Y.clone(), Box::new(tau.subst(t,X)))
                    }
                }
            },
        }
    }

    /// Returns an identical type with `var` renamed into `into`
    fn rename(&self, var: &str, into: &str) -> Type {
        match *self {
            Type::Var(ref X) => {
                if *X == var {
                    Type::Var(String::from(into))
                } else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.rename(var, into)),
                        Box::new(t2.rename(var,into)))
            },
            Type::Forall(ref X, ref tau) => {
                let binder = {
                    if *X == var {
                        String::from(into)
                    } else {
                        X.clone()
                    }
                };
                Type::Forall(binder, Box::new(tau.rename(var, into)))
            },
        }
    }

    /// Returns a set the free variables contained in `self`
    fn free_vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut fvs = HashSet::new();
                fvs.insert(X.clone());
                fvs
            },
            Type::Fun(ref t1, ref t2) => {
                let mut fvs = t1.free_vars();
                let mut t2_fvs = t2.free_vars();
                fvs.extend(t2_fvs.drain());
                fvs
            }
            Type::Forall(ref X, ref t) => {
                let mut fvs = t.free_vars();
                fvs.remove(X);
                fvs
            }
        }
    }

    /// Returns a set containing all of the variables contained in `self`
    fn vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut vars = HashSet::new();
                vars.insert(X.clone());
                vars
            },
            Type::Fun(ref t1, ref t2) => {
                let mut vars = t1.vars();
                let mut t2_vars = t2.vars();
                vars.extend(t2_vars.drain());
                vars
            }
            Type::Forall(ref X, ref t) => {
                let mut vars = t.vars();
                vars.insert(X.clone());
                vars
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
    Var(Id),
    Lam(Id, Box<Type>, Box<Expr>),
    App(Box<Expr>, Box<Expr>),
    TLam(Id, Box<Expr>),
    TApp(Box<Expr>, Box<Type>),
    Let(Id, Box<Type>, Box<Expr>, Box<Expr>),
    TLet(Id, Box<Type>, Box<Expr>),
}

impl Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Var(ref x) => write!(f,"{}",x),
            Expr::Lam(ref x, ref t, ref e) => write!(f,"(\\{}:{}.{})",x,t,e),
            Expr::App(ref e1, ref e2) => write!(f,"({} {})",e1,e2),
            Expr::TLam(ref X, ref e) => write!(f,"(/\\{}.{})",X,e),
            Expr::TApp(ref e, ref t) => write!(f,"({} [{}])",e,t),
            Expr::Let(ref x, ref t, ref e1, ref e2) => write!(f,"(let {}:{} = {} in {})",x,t,e1,e2),
            Expr::TLet(ref X, ref t, ref e) => write!(f,"(Let {} = {} in {})",X,t,e),
        }
    }
}

impl Expr {
    /// Returns the normal form of `self` under call-by-value semantics
    pub fn eval(&self) -> Result<Expr,EvaluationError> {
        match *self {
            Expr::Var(ref x) => {
                Err(EvaluationError::UnboundVariable(x.clone()))
            },
            Expr::Lam(_,_,_) | Expr::TLam(_,_) => Ok(self.clone()),
            Expr::App(ref e1, ref e2) => {
                let v1 = e1.eval()?;
                let v2 = e2.eval()?;
                if let Expr::Lam(x,t,e3) = v1 {
                    let new_expr = e3.subst(&v2, &x);
                    new_expr.eval()
                } else {
                    Err(EvaluationError::IllformedExpression)
                }
            },
            Expr::TApp(ref e, ref t) => {
                let v = e.eval()?;
                if let Expr::TLam(X,e) = v {
                    let new_expr = e.subst_type(t, &X);
                    new_expr.eval()
                } else {
                    Err(EvaluationError::IllformedExpression)
                }
            },
            Expr::Let(ref x, ref t, ref e1, ref e2) => {
                Expr::App(
                    Box::new(Expr::Lam(
                        x.clone(),
                        t.clone(),
                        e2.clone())),
                    e1.clone()).eval()
            },
            Expr::TLet(ref X, ref t, ref e) => {
                Expr::TApp(
                    Box::new(Expr::TLam(
                        X.clone(),
                        e.clone())),
                    t.clone()).eval()
            },
        }
    }

    /// Returns the result of the capture avoiding substitution `self` {`e`/`x`}
    fn subst(&self, e: &Expr, x: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                if x == *y {
                    e.clone()
                } else {
                    self.clone()
                }
            },
            Expr::Lam(ref y,ref t,ref e1) => {
                if x == *y {
                    self.clone()
                } else {
                    // TODO: check freshness
                    unimplemented!()
                }
            },
            Expr::App(ref e1,ref e2) => {
                Expr::App(Box::new(e1.subst(e,x)), Box::new(e2.subst(e,x)))
            },
            Expr::TLam(ref X,ref e1) => {
                Expr::TLam(X.clone(), Box::new(e1.subst(e,x)))
            },
            Expr::TApp(ref e1,ref t) => {
                Expr::TApp(Box::new(e1.subst(e,x)), t.clone())
            },
            Expr::Let(ref y,ref t,ref e1,ref e2) => {
                let new_e1 = e1.subst(e, x);
                // Unclear
                unimplemented!()
            },
            Expr::TLet(ref X,ref t,ref e1) => {
                Expr::TLet(X.clone(), t.clone(), Box::new(e1.subst(e,x)))
            },
        }
    }

    fn subst_type(&self, to: &Type, from: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                self.clone()
            },
            Expr::Lam(ref y,ref t,ref e1) => {
                let new_t = t.subst(to, from);
                Expr::Lam(y.clone(), Box::new(new_t), Box::new(e1.subst_type(to,from)))
            },
            Expr::App(ref e1,ref e2) => {
                Expr::App(Box::new(e1.subst_type(to,from)), Box::new(e2.subst_type(to,from)))
            },
            Expr::TLam(ref X,ref e1) => {
                if *X == from {
                    self.clone()
                } else {
                    unimplemented!()
                }
            },
            Expr::TApp(ref e1,ref t) => {
                let new_t = t.subst(to, from);
                let new_e1 = e1.subst_type(to, from);
                Expr::TApp(Box::new(new_e1), Box::new(new_t))
            },
            Expr::Let(ref y,ref t,ref e1,ref e2) => {
                let new_t = t.subst(to, from);
                let new_e1 = e1.subst_type(to, from);
                let new_e2 = e2.subst_type(to, from);
                Expr::Let(y.clone(), Box::new(new_t), Box::new(new_e1), Box::new(new_e2))
            },
            Expr::TLet(ref X,ref t,ref e1) => {
                let new_t = t.subst(to, from);
                if *X == from {
                    Expr::TLet(X.clone(), Box::new(new_t), e1.clone())
                }
                else {
                    unimplemented!()
                }
            },
        }
    }

    /// Returns an identical expression with expression variable `var` renamed into `into`
    fn rename(&self, var: &str, into: &str) -> Expr {
        unimplemented!()
    }

    /// Returns an identical expression with type variable `var` renamed into `into`
    fn rename_type(&self, var: &str, into: &str) -> Expr {
        unimplemented!()
    }

    /// Returns a set the free variables contained in `self`
    fn free_vars(&self) -> HashSet<Id> {
        unimplemented!()
    }

    /// Returns a set containing all of the variables contained in `self`
    fn vars(&self) -> HashSet<Id> {
        match *self {
            Expr::Var(ref x) => {
                let mut vars = HashSet::new();
                vars.insert(x.clone());
                vars
            },
            Expr::Lam(ref x, _, ref e) => {
                let mut vars = e.vars();
                vars.insert(x.clone());
                vars
            },
            Expr::App(ref e1, ref e2) => {
                let mut vars = e1.vars();
                let mut e2_vars = e2.vars();
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLam(_, ref e) => {
                e.vars()
            },
            Expr::TApp(ref e, _) => {
                e.vars()
            },
            Expr::Let(ref x, _, ref e1, ref e2) => {
                let mut vars = e1.vars();
                let mut e2_vars = e2.vars();
                vars.extend(e2_vars.drain());
                vars.insert(x.clone());
                vars
            },
            Expr::TLet(_, _, ref e) => {
                e.vars()
            }
        }
    }

    /// Returns a set the free type variables contained in `self`
    fn free_type_vars(&self) -> HashSet<Id> {
        match *self {
            Expr::Var(_) => {
                HashSet::new()
            },
            Expr::Lam(_, ref t, ref e) => {
                let mut vars = t.vars();
                let mut e_vars = e.type_vars();
                vars.extend(e_vars.drain());
                vars
            },
            Expr::App(ref e1, ref e2) => {
                let mut vars = e1.type_vars();
                let mut e2_vars = e2.type_vars();
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLam(ref X, ref e) => {
                let mut vars = e.type_vars();
                vars.remove(X.clone());
                vars
            },
            Expr::TApp(ref e, ref t) => {
                let mut vars = e.type_vars();
                let mut t_vars = e.vars();
                vars.extend(t_vars.drain());
                vars
            },
            Expr::Let(_, ref t, ref e1, ref e2) => {
                let mut vars = t.vars();
                let mut e1_vars = e1.type_vars();
                let mut e2_vars = e2.type_vars();
                vars.extend(e1_vars.drain());
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLet(ref X, ref t, ref e) => {
                let mut vars = t.vars();
                let mut e_vars = e.type_vars();
                e_vars.remove(X.clone());
                vars.extend(e_vars.drain());
                vars
            }
        }
    }

    /// Returns a set containing all of the type variables contained in `self`
    fn type_vars(&self) -> HashSet<Id> {
        match *self {
            Expr::Var(_) => {
                HashSet::new()
            },
            Expr::Lam(_, ref t, ref e) => {
                let mut vars = t.vars();
                let mut e_vars = e.type_vars();
                vars.extend(e_vars.drain());
                vars
            },
            Expr::App(ref e1, ref e2) => {
                let mut vars = e1.type_vars();
                let mut e2_vars = e2.type_vars();
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLam(ref X, ref e) => {
                let mut vars = e.type_vars();
                vars.insert(X.clone());
                vars
            },
            Expr::TApp(ref e, ref t) => {
                let mut vars = e.type_vars();
                let mut t_vars = e.vars();
                vars.extend(t_vars.drain());
                vars
            },
            Expr::Let(_, ref t, ref e1, ref e2) => {
                let mut vars = t.vars();
                let mut e1_vars = e1.type_vars();
                let mut e2_vars = e2.type_vars();
                vars.extend(e1_vars.drain());
                vars.extend(e2_vars.drain());
                vars
            },
            Expr::TLet(ref X, ref t, ref e) => {
                let mut vars = t.vars();
                let mut e_vars = e.type_vars();
                vars.extend(e_vars.drain());
                vars.insert(X.clone());
                vars
            }
        }
    }
}<|endoftext|>


<commit_before>use std::sync::mpsc::{channel, Receiver, Sender};
use std::net::TcpStream;
use std::io::{Read, Write};
use std::sync::{Arc, RwLock};
use std::io;
use std::thread;

pub enum NeedsAck {
    Yes,
    No,
}

#[derive(Copy, Clone, PartialEq)]
pub enum State {
    Disconnected,
    Connected,
    SendingData,
    WaitingForData,
    Close,
}

pub struct GdbRemote {
    pub needs_ack: NeedsAck,
    pub writer: Sender<Vec<u8>>,
    pub reader: Receiver<Vec<u8>>,
    temp_data: Vec<u8>,
    state: Arc<RwLock<State>>,
}

static HEX_CHARS: &'static [u8; 16] = b"0123456789abcdef";

impl GdbRemote {
    pub fn new(needs_ack: NeedsAck) -> GdbRemote {
        let (tx, rx) = channel::<Vec<u8>>();

        GdbRemote {
            writer: tx,
            reader: rx,
            needs_ack: needs_ack,
            temp_data: Vec::new(),
            state: Arc::new(RwLock::new(State::Disconnected)),
        }
    }

    fn read_write_data(reader: &Receiver<Vec<u8>>, writer: &Sender<Vec<u8>>, stream: &mut TcpStream) -> io::Result<()> {
        match reader.recv() {
            Ok(data) => {
                // TODO: Less allocs
                let mut buffer = [0; 1024];
                let mut t = Vec::new();
                try!(stream.write_all(&data.into_boxed_slice()));
                let len = try!(stream.read(&mut buffer));
                for i in 0..len { t.push(buffer[i]); }
                match writer.send(t) {
                    Ok(()) => Ok(()),
                    Err(_) => Err(io::Error::new(io::ErrorKind::Other, "channel write failed")),
                }
            }

            Err(_) => Err(io::Error::new(io::ErrorKind::Other, "channel reade error")),
        }
    }

    fn set_state(&mut self, state: State) {
        *(*self.state).write().unwrap() = state
    }

    pub fn connect(&mut self, addr: &str) -> io::Result<()> {
        let mut stream = try!(TcpStream::connect(addr));

        self.set_state(State::Connected);

        let (main_tx, main_rx) = channel::<Vec<u8>>();
        let (thread_tx, thread_rx) = channel::<Vec<u8>>();

        self.writer = main_tx;
        self.reader = thread_rx;

        let state = self.state.clone();

        thread::spawn(move || {
            loop {
                match Self::read_write_data(&main_rx, &thread_tx, &mut stream) {
                    Err(e) => {
                        *(*state).write().unwrap() = State::Disconnected;
                        println!("Error reading/sending data {:?}", e);
                        break;
                    }

                    _ => (),
                }
            }
        });

        Ok(())
    }

    pub fn update(&mut self) {
        match self.reader.try_recv() {
            Ok(data) => {
                println!("got data {}", String::from_utf8(data).unwrap());
            }

            _ => (),
        }
    }

    #[inline]
    fn calc_checksum(data: &[u8]) -> u8 {
        let mut checksum = 0u32;
        for i in data {
            checksum += *i as u32;
        }
        (checksum & 0xff) as u8
    }

    #[inline]
    pub fn get_checksum_array(checksum: u8) -> [u8; 2] {
        let cs_string: [u8; 2] = [HEX_CHARS[((checksum >> 4) & 0xf) as usize],
                                  HEX_CHARS[(checksum & 0xf) as usize]];
        cs_string
    }

    pub fn get_processed_string(data: &str) -> String {
        let checksum = Self::calc_checksum(data.as_bytes());
        let cs_array = Self::get_checksum_array(checksum);

        // len + 4 = # <string> $xx (4 bytes extra needed)
        let mut gdb_string = String::with_capacity(data.len() + 4);

        gdb_string.push('$');
        gdb_string.push_str(data);
        gdb_string.push('#');
        gdb_string.push(cs_array[0] as char);
        gdb_string.push(cs_array[1] as char);

        gdb_string
    }

    pub fn send_command(&mut self, data: &str) -> io::Result<usize> {
        let command = Self::get_processed_string(data);
        self.send_command_raw(&command)
    }

    pub fn send_command_raw(&mut self, data: &str) -> io::Result<usize> {
        // TEMP fix me:
        self.temp_data.clear();
        for i in data.as_bytes().iter() { self.temp_data.push(*i) }
        let _ = self.writer.send(self.temp_data.clone());
        Ok((0))
    }

    fn get_state(&mut self) -> State {
        *(*self.state).read().unwrap()
    }

    pub fn send_no_ack_request(&mut self)-> io::Result<usize> {
        self.send_command_raw("+$QStartNoAckMode+#db")
    }

    pub fn get_data_sync(&mut self) -> Option<Vec<u8>> {
        match self.reader.recv() {
            Ok(data) => {
                self.temp_data.clear();
                for i in &data { self.temp_data.push(*i) }
                Some(self.temp_data.clone())
            }

            Err(_) => None,
        }
    }

    pub fn send_command_sync(&mut self, command: &str) -> Option<Vec<u8>> {
        if self.get_state() == State::Connected {
            self.send_command(command).unwrap();
            println!("waiting for data");
            let data = self.get_data_sync();
            println!("got data {}", data.as_ref().unwrap().len());
            data
        } else {
            None
        }
    }

    pub fn step_sync(&mut self) -> Option<Vec<u8>> {
        self.send_command_sync("s")
    }

    pub fn get_registers_sync(&mut self) -> Option<Vec<u8>> {
        self.send_command_sync("g")
    }
}

#[test]
fn test_checksum_calc() {
    let data: [u8; 8] = [32, 32, 32, 32, 64, 64, 64, 64];
    assert_eq!(GdbRemote::calc_checksum(&data), 128);
}

#[test]
fn test_process_string() {
    assert_eq!(GdbRemote::get_processed_string("f"), "$f#66");
}

<commit_msg>Support for getting memory<commit_after>use std::sync::mpsc::{channel, Receiver, Sender};
use std::net::TcpStream;
use std::io::{Read, Write};
use std::sync::{Arc, RwLock};
use std::io;
use std::thread;

pub enum NeedsAck {
    Yes,
    No,
}

#[derive(Copy, Clone, PartialEq)]
pub enum State {
    Disconnected,
    Connected,
    SendingData,
    WaitingForData,
    Close,
}

pub struct GdbRemote {
    pub needs_ack: NeedsAck,
    pub writer: Sender<Vec<u8>>,
    pub reader: Receiver<Vec<u8>>,
    temp_data: Vec<u8>,
    state: Arc<RwLock<State>>,
}

pub struct Memory {
    pub address: u64,
    pub data: Vec<u8>
}

static HEX_CHARS: &'static [u8; 16] = b"0123456789abcdef";

impl GdbRemote {
    pub fn new(needs_ack: NeedsAck) -> GdbRemote {
        let (tx, rx) = channel::<Vec<u8>>();

        GdbRemote {
            writer: tx,
            reader: rx,
            needs_ack: needs_ack,
            temp_data: Vec::new(),
            state: Arc::new(RwLock::new(State::Disconnected)),
        }
    }

    fn read_write_data(reader: &Receiver<Vec<u8>>, writer: &Sender<Vec<u8>>, stream: &mut TcpStream) -> io::Result<()> {
        match reader.recv() {
            Ok(data) => {
                // TODO: Less allocs
                let mut buffer = [0; 1024];
                let mut t = Vec::new();
                try!(stream.write_all(&data.into_boxed_slice()));
                let len = try!(stream.read(&mut buffer));
                for i in 0..len { t.push(buffer[i]); }
                match writer.send(t) {
                    Ok(()) => Ok(()),
                    Err(_) => Err(io::Error::new(io::ErrorKind::Other, "channel write failed")),
                }
            }

            Err(_) => Err(io::Error::new(io::ErrorKind::Other, "channel reade error")),
        }
    }

    fn set_state(&mut self, state: State) {
        *(*self.state).write().unwrap() = state
    }

    pub fn connect(&mut self, addr: &str) -> io::Result<()> {
        let mut stream = try!(TcpStream::connect(addr));

        self.set_state(State::Connected);

        let (main_tx, main_rx) = channel::<Vec<u8>>();
        let (thread_tx, thread_rx) = channel::<Vec<u8>>();

        self.writer = main_tx;
        self.reader = thread_rx;

        let state = self.state.clone();

        thread::spawn(move || {
            loop {
                match Self::read_write_data(&main_rx, &thread_tx, &mut stream) {
                    Err(e) => {
                        *(*state).write().unwrap() = State::Disconnected;
                        println!("Error reading/sending data {:?}", e);
                        break;
                    }

                    _ => (),
                }
            }
        });

        Ok(())
    }

    pub fn update(&mut self) {
        match self.reader.try_recv() {
            Ok(data) => {
                println!("got data {}", String::from_utf8(data).unwrap());
            }

            _ => (),
        }
    }

    #[inline]
    fn calc_checksum(data: &[u8]) -> u8 {
        let mut checksum = 0u32;
        for i in data {
            checksum += *i as u32;
        }
        (checksum & 0xff) as u8
    }

    #[inline]
    pub fn get_checksum_array(checksum: u8) -> [u8; 2] {
        let cs_string: [u8; 2] = [HEX_CHARS[((checksum >> 4) & 0xf) as usize],
                                  HEX_CHARS[(checksum & 0xf) as usize]];
        cs_string
    }

    pub fn get_processed_string(data: &str) -> String {
        let checksum = Self::calc_checksum(data.as_bytes());
        let cs_array = Self::get_checksum_array(checksum);

        // len + 4 = # <string> $xx (4 bytes extra needed)
        let mut gdb_string = String::with_capacity(data.len() + 4);

        gdb_string.push('$');
        gdb_string.push_str(data);
        gdb_string.push('#');
        gdb_string.push(cs_array[0] as char);
        gdb_string.push(cs_array[1] as char);

        gdb_string
    }

    pub fn send_command(&mut self, data: &str) -> io::Result<usize> {
        let command = Self::get_processed_string(data);
        self.send_command_raw(&command)
    }

    pub fn send_command_raw(&mut self, data: &str) -> io::Result<usize> {
        // TEMP fix me:
        self.temp_data.clear();
        for i in data.as_bytes().iter() { self.temp_data.push(*i) }
        let _ = self.writer.send(self.temp_data.clone());
        Ok((0))
    }

    fn get_state(&mut self) -> State {
        *(*self.state).read().unwrap()
    }

    pub fn send_no_ack_request(&mut self)-> io::Result<usize> {
        self.send_command_raw("+$QStartNoAckMode+#db")
    }

    fn from_hex(ch: u8) -> u8 {
        if (ch >= b'a') && (ch <= b'f') {
            return ch - b'a' + 10;
        }

        if (ch >= b'0') && (ch <= b'9') {
            return ch - b'0';
        }

        if (ch >= b'A') && (ch <= b'F') {
            return ch - b'A' + 10;
        }

        return 0;
    }

    pub fn get_data_sync(&mut self) -> Option<Vec<u8>> {
        match self.reader.recv() {
            Ok(data) => {
                self.temp_data.clear();
                for i in &data { self.temp_data.push(*i) }
                Some(self.temp_data.clone())
            }

            Err(_) => None,
        }
    }

    pub fn send_command_sync(&mut self, command: &str) -> Option<Vec<u8>> {
        if self.get_state() == State::Connected {
            self.send_command(command).unwrap();
            println!("waiting for data");
            let data = self.get_data_sync();
            println!("got data {}", data.as_ref().unwrap().len());
            data
        } else {
            None
        }
    }

    pub fn step_sync(&mut self) -> Option<Vec<u8>> {
        self.send_command_sync("s")
    }

    pub fn get_registers_sync(&mut self) -> Option<Vec<u8>> {
        self.send_command_sync("g")
    }

    // TODO: 64-bit addresses
    pub fn get_memory_sync(&mut self, address: u32, size: u32) -> Option<Memory> {
        let mem_req = format!("m{:x},{:x}", address, size);

        if let Some(data) = self.send_command_sync(&mem_req) {
            let mut memory = Vec::with_capacity((data.len() - 2) / 2);
            let mut index = 1;

            for _ in 0..((data.len() - 2) / 2) {
                let v0 = data[index + 0];
                let v1 = data[index + 1];
                let v = (Self::from_hex(v0) << 4) | (Self::from_hex(v1));
                memory.push(v);
                index += 2;
            }

            Some(Memory {
                address: address as u64,
                data: memory,
            })
        } else {
            None
        }
    }
}

#[test]
fn test_checksum_calc() {
    let data: [u8; 8] = [32, 32, 32, 32, 64, 64, 64, 64];
    assert_eq!(GdbRemote::calc_checksum(&data), 128);
}

#[test]
fn test_process_string() {
    assert_eq!(GdbRemote::get_processed_string("f"), "$f#66");
}

<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use collections::hashmap::HashMap;
use serialize::{
    Decodable,
    json,
};
use glfw;
use cgmath::vector::{
    Vec3,
    Vec2,
};
use gl_helpers::{
    uniform_mat4f,
    set_clear_color,
    clear_screen,
    init_opengl,
    load_gl_funcs_with,
    set_viewport,
    tr,
};
use camera::Camera;
use map::MapPosIter;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use core::{
    Core,
    Unit,
    CommandEndTurn,
    CommandMove,
    CommandCreateUnit,
    CommandAttackUnit,
    Event,
    EventMove,
    EventEndTurn,
    EventCreateUnit,
    EventAttackUnit,
};
use core_types::{
    Size2,
    Int,
    Bool,
    UnitId,
    PlayerId,
    MapPos,
};
use gl_types::{
    Scene,
    VertexCoord,
    TextureCoord,
    Float,
    Point2,
    MatId,
};
use event_visualizer::{
    EventVisualizer,
    EventMoveVisualizer,
    EventEndTurnVisualizer,
    EventCreateUnitVisualizer,
    EventAttackUnitVisualizer,
};
use game_state::GameState;
use pathfinder::Pathfinder;
use misc::read_file;
use shader::Shader;
use texture::Texture;

fn build_hex_mesh(&geom: &Geom, map_size: Size2<Int>) -> ~[VertexCoord] {
    let mut vertex_data = ~[];
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom.map_pos_to_world_pos(tile_pos);
        for num in range(0 as Int, 6) {
            let vertex = geom.index_to_hex_vertex(num);
            let next_vertex = geom.index_to_hex_vertex(num + 1);
            vertex_data.push(pos + vertex);
            vertex_data.push(pos + next_vertex);
            vertex_data.push(pos + Vec3::zero());
        }
    }
    vertex_data
}

fn build_hex_tex_coord(map_size: Size2<Int>) -> ~[TextureCoord] {
    let mut vertex_data = ~[];
    for _ in MapPosIter::new(map_size) {
        for _ in range(0, 6) {
            vertex_data.push(Vec2{x: 0.0, y: 0.0});
            vertex_data.push(Vec2{x: 1.0, y: 0.0});
            vertex_data.push(Vec2{x: 0.5, y: 0.5});
        }
    }
    vertex_data
}

fn read_win_size(config_path: &str) -> Size2<Int> {
    let path = Path::new(config_path);
    let json = json::from_str(read_file(&path)).unwrap();
    let mut decoder = json::Decoder::new(json);
    let size: Size2<Int> = Decodable::decode(&mut decoder);
    size
}

fn init_win(win_size: Size2<Int>) -> glfw::Window {
    glfw::set_error_callback(~glfw::LogErrorHandler);
    let init_status = glfw::init();
    if !init_status.is_ok() {
        fail!("Failed to initialize GLFW");
    }
    let win = glfw::Window::create(
        win_size.w as u32,
        win_size.h as u32,
        "Marauder",
        glfw::Windowed,
    ).unwrap();
    win.make_context_current();
    win.set_all_polling(true);
    win
}

fn get_scenes(players_count: Int) -> HashMap<PlayerId, Scene> {
    let mut m = HashMap::new();
    for i in range(0, players_count) {
        m.insert(PlayerId(i), HashMap::new());
    }
    m
}

fn get_game_states(players_count: Int) -> HashMap<PlayerId, GameState> {
    let mut m = HashMap::new();
    for i in range(0, players_count) {
        m.insert(PlayerId(i), GameState::new());
    }
    m
}

fn get_pathfinders(
    players_count: Int,
    map_size: Size2<Int>,
) -> HashMap<PlayerId, Pathfinder> {
    let mut m = HashMap::new();
    for i in range(0, players_count) {
        m.insert(PlayerId(i), Pathfinder::new(map_size));
    }
    m
}

fn get_map_mesh(geom: &Geom, map_size: Size2<Int>, shader: &Shader) -> Mesh {
    let tex = Texture::new(~"data/floor.png");
    let mut mesh = Mesh::new(build_hex_mesh(geom, map_size));
    mesh.set_texture(tex, build_hex_tex_coord(map_size));
    mesh.prepare(shader);
    mesh
}

fn load_unit_mesh(shader: &Shader) -> Mesh {
    let tex = Texture::new(~"data/tank.png");
    let obj = obj::Model::new("data/tank.obj");
    let mut mesh = Mesh::new(obj.build());
    mesh.set_texture(tex, obj.build_tex_coord());
    mesh.prepare(shader);
    mesh
}

pub struct Visualizer<'a> {
    shader: Shader,
    map_mesh: Mesh,
    unit_mesh: Mesh,
    mvp_mat_id: MatId,
    win: glfw::Window,
    mouse_pos: Point2<Float>,
    camera: Camera,
    tile_picker: ~TilePicker,
    selected_tile_pos: Option<MapPos>,
    selected_unit_id: Option<UnitId>,
    geom: Geom,
    scenes: HashMap<PlayerId, Scene>,
    core: ~Core<'a>,
    event: Option<Event>,
    event_visualizer: Option<~EventVisualizer>,
    game_state: HashMap<PlayerId, GameState>,
    pathfinders: HashMap<PlayerId, Pathfinder>,
}

impl<'a> Visualizer<'a> {
    pub fn new() -> ~Visualizer {
        let players_count = 2;
        let win_size = read_win_size("config.json");
        let win = init_win(win_size);
        load_gl_funcs_with(glfw::get_proc_address);
        init_opengl();
        let geom = Geom::new();
        let core = Core::new();
        let map_size = core.map_size();
        let tile_picker = TilePicker::new(
            win_size, &geom, core.map_size());
        let shader = Shader::new("normal.vs.glsl", "normal.fs.glsl");
        let mvp_mat_id = MatId(shader.get_uniform("mvp_mat"));
        let vis = ~Visualizer {
            map_mesh: get_map_mesh(&geom, map_size, &shader),
            unit_mesh: load_unit_mesh(&shader),
            mvp_mat_id: mvp_mat_id,
            shader: shader,
            win: win,
            mouse_pos: Vec2::zero(),
            camera: Camera::new(),
            tile_picker: tile_picker,
            selected_tile_pos: None,
            selected_unit_id: None,
            geom: geom,
            core: core,
            event_visualizer: None,
            event: None,
            scenes: get_scenes(players_count),
            game_state: get_game_states(players_count),
            pathfinders: get_pathfinders(players_count, map_size),
        };
        vis
    }

    fn win<'a>(&'a self) -> &'a glfw::Window {
        &self.win
    }

    fn scene<'a>(&'a self) -> &'a Scene {
        self.scenes.get(&self.core.player_id())
    }

    fn unit_at_opt(&'a self, pos: MapPos) -> Option<&'a Unit> {
        let mut res = None;
        let id = self.core.player_id();
        for (_, unit) in self.game_state.get(&id).units.iter() {
            if unit.pos == pos {
                res = Some(unit);
                break;
            }
        }
        res
    }

    fn draw_units(&self) {
        self.shader.activate();
        for (_, unit) in self.scene().iter() {
            let m = tr(self.camera.mat(), unit.pos);
            uniform_mat4f(self.mvp_mat_id, &m);
            self.unit_mesh.draw(&self.shader);
        }
    }

    fn draw_map(&self) {
        uniform_mat4f(self.mvp_mat_id, &self.camera.mat());
        self.map_mesh.draw(&self.shader);
    }

    fn draw(&mut self) {
        set_clear_color(0.3, 0.3, 0.3);
        clear_screen();
        self.shader.activate();
        self.draw_units();
        self.draw_map();
        if !self.event_visualizer.is_none() {
            let scene = self.scenes.get_mut(&self.core.player_id());
            self.event_visualizer.get_mut_ref().draw(&self.geom, scene);
        }
        self.win().swap_buffers();
    }

    pub fn is_running(&self) -> Bool {
        return !self.win().should_close()
    }

    fn handle_key_event(&mut self, key: glfw::Key) {
        match key {
            glfw::KeyEscape | glfw::KeyQ => {
                self.win().set_should_close(true);
            },
            glfw::KeyUp => self.camera.move(270.0),
            glfw::KeyDown => self.camera.move(90.0),
            glfw::KeyRight => self.camera.move(0.0),
            glfw::KeyLeft => self.camera.move(180.0),
            glfw::KeyMinus => self.camera.zoom += 1.0,
            glfw::KeyEqual => self.camera.zoom -= 1.0,
            _ => {},
        }
        if self.event_visualizer.is_some() {
            return;
        }
        match key {
            glfw::KeyT => {
                self.core.do_command(CommandEndTurn);
                self.selected_unit_id = None;
            },
            glfw::KeyU => {
                let pos_opt = self.selected_tile_pos;
                if pos_opt.is_some() {
                    let pos = pos_opt.unwrap();
                    if self.unit_at_opt(pos).is_none() {
                        let cmd = CommandCreateUnit(pos);
                        self.core.do_command(cmd);
                    }
                }
            },
            glfw::KeyA => {
                let pos_opt = self.selected_tile_pos;
                if pos_opt.is_some() {
                    let pos = pos_opt.unwrap();
                    if self.unit_at_opt(pos).is_some() {
                        let defender_id = self.unit_at_opt(pos).unwrap().id;
                        let cmd = CommandAttackUnit(UnitId(0), defender_id);
                        self.core.do_command(cmd);
                    }
                }
            },
            _ => {},
        }
    }

    fn handle_cursor_pos_event(&mut self, pos: Point2<Float>) {
        let button = self.win().get_mouse_button(glfw::MouseButtonRight);
        if button == glfw::Press {
            self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
            self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
        }
        self.mouse_pos = pos;
    }

    fn handle_mouse_button_event(&mut self) {
        if self.event_visualizer.is_some() {
            return;
        }
        if self.selected_tile_pos.is_some() {
            let pos = self.selected_tile_pos.unwrap();
            if self.unit_at_opt(pos).is_some() {
                let unit_id = self.unit_at_opt(pos).unwrap().id;
                let state = self.game_state.get_mut(&self.core.player_id());
                self.selected_unit_id = Some(unit_id);
                let pf = self.pathfinders.get_mut(&self.core.player_id());
                pf.fill_map(state, state.units.get(&unit_id));
            } else if self.selected_unit_id.is_some() {
                let unit_id = self.selected_unit_id.unwrap();
                let pf = self.pathfinders.get_mut(&self.core.player_id());
                let path = pf.get_path(pos);
                self.core.do_command(CommandMove(unit_id, path));
            }
        }
    }

    fn get_events(&mut self) -> ~[glfw::WindowEvent] {
        glfw::poll_events();
        let mut events = ~[];
        for (_, event) in self.win().flush_events() {
            events.push(event);
        }
        events
    }

    fn handle_event(&mut self, event: glfw::WindowEvent) {
        match event {
            glfw::KeyEvent(key, _, glfw::Press, _) => {
                self.handle_key_event(key);
            },
            glfw::CursorPosEvent(x, y) => {
                let p = Vec2{x: x as Float, y: y as Float};
                self.handle_cursor_pos_event(p);
            },
            glfw::MouseButtonEvent(glfw::MouseButtonLeft, glfw::Press, _) => {
                self.handle_mouse_button_event();
            },
            glfw::SizeEvent(w, h) => {
                set_viewport(Size2{w: w, h: h});
                self.tile_picker.set_win_size(Size2{w: w, h: h});
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        for event in self.get_events().iter() {
            self.handle_event(*event);
        }
    }

    fn pick_tile(&mut self) {
        let mouse_pos = Vec2 {
            x: self.mouse_pos.x as Int,
            y: self.mouse_pos.y as Int,
        };
        self.selected_tile_pos =
            self.tile_picker.pick_tile(&self.camera, mouse_pos);
    }

    pub fn make_event_visualizer(&mut self, event: &Event) -> ~EventVisualizer {
        match *event {
            EventMove(ref unit_id, ref path) => {
                EventMoveVisualizer::new(*unit_id, path.clone())
            },
            EventEndTurn(_, _) => {
                EventEndTurnVisualizer::new()
            },
            EventCreateUnit(id, ref pos) => {
                EventCreateUnitVisualizer::new(id, *pos)
            },
            EventAttackUnit(attacker_id, defender_id) => {
                EventAttackUnitVisualizer::new(attacker_id, defender_id)
            },
        }
    }

    pub fn logic(&mut self) {
        if self.event_visualizer.is_none() {
            let event_opt = self.core.get_event();
            if event_opt.is_some() {
                let event = event_opt.unwrap();
                let vis = self.make_event_visualizer(&event);
                self.event = Some(event);
                self.event_visualizer = Some(vis);
            }
        } else if self.event_visualizer.get_ref().is_finished() {
            let scene = self.scenes.get_mut(&self.core.player_id());
            self.event_visualizer.get_mut_ref().end(&self.geom, scene);
            let state = self.game_state.get_mut(&self.core.player_id());
            state.apply_event(self.event.get_ref());
            self.event_visualizer = None;
            self.event = None;
            if self.selected_unit_id.is_some() {
                let unit_id = self.selected_unit_id.unwrap();
                let pf = self.pathfinders.get_mut(&self.core.player_id());
                pf.fill_map(state, state.units.get(&unit_id));
            }
        }
    }

    pub fn tick(&mut self) {
        self.handle_events();
        self.logic();
        self.pick_tile();
        self.draw();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Visualizer: removed unneeded 'pub'<commit_after>// See LICENSE file for copyright and license details.

use collections::hashmap::HashMap;
use serialize::{
    Decodable,
    json,
};
use glfw;
use cgmath::vector::{
    Vec3,
    Vec2,
};
use gl_helpers::{
    uniform_mat4f,
    set_clear_color,
    clear_screen,
    init_opengl,
    load_gl_funcs_with,
    set_viewport,
    tr,
};
use camera::Camera;
use map::MapPosIter;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use core::{
    Core,
    Unit,
    CommandEndTurn,
    CommandMove,
    CommandCreateUnit,
    CommandAttackUnit,
    Event,
    EventMove,
    EventEndTurn,
    EventCreateUnit,
    EventAttackUnit,
};
use core_types::{
    Size2,
    Int,
    Bool,
    UnitId,
    PlayerId,
    MapPos,
};
use gl_types::{
    Scene,
    VertexCoord,
    TextureCoord,
    Float,
    Point2,
    MatId,
};
use event_visualizer::{
    EventVisualizer,
    EventMoveVisualizer,
    EventEndTurnVisualizer,
    EventCreateUnitVisualizer,
    EventAttackUnitVisualizer,
};
use game_state::GameState;
use pathfinder::Pathfinder;
use misc::read_file;
use shader::Shader;
use texture::Texture;

fn build_hex_mesh(&geom: &Geom, map_size: Size2<Int>) -> ~[VertexCoord] {
    let mut vertex_data = ~[];
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom.map_pos_to_world_pos(tile_pos);
        for num in range(0 as Int, 6) {
            let vertex = geom.index_to_hex_vertex(num);
            let next_vertex = geom.index_to_hex_vertex(num + 1);
            vertex_data.push(pos + vertex);
            vertex_data.push(pos + next_vertex);
            vertex_data.push(pos + Vec3::zero());
        }
    }
    vertex_data
}

fn build_hex_tex_coord(map_size: Size2<Int>) -> ~[TextureCoord] {
    let mut vertex_data = ~[];
    for _ in MapPosIter::new(map_size) {
        for _ in range(0, 6) {
            vertex_data.push(Vec2{x: 0.0, y: 0.0});
            vertex_data.push(Vec2{x: 1.0, y: 0.0});
            vertex_data.push(Vec2{x: 0.5, y: 0.5});
        }
    }
    vertex_data
}

fn read_win_size(config_path: &str) -> Size2<Int> {
    let path = Path::new(config_path);
    let json = json::from_str(read_file(&path)).unwrap();
    let mut decoder = json::Decoder::new(json);
    let size: Size2<Int> = Decodable::decode(&mut decoder);
    size
}

fn init_win(win_size: Size2<Int>) -> glfw::Window {
    glfw::set_error_callback(~glfw::LogErrorHandler);
    let init_status = glfw::init();
    if !init_status.is_ok() {
        fail!("Failed to initialize GLFW");
    }
    let win = glfw::Window::create(
        win_size.w as u32,
        win_size.h as u32,
        "Marauder",
        glfw::Windowed,
    ).unwrap();
    win.make_context_current();
    win.set_all_polling(true);
    win
}

fn get_scenes(players_count: Int) -> HashMap<PlayerId, Scene> {
    let mut m = HashMap::new();
    for i in range(0, players_count) {
        m.insert(PlayerId(i), HashMap::new());
    }
    m
}

fn get_game_states(players_count: Int) -> HashMap<PlayerId, GameState> {
    let mut m = HashMap::new();
    for i in range(0, players_count) {
        m.insert(PlayerId(i), GameState::new());
    }
    m
}

fn get_pathfinders(
    players_count: Int,
    map_size: Size2<Int>,
) -> HashMap<PlayerId, Pathfinder> {
    let mut m = HashMap::new();
    for i in range(0, players_count) {
        m.insert(PlayerId(i), Pathfinder::new(map_size));
    }
    m
}

fn get_map_mesh(geom: &Geom, map_size: Size2<Int>, shader: &Shader) -> Mesh {
    let tex = Texture::new(~"data/floor.png");
    let mut mesh = Mesh::new(build_hex_mesh(geom, map_size));
    mesh.set_texture(tex, build_hex_tex_coord(map_size));
    mesh.prepare(shader);
    mesh
}

fn load_unit_mesh(shader: &Shader) -> Mesh {
    let tex = Texture::new(~"data/tank.png");
    let obj = obj::Model::new("data/tank.obj");
    let mut mesh = Mesh::new(obj.build());
    mesh.set_texture(tex, obj.build_tex_coord());
    mesh.prepare(shader);
    mesh
}

pub struct Visualizer<'a> {
    shader: Shader,
    map_mesh: Mesh,
    unit_mesh: Mesh,
    mvp_mat_id: MatId,
    win: glfw::Window,
    mouse_pos: Point2<Float>,
    camera: Camera,
    tile_picker: ~TilePicker,
    selected_tile_pos: Option<MapPos>,
    selected_unit_id: Option<UnitId>,
    geom: Geom,
    scenes: HashMap<PlayerId, Scene>,
    core: ~Core<'a>,
    event: Option<Event>,
    event_visualizer: Option<~EventVisualizer>,
    game_state: HashMap<PlayerId, GameState>,
    pathfinders: HashMap<PlayerId, Pathfinder>,
}

impl<'a> Visualizer<'a> {
    pub fn new() -> ~Visualizer {
        let players_count = 2;
        let win_size = read_win_size("config.json");
        let win = init_win(win_size);
        load_gl_funcs_with(glfw::get_proc_address);
        init_opengl();
        let geom = Geom::new();
        let core = Core::new();
        let map_size = core.map_size();
        let tile_picker = TilePicker::new(
            win_size, &geom, core.map_size());
        let shader = Shader::new("normal.vs.glsl", "normal.fs.glsl");
        let mvp_mat_id = MatId(shader.get_uniform("mvp_mat"));
        let vis = ~Visualizer {
            map_mesh: get_map_mesh(&geom, map_size, &shader),
            unit_mesh: load_unit_mesh(&shader),
            mvp_mat_id: mvp_mat_id,
            shader: shader,
            win: win,
            mouse_pos: Vec2::zero(),
            camera: Camera::new(),
            tile_picker: tile_picker,
            selected_tile_pos: None,
            selected_unit_id: None,
            geom: geom,
            core: core,
            event_visualizer: None,
            event: None,
            scenes: get_scenes(players_count),
            game_state: get_game_states(players_count),
            pathfinders: get_pathfinders(players_count, map_size),
        };
        vis
    }

    fn win<'a>(&'a self) -> &'a glfw::Window {
        &self.win
    }

    fn scene<'a>(&'a self) -> &'a Scene {
        self.scenes.get(&self.core.player_id())
    }

    fn unit_at_opt(&'a self, pos: MapPos) -> Option<&'a Unit> {
        let mut res = None;
        let id = self.core.player_id();
        for (_, unit) in self.game_state.get(&id).units.iter() {
            if unit.pos == pos {
                res = Some(unit);
                break;
            }
        }
        res
    }

    fn draw_units(&self) {
        self.shader.activate();
        for (_, unit) in self.scene().iter() {
            let m = tr(self.camera.mat(), unit.pos);
            uniform_mat4f(self.mvp_mat_id, &m);
            self.unit_mesh.draw(&self.shader);
        }
    }

    fn draw_map(&self) {
        uniform_mat4f(self.mvp_mat_id, &self.camera.mat());
        self.map_mesh.draw(&self.shader);
    }

    fn draw(&mut self) {
        set_clear_color(0.3, 0.3, 0.3);
        clear_screen();
        self.shader.activate();
        self.draw_units();
        self.draw_map();
        if !self.event_visualizer.is_none() {
            let scene = self.scenes.get_mut(&self.core.player_id());
            self.event_visualizer.get_mut_ref().draw(&self.geom, scene);
        }
        self.win().swap_buffers();
    }

    pub fn is_running(&self) -> Bool {
        return !self.win().should_close()
    }

    fn handle_key_event(&mut self, key: glfw::Key) {
        match key {
            glfw::KeyEscape | glfw::KeyQ => {
                self.win().set_should_close(true);
            },
            glfw::KeyUp => self.camera.move(270.0),
            glfw::KeyDown => self.camera.move(90.0),
            glfw::KeyRight => self.camera.move(0.0),
            glfw::KeyLeft => self.camera.move(180.0),
            glfw::KeyMinus => self.camera.zoom += 1.0,
            glfw::KeyEqual => self.camera.zoom -= 1.0,
            _ => {},
        }
        if self.event_visualizer.is_some() {
            return;
        }
        match key {
            glfw::KeyT => {
                self.core.do_command(CommandEndTurn);
                self.selected_unit_id = None;
            },
            glfw::KeyU => {
                let pos_opt = self.selected_tile_pos;
                if pos_opt.is_some() {
                    let pos = pos_opt.unwrap();
                    if self.unit_at_opt(pos).is_none() {
                        let cmd = CommandCreateUnit(pos);
                        self.core.do_command(cmd);
                    }
                }
            },
            glfw::KeyA => {
                let pos_opt = self.selected_tile_pos;
                if pos_opt.is_some() {
                    let pos = pos_opt.unwrap();
                    if self.unit_at_opt(pos).is_some() {
                        let defender_id = self.unit_at_opt(pos).unwrap().id;
                        let cmd = CommandAttackUnit(UnitId(0), defender_id);
                        self.core.do_command(cmd);
                    }
                }
            },
            _ => {},
        }
    }

    fn handle_cursor_pos_event(&mut self, pos: Point2<Float>) {
        let button = self.win().get_mouse_button(glfw::MouseButtonRight);
        if button == glfw::Press {
            self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
            self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
        }
        self.mouse_pos = pos;
    }

    fn handle_mouse_button_event(&mut self) {
        if self.event_visualizer.is_some() {
            return;
        }
        if self.selected_tile_pos.is_some() {
            let pos = self.selected_tile_pos.unwrap();
            if self.unit_at_opt(pos).is_some() {
                let unit_id = self.unit_at_opt(pos).unwrap().id;
                let state = self.game_state.get_mut(&self.core.player_id());
                self.selected_unit_id = Some(unit_id);
                let pf = self.pathfinders.get_mut(&self.core.player_id());
                pf.fill_map(state, state.units.get(&unit_id));
            } else if self.selected_unit_id.is_some() {
                let unit_id = self.selected_unit_id.unwrap();
                let pf = self.pathfinders.get_mut(&self.core.player_id());
                let path = pf.get_path(pos);
                self.core.do_command(CommandMove(unit_id, path));
            }
        }
    }

    fn get_events(&mut self) -> ~[glfw::WindowEvent] {
        glfw::poll_events();
        let mut events = ~[];
        for (_, event) in self.win().flush_events() {
            events.push(event);
        }
        events
    }

    fn handle_event(&mut self, event: glfw::WindowEvent) {
        match event {
            glfw::KeyEvent(key, _, glfw::Press, _) => {
                self.handle_key_event(key);
            },
            glfw::CursorPosEvent(x, y) => {
                let p = Vec2{x: x as Float, y: y as Float};
                self.handle_cursor_pos_event(p);
            },
            glfw::MouseButtonEvent(glfw::MouseButtonLeft, glfw::Press, _) => {
                self.handle_mouse_button_event();
            },
            glfw::SizeEvent(w, h) => {
                set_viewport(Size2{w: w, h: h});
                self.tile_picker.set_win_size(Size2{w: w, h: h});
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        for event in self.get_events().iter() {
            self.handle_event(*event);
        }
    }

    fn pick_tile(&mut self) {
        let mouse_pos = Vec2 {
            x: self.mouse_pos.x as Int,
            y: self.mouse_pos.y as Int,
        };
        self.selected_tile_pos =
            self.tile_picker.pick_tile(&self.camera, mouse_pos);
    }

    fn make_event_visualizer(&mut self, event: &Event) -> ~EventVisualizer {
        match *event {
            EventMove(ref unit_id, ref path) => {
                EventMoveVisualizer::new(*unit_id, path.clone())
            },
            EventEndTurn(_, _) => {
                EventEndTurnVisualizer::new()
            },
            EventCreateUnit(id, ref pos) => {
                EventCreateUnitVisualizer::new(id, *pos)
            },
            EventAttackUnit(attacker_id, defender_id) => {
                EventAttackUnitVisualizer::new(attacker_id, defender_id)
            },
        }
    }

    fn logic(&mut self) {
        if self.event_visualizer.is_none() {
            let event_opt = self.core.get_event();
            if event_opt.is_some() {
                let event = event_opt.unwrap();
                let vis = self.make_event_visualizer(&event);
                self.event = Some(event);
                self.event_visualizer = Some(vis);
            }
        } else if self.event_visualizer.get_ref().is_finished() {
            let scene = self.scenes.get_mut(&self.core.player_id());
            self.event_visualizer.get_mut_ref().end(&self.geom, scene);
            let state = self.game_state.get_mut(&self.core.player_id());
            state.apply_event(self.event.get_ref());
            self.event_visualizer = None;
            self.event = None;
            if self.selected_unit_id.is_some() {
                let unit_id = self.selected_unit_id.unwrap();
                let pf = self.pathfinders.get_mut(&self.core.player_id());
                pf.fill_map(state, state.units.get(&unit_id));
            }
        }
    }

    pub fn tick(&mut self) {
        self.handle_events();
        self.logic();
        self.pick_tile();
        self.draw();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

extern crate pest;
extern crate pest_meta;

use pest::{Atomicity, Error, ParseResult, ParserState};
use pest::iterators::Pairs;
use pest_meta::ast::{Expr, Rule, RuleType};
use std::char;
use std::collections::HashMap;

mod macros;

pub struct Vm {
    rules: HashMap<String, Rule>
}

impl Vm {
    pub fn new(rules: Vec<Rule>) -> Vm {
        let rules = rules.into_iter().map(|r| (r.name.clone(), r)).collect();
        Vm { rules }
    }

    pub fn parse<'a, 'i>(
        &'a self,
        rule: &'a str,
        input: &'i str
    ) -> Result<Pairs<'i, &str>, Error<'i, &str>> {
        pest::state(input, |state| self.parse_rule(rule, state))
    }

    fn parse_rule<'a, 'i>(
        &'a self,
        rule: &'a str,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        match rule {
            "any" => return state.skip(1),
            "eoi" => return state.rule("eoi", |state| state.end_of_input()),
            "soi" => return state.start_of_input(),
            "peek" => return state.stack_peek(),
            "pop" => return state.stack_pop(),
            "drop" => return state.stack_drop(),
            _ => ()
        };

        if let Some(rule) = self.rules.get(rule) {
            if &rule.name == "whitespace" || &rule.name == "comment" {
                match rule.ty {
                    RuleType::Normal => state.rule(&rule.name, |state| {
                        state.atomic(Atomicity::Atomic, |state| {
                            self.parse_expr(&rule.expr, state)
                        })
                    }),
                    RuleType::Silent => state.atomic(Atomicity::Atomic, |state| {
                        self.parse_expr(&rule.expr, state)
                    }),
                    RuleType::Atomic => state.rule(&rule.name, |state| {
                        state.atomic(Atomicity::Atomic, |state| {
                            self.parse_expr(&rule.expr, state)
                        })
                    }),
                    RuleType::CompoundAtomic => state.atomic(Atomicity::CompoundAtomic, |state| {
                        state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                    }),
                    RuleType::NonAtomic => state.atomic(Atomicity::Atomic, |state| {
                        state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                    })
                }
            } else {
                match rule.ty {
                    RuleType::Normal => {
                        state.rule(&rule.name, move |state| self.parse_expr(&rule.expr, state))
                    }
                    RuleType::Silent => self.parse_expr(&rule.expr, state),
                    RuleType::Atomic => state.rule(&rule.name, move |state| {
                        state.atomic(Atomicity::Atomic, move |state| {
                            self.parse_expr(&rule.expr, state)
                        })
                    }),
                    RuleType::CompoundAtomic => {
                        state.atomic(Atomicity::CompoundAtomic, move |state| {
                            state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                        })
                    }
                    RuleType::NonAtomic => state.atomic(Atomicity::NonAtomic, move |state| {
                        state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                    })
                }
            }
        } else {
            panic!("undefined rule {}", rule);
        }
    }

    fn parse_expr<'a, 'i>(
        &'a self,
        expr: &'a Expr,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        match *expr {
            Expr::Str(ref string) => {
                state.match_string(&unescape(string).expect("incorrect string literal"))
            }
            Expr::Insens(ref string) => {
                state.match_insensitive(&unescape(string).expect("incorrect string literal"))
            }
            Expr::Range(ref start, ref end) => {
                let start = unescape(start)
                    .expect("incorrect char literal")
                    .chars()
                    .next()
                    .expect("empty char literal");
                let end = unescape(end)
                    .expect("incorrect char literal")
                    .chars()
                    .next()
                    .expect("empty char literal");

                state.match_range(start..end)
            }
            Expr::Ident(ref name) => self.parse_rule(name, state),
            Expr::PosPred(ref expr) => {
                state.lookahead(true, |state| self.parse_expr(&*expr, state))
            }
            Expr::NegPred(ref expr) => {
                state.lookahead(false, |state| self.parse_expr(&*expr, state))
            }
            Expr::Seq(ref lhs, ref rhs) => state.sequence(|state| {
                self.parse_expr(&*lhs, state)
                    .and_then(|state| self.skip(state))
                    .and_then(|state| self.parse_expr(&*rhs, state))
            }),
            Expr::Choice(ref lhs, ref rhs) => self.parse_expr(&*lhs, state)
                .or_else(|state| self.parse_expr(&*rhs, state)),
            Expr::Opt(ref expr) => state.optional(|state| self.parse_expr(&*expr, state)),
            Expr::Rep(ref expr) => self.repeat(expr, None, None, state),
            Expr::RepOnce(ref expr) => self.repeat(expr, Some(1), None, state),
            Expr::RepExact(ref expr, num) => self.repeat(expr, Some(num), Some(num), state),
            Expr::RepMin(ref expr, min) => self.repeat(expr, Some(min), None, state),
            Expr::RepMax(ref expr, max) => self.repeat(expr, None, Some(max), state),
            Expr::RepMinMax(ref expr, min, max) => self.repeat(expr, Some(min), Some(max), state),
            Expr::Push(ref expr) => state.stack_push(|state| self.parse_expr(&*expr, state)),
            Expr::Skip(ref strings) => {
                state.skip_until_any(&strings.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
            }
        }
    }

    fn repeat<'a, 'i>(
        &'a self,
        expr: &'a Expr,
        min: Option<u32>,
        max: Option<u32>,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        state.sequence(|state| {
            let mut result = match min {
                Some(min) if min > 0 => {
                    let mut result = self.parse_expr(&*expr, state);

                    for _ in 2..min + 1 {
                        result = result.and_then(|state| {
                            self.skip(state)
                                .and_then(|state| self.parse_expr(&*expr, state))
                        });
                    }

                    result
                }
                _ => state.optional(|state| self.parse_expr(&*expr, state))
            };

            let mut times = 1;

            loop {
                if let Some(max) = max {
                    if times >= max {
                        return result;
                    }
                }

                let initial_result_is_err = result.is_err();

                let current = result.and_then(|state| {
                    state.lookahead(true, |state| {
                        self.skip(state).and_then(|state| self.parse_expr(&*expr, state))
                    })
                });
                times += 1;

                if current.is_err() {
                    if initial_result_is_err {
                        return Err(current.unwrap_err());
                    } else {
                        return Ok(current.unwrap_err());
                    }
                }

                result = self.skip(current.unwrap()).and_then(|state|
                    self.parse_expr(&*expr, state)
                );
            }
        })
    }

    fn skip<'a, 'i>(
        &'a self,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        match (
            self.rules.contains_key("whitespace"),
            self.rules.contains_key("comment")
        ) {
            (false, false) => Ok(state),
            (true, false) => if state.atomicity() == Atomicity::NonAtomic {
                state.repeat(|state| self.parse_rule("whitespace", state))
            } else {
                Ok(state)
            },
            (false, true) => if state.atomicity() == Atomicity::NonAtomic {
                state.repeat(|state| self.parse_rule("comment", state))
            } else {
                Ok(state)
            },
            (true, true) => if state.atomicity() == Atomicity::NonAtomic {
                state.sequence(|state| {
                    state
                        .repeat(|state| self.parse_rule("whitespace", state))
                        .and_then(|state| {
                            state.repeat(|state| {
                                state.sequence(|state| {
                                    self.parse_rule("comment", state).and_then(|state| {
                                        state.repeat(|state| self.parse_rule("whitespace", state))
                                    })
                                })
                            })
                        })
                })
            } else {
                Ok(state)
            }
        }
    }
}

fn unescape(string: &str) -> Option<String> {
    let mut result = String::new();
    let mut chars = string.chars();

    loop {
        match chars.next() {
            Some('\\') => match chars.next()? {
                '"' => result.push('"'),
                '\\' => result.push('\\'),
                'r' => result.push('\r'),
                'n' => result.push('\n'),
                't' => result.push('\t'),
                '0' => result.push('\0'),
                '\'' => result.push('\''),
                'x' => {
                    let string: String = chars.clone().take(2).collect();

                    if string.len() != 2 {
                        return None;
                    }

                    for _ in 0..string.len() {
                        chars.next()?;
                    }

                    let value = u8::from_str_radix(&string, 16).ok()?;

                    result.push(char::from(value));
                }
                'u' => {
                    if chars.next()? != '{' {
                        return None;
                    }

                    let string: String = chars.clone().take_while(|c| *c != '}').collect();

                    if string.len() < 2 || 6 < string.len() {
                        return None;
                    }

                    for _ in 0..string.len() + 1 {
                        chars.next()?;
                    }

                    let value = u32::from_str_radix(&string, 16).ok()?;

                    result.push(char::from_u32(value)?);
                }
                _ => return None
            },
            Some(c) => result.push(c),
            None => return Some(result)
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn unescape_all() {
        let string = r"a\nb\x55c\u{111}d";

        assert_eq!(unescape(string), Some("a\nb\x55c\u{111}d".to_owned()));
    }

    #[test]
    fn unescape_empty_escape() {
        let string = r"\";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_wrong_escape() {
        let string = r"\w";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_wrong_byte() {
        let string = r"\xfg";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_short_byte() {
        let string = r"\xf";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_no_open_brace_unicode() {
        let string = r"\u11";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_no_close_brace_unicode() {
        let string = r"\u{11";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_short_unicode() {
        let string = r"\u{1}";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_long_unicode() {
        let string = r"\u{1111111}";

        assert_eq!(unescape(string), None);
    }
}
<commit_msg>ran a cargo fmt<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

extern crate pest;
extern crate pest_meta;

use pest::{Atomicity, Error, ParseResult, ParserState};
use pest::iterators::Pairs;
use pest_meta::ast::{Expr, Rule, RuleType};
use std::char;
use std::collections::HashMap;

mod macros;

pub struct Vm {
    rules: HashMap<String, Rule>
}

impl Vm {
    pub fn new(rules: Vec<Rule>) -> Vm {
        let rules = rules.into_iter().map(|r| (r.name.clone(), r)).collect();
        Vm { rules }
    }

    pub fn parse<'a, 'i>(
        &'a self,
        rule: &'a str,
        input: &'i str
    ) -> Result<Pairs<'i, &str>, Error<'i, &str>> {
        pest::state(input, |state| self.parse_rule(rule, state))
    }

    fn parse_rule<'a, 'i>(
        &'a self,
        rule: &'a str,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        match rule {
            "any" => return state.skip(1),
            "eoi" => return state.rule("eoi", |state| state.end_of_input()),
            "soi" => return state.start_of_input(),
            "peek" => return state.stack_peek(),
            "pop" => return state.stack_pop(),
            "drop" => return state.stack_drop(),
            _ => ()
        };

        if let Some(rule) = self.rules.get(rule) {
            if &rule.name == "whitespace" || &rule.name == "comment" {
                match rule.ty {
                    RuleType::Normal => state.rule(&rule.name, |state| {
                        state.atomic(Atomicity::Atomic, |state| {
                            self.parse_expr(&rule.expr, state)
                        })
                    }),
                    RuleType::Silent => state.atomic(Atomicity::Atomic, |state| {
                        self.parse_expr(&rule.expr, state)
                    }),
                    RuleType::Atomic => state.rule(&rule.name, |state| {
                        state.atomic(Atomicity::Atomic, |state| {
                            self.parse_expr(&rule.expr, state)
                        })
                    }),
                    RuleType::CompoundAtomic => state.atomic(Atomicity::CompoundAtomic, |state| {
                        state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                    }),
                    RuleType::NonAtomic => state.atomic(Atomicity::Atomic, |state| {
                        state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                    })
                }
            } else {
                match rule.ty {
                    RuleType::Normal => {
                        state.rule(&rule.name, move |state| self.parse_expr(&rule.expr, state))
                    }
                    RuleType::Silent => self.parse_expr(&rule.expr, state),
                    RuleType::Atomic => state.rule(&rule.name, move |state| {
                        state.atomic(Atomicity::Atomic, move |state| {
                            self.parse_expr(&rule.expr, state)
                        })
                    }),
                    RuleType::CompoundAtomic => {
                        state.atomic(Atomicity::CompoundAtomic, move |state| {
                            state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                        })
                    }
                    RuleType::NonAtomic => state.atomic(Atomicity::NonAtomic, move |state| {
                        state.rule(&rule.name, |state| self.parse_expr(&rule.expr, state))
                    })
                }
            }
        } else {
            panic!("undefined rule {}", rule);
        }
    }

    fn parse_expr<'a, 'i>(
        &'a self,
        expr: &'a Expr,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        match *expr {
            Expr::Str(ref string) => {
                state.match_string(&unescape(string).expect("incorrect string literal"))
            }
            Expr::Insens(ref string) => {
                state.match_insensitive(&unescape(string).expect("incorrect string literal"))
            }
            Expr::Range(ref start, ref end) => {
                let start = unescape(start)
                    .expect("incorrect char literal")
                    .chars()
                    .next()
                    .expect("empty char literal");
                let end = unescape(end)
                    .expect("incorrect char literal")
                    .chars()
                    .next()
                    .expect("empty char literal");

                state.match_range(start..end)
            }
            Expr::Ident(ref name) => self.parse_rule(name, state),
            Expr::PosPred(ref expr) => {
                state.lookahead(true, |state| self.parse_expr(&*expr, state))
            }
            Expr::NegPred(ref expr) => {
                state.lookahead(false, |state| self.parse_expr(&*expr, state))
            }
            Expr::Seq(ref lhs, ref rhs) => state.sequence(|state| {
                self.parse_expr(&*lhs, state)
                    .and_then(|state| self.skip(state))
                    .and_then(|state| self.parse_expr(&*rhs, state))
            }),
            Expr::Choice(ref lhs, ref rhs) => self.parse_expr(&*lhs, state)
                .or_else(|state| self.parse_expr(&*rhs, state)),
            Expr::Opt(ref expr) => state.optional(|state| self.parse_expr(&*expr, state)),
            Expr::Rep(ref expr) => self.repeat(expr, None, None, state),
            Expr::RepOnce(ref expr) => self.repeat(expr, Some(1), None, state),
            Expr::RepExact(ref expr, num) => self.repeat(expr, Some(num), Some(num), state),
            Expr::RepMin(ref expr, min) => self.repeat(expr, Some(min), None, state),
            Expr::RepMax(ref expr, max) => self.repeat(expr, None, Some(max), state),
            Expr::RepMinMax(ref expr, min, max) => self.repeat(expr, Some(min), Some(max), state),
            Expr::Push(ref expr) => state.stack_push(|state| self.parse_expr(&*expr, state)),
            Expr::Skip(ref strings) => {
                state.skip_until_any(&strings.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
            }
        }
    }

    fn repeat<'a, 'i>(
        &'a self,
        expr: &'a Expr,
        min: Option<u32>,
        max: Option<u32>,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        state.sequence(|state| {
            let mut result = match min {
                Some(min) if min > 0 => {
                    let mut result = self.parse_expr(&*expr, state);

                    for _ in 2..min + 1 {
                        result = result.and_then(|state| {
                            self.skip(state)
                                .and_then(|state| self.parse_expr(&*expr, state))
                        });
                    }

                    result
                }
                _ => state.optional(|state| self.parse_expr(&*expr, state))
            };

            let mut times = 1;

            loop {
                if let Some(max) = max {
                    if times >= max {
                        return result;
                    }
                }

                let initial_result_is_err = result.is_err();

                let current = result.and_then(|state| {
                    state.lookahead(true, |state| {
                        self.skip(state)
                            .and_then(|state| self.parse_expr(&*expr, state))
                    })
                });
                times += 1;

                if current.is_err() {
                    if initial_result_is_err {
                        return Err(current.unwrap_err());
                    } else {
                        return Ok(current.unwrap_err());
                    }
                }

                result = self.skip(current.unwrap())
                    .and_then(|state| self.parse_expr(&*expr, state));
            }
        })
    }

    fn skip<'a, 'i>(
        &'a self,
        state: Box<ParserState<'i, &'a str>>
    ) -> ParseResult<Box<ParserState<'i, &'a str>>> {
        match (
            self.rules.contains_key("whitespace"),
            self.rules.contains_key("comment")
        ) {
            (false, false) => Ok(state),
            (true, false) => if state.atomicity() == Atomicity::NonAtomic {
                state.repeat(|state| self.parse_rule("whitespace", state))
            } else {
                Ok(state)
            },
            (false, true) => if state.atomicity() == Atomicity::NonAtomic {
                state.repeat(|state| self.parse_rule("comment", state))
            } else {
                Ok(state)
            },
            (true, true) => if state.atomicity() == Atomicity::NonAtomic {
                state.sequence(|state| {
                    state
                        .repeat(|state| self.parse_rule("whitespace", state))
                        .and_then(|state| {
                            state.repeat(|state| {
                                state.sequence(|state| {
                                    self.parse_rule("comment", state).and_then(|state| {
                                        state.repeat(|state| self.parse_rule("whitespace", state))
                                    })
                                })
                            })
                        })
                })
            } else {
                Ok(state)
            }
        }
    }
}

fn unescape(string: &str) -> Option<String> {
    let mut result = String::new();
    let mut chars = string.chars();

    loop {
        match chars.next() {
            Some('\\') => match chars.next()? {
                '"' => result.push('"'),
                '\\' => result.push('\\'),
                'r' => result.push('\r'),
                'n' => result.push('\n'),
                't' => result.push('\t'),
                '0' => result.push('\0'),
                '\'' => result.push('\''),
                'x' => {
                    let string: String = chars.clone().take(2).collect();

                    if string.len() != 2 {
                        return None;
                    }

                    for _ in 0..string.len() {
                        chars.next()?;
                    }

                    let value = u8::from_str_radix(&string, 16).ok()?;

                    result.push(char::from(value));
                }
                'u' => {
                    if chars.next()? != '{' {
                        return None;
                    }

                    let string: String = chars.clone().take_while(|c| *c != '}').collect();

                    if string.len() < 2 || 6 < string.len() {
                        return None;
                    }

                    for _ in 0..string.len() + 1 {
                        chars.next()?;
                    }

                    let value = u32::from_str_radix(&string, 16).ok()?;

                    result.push(char::from_u32(value)?);
                }
                _ => return None
            },
            Some(c) => result.push(c),
            None => return Some(result)
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn unescape_all() {
        let string = r"a\nb\x55c\u{111}d";

        assert_eq!(unescape(string), Some("a\nb\x55c\u{111}d".to_owned()));
    }

    #[test]
    fn unescape_empty_escape() {
        let string = r"\";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_wrong_escape() {
        let string = r"\w";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_wrong_byte() {
        let string = r"\xfg";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_short_byte() {
        let string = r"\xf";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_no_open_brace_unicode() {
        let string = r"\u11";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_no_close_brace_unicode() {
        let string = r"\u{11";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_short_unicode() {
        let string = r"\u{1}";

        assert_eq!(unescape(string), None);
    }

    #[test]
    fn unescape_long_unicode() {
        let string = r"\u{1111111}";

        assert_eq!(unescape(string), None);
    }
}
<|endoftext|>