<commit_before>use consts::constant;
use rustc::lint::*;
use rustc_front::hir::*;
use syntax::ptr::P;

/// Type used to check whether two ast are the same. This is different from the operator
/// `==` on ast types as this operator would compare true equality with ID and span.
///
/// Note that some expressions kinds are not considered but could be added.
pub struct SpanlessEq<'a, 'tcx: 'a> {
    /// Context used to evaluate constant expressions.
    cx: &'a LateContext<'a, 'tcx>,
    /// If is true, never consider as equal expressions containing fonction calls.
    ignore_fn: bool,
}

impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
    pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        SpanlessEq { cx: cx, ignore_fn: false }
    }

    pub fn ignore_fn(self) -> Self {
        SpanlessEq { cx: self.cx, ignore_fn: true }
    }

    /// Check whether two statements are the same.
    pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool {
        match (&left.node, &right.node) {
            (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => {
                if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) {
                    // TODO: tys
                    l.ty.is_none() && r.ty.is_none() &&
                        both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                }
                else {
                    false
                }
            }
            (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => self.eq_expr(l, r),
            (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r),
            _ => false,
        }
    }

    /// Check whether two blocks are the same.
    pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
        over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
            both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
    }

    // ok, it’s a big function, but mostly one big match with simples cases
    #[allow(cyclomatic_complexity)]
    pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
        if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) {
            if l == r {
                return true;
            }
        }

        match (&left.node, &right.node) {
            (&ExprAddrOf(ref lmut, ref le), &ExprAddrOf(ref rmut, ref re)) => {
                lmut == rmut && self.eq_expr(le, re)
            }
            (&ExprAgain(li), &ExprAgain(ri)) => {
                both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str())
            }
            (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => {
                self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
            }
            (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
                lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
            }
            (&ExprBlock(ref l), &ExprBlock(ref r)) => {
                self.eq_block(l, r)
            }
            (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => {
                lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
            }
            (&ExprBreak(li), &ExprBreak(ri)) => {
                both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str())
            }
            (&ExprBox(ref l), &ExprBox(ref r)) => {
                self.eq_expr(l, r)
            }
            (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => {
                !self.ignore_fn &&
                    self.eq_expr(lfun, rfun) &&
                    self.eq_exprs(largs, rargs)
            }
            (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => {
                self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
            }
            (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => {
                lfident.node == rfident.node && self.eq_expr(lfexp, rfexp)
            }
            (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => {
                self.eq_expr(la, ra) && self.eq_expr(li, ri)
            }
            (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => {
                self.eq_expr(lc, rc) &&
                    self.eq_block(lt, rt) &&
                    both(le, re, |l, r| self.eq_expr(l, r))
            }
            (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
            (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
                ls == rs &&
                    self.eq_expr(le, re) &&
                    over(la, ra, |l, r| {
                        self.eq_expr(&l.body, &r.body) &&
                            both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
                            over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
                    })
            }
            (&ExprMethodCall(ref lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => {
                // TODO: tys
                !self.ignore_fn &&
                    lname.node == rname.node &&
                    ltys.is_empty() &&
                    rtys.is_empty() &&
                    self.eq_exprs(largs, rargs)
            }
            (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => {
                both(lb, rb, |l, r| self.eq_expr(l, r)) &&
                both(le, re, |l, r| self.eq_expr(l, r))
            }
            (&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => {
                self.eq_expr(le, re) && self.eq_expr(ll, rl)
            }
            (&ExprRet(ref l), &ExprRet(ref r)) => {
                both(l, r, |l, r| self.eq_expr(l, r))
            }
            (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => {
                both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath)
            }
            (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup),
            (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => {
                li.node == ri.node && self.eq_expr(le, re)
            }
            (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => {
                lop == rop && self.eq_expr(le, re)
            }
            (&ExprVec(ref l), &ExprVec(ref r)) => self.eq_exprs(l, r),
            (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => {
                self.eq_expr(lc, rc) &&
                    self.eq_block(lb, rb) &&
                    both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
            }
            _ => false,
        }
    }

    fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool {
        over(left, right, |l, r| self.eq_expr(l, r))
    }

    /// Check whether two patterns are the same.
    pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool {
        match (&left.node, &right.node) {
            (&PatBox(ref l), &PatBox(ref r)) => {
                self.eq_pat(l, r)
            }
            (&PatEnum(ref lp, ref la), &PatEnum(ref rp, ref ra)) => {
                self.eq_path(lp, rp) &&
                    both(la, ra, |l, r| {
                        over(l, r, |l, r| self.eq_pat(l, r))
                    })
            }
            (&PatIdent(ref lb, ref li, ref lp), &PatIdent(ref rb, ref ri, ref rp)) => {
                lb == rb && li.node.name.as_str() == ri.node.name.as_str() &&
                    both(lp, rp, |l, r| self.eq_pat(l, r))
            }
            (&PatLit(ref l), &PatLit(ref r)) => {
                self.eq_expr(l, r)
            }
            (&PatQPath(ref ls, ref lp), &PatQPath(ref rs, ref rp)) => {
                self.eq_qself(ls, rs) && self.eq_path(lp, rp)
            }
            (&PatTup(ref l), &PatTup(ref r)) => {
                over(l, r, |l, r| self.eq_pat(l, r))
            }
            (&PatRange(ref ls, ref le), &PatRange(ref rs, ref re)) => {
                self.eq_expr(ls, rs) &&
                    self.eq_expr(le, re)
            }
            (&PatRegion(ref le, ref lm), &PatRegion(ref re, ref rm)) => {
                lm == rm && self.eq_pat(le, re)
            }
            (&PatVec(ref ls, ref li, ref le), &PatVec(ref rs, ref ri, ref re)) => {
                over(ls, rs, |l, r| self.eq_pat(l, r)) &&
                    over(le, re, |l, r| self.eq_pat(l, r)) &&
                    both(li, ri, |l, r| self.eq_pat(l, r))
            }
            (&PatWild, &PatWild) => true,
            _ => false,
        }
    }

    fn eq_path(&self, left: &Path, right: &Path) -> bool {
        // The == of idents doesn't work with different contexts,
        // we have to be explicit about hygiene
        left.global == right.global &&
        over(&left.segments,
             &right.segments,
             |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters)
    }

    fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool {
        left.ty.node == right.ty.node && left.position == right.position
    }

    fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
        match (&left.node, &right.node) {
            (&TyVec(ref lvec), &TyVec(ref rvec)) => self.eq_ty(lvec, rvec),
            (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && self.eq_ty(&*lmut.ty, &*rmut.ty),
            (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => {
                lrmut.mutbl == rrmut.mutbl && self.eq_ty(&*lrmut.ty, &*rrmut.ty)
            }
            (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => {
                both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(lpath, rpath)
            }
            (&TyInfer, &TyInfer) => true,
            _ => false,
        }
    }
}

/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`.
fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
    where F: FnMut(&X, &X) -> bool
{
    l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
}

/// Check if two slices are equal as per `eq_fn`.
fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
    where F: FnMut(&X, &X) -> bool
{
    left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
}
<commit_msg>Add missing ExprLoop to SpanlessEq<commit_after>use consts::constant;
use rustc::lint::*;
use rustc_front::hir::*;
use syntax::ptr::P;

/// Type used to check whether two ast are the same. This is different from the operator
/// `==` on ast types as this operator would compare true equality with ID and span.
///
/// Note that some expressions kinds are not considered but could be added.
pub struct SpanlessEq<'a, 'tcx: 'a> {
    /// Context used to evaluate constant expressions.
    cx: &'a LateContext<'a, 'tcx>,
    /// If is true, never consider as equal expressions containing fonction calls.
    ignore_fn: bool,
}

impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
    pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        SpanlessEq { cx: cx, ignore_fn: false }
    }

    pub fn ignore_fn(self) -> Self {
        SpanlessEq { cx: self.cx, ignore_fn: true }
    }

    /// Check whether two statements are the same.
    pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool {
        match (&left.node, &right.node) {
            (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => {
                if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) {
                    // TODO: tys
                    l.ty.is_none() && r.ty.is_none() &&
                        both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                }
                else {
                    false
                }
            }
            (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => self.eq_expr(l, r),
            (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r),
            _ => false,
        }
    }

    /// Check whether two blocks are the same.
    pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
        over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
            both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
    }

    // ok, it’s a big function, but mostly one big match with simples cases
    #[allow(cyclomatic_complexity)]
    pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
        if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) {
            if l == r {
                return true;
            }
        }

        match (&left.node, &right.node) {
            (&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => {
                lmut == rmut && self.eq_expr(le, re)
            }
            (&ExprAgain(li), &ExprAgain(ri)) => {
                both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str())
            }
            (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => {
                self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
            }
            (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
                lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
            }
            (&ExprBlock(ref l), &ExprBlock(ref r)) => {
                self.eq_block(l, r)
            }
            (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => {
                lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
            }
            (&ExprBreak(li), &ExprBreak(ri)) => {
                both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str())
            }
            (&ExprBox(ref l), &ExprBox(ref r)) => {
                self.eq_expr(l, r)
            }
            (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => {
                !self.ignore_fn &&
                    self.eq_expr(lfun, rfun) &&
                    self.eq_exprs(largs, rargs)
            }
            (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => {
                self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
            }
            (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => {
                lfident.node == rfident.node && self.eq_expr(lfexp, rfexp)
            }
            (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => {
                self.eq_expr(la, ra) && self.eq_expr(li, ri)
            }
            (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => {
                self.eq_expr(lc, rc) &&
                    self.eq_block(lt, rt) &&
                    both(le, re, |l, r| self.eq_expr(l, r))
            }
            (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
            (&ExprLoop(ref lb, ref ll), &ExprLoop(ref rb, ref rl)) => {
                self.eq_block(lb, rb) &&
                    both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())

            }
            (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
                ls == rs &&
                    self.eq_expr(le, re) &&
                    over(la, ra, |l, r| {
                        self.eq_expr(&l.body, &r.body) &&
                            both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
                            over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
                    })
            }
            (&ExprMethodCall(ref lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => {
                // TODO: tys
                !self.ignore_fn &&
                    lname.node == rname.node &&
                    ltys.is_empty() &&
                    rtys.is_empty() &&
                    self.eq_exprs(largs, rargs)
            }
            (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => {
                both(lb, rb, |l, r| self.eq_expr(l, r)) &&
                both(le, re, |l, r| self.eq_expr(l, r))
            }
            (&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => {
                self.eq_expr(le, re) && self.eq_expr(ll, rl)
            }
            (&ExprRet(ref l), &ExprRet(ref r)) => {
                both(l, r, |l, r| self.eq_expr(l, r))
            }
            (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => {
                both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath)
            }
            (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup),
            (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => {
                li.node == ri.node && self.eq_expr(le, re)
            }
            (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => {
                lop == rop && self.eq_expr(le, re)
            }
            (&ExprVec(ref l), &ExprVec(ref r)) => self.eq_exprs(l, r),
            (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => {
                self.eq_expr(lc, rc) &&
                    self.eq_block(lb, rb) &&
                    both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
            }
            _ => false,
        }
    }

    fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool {
        over(left, right, |l, r| self.eq_expr(l, r))
    }

    /// Check whether two patterns are the same.
    pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool {
        match (&left.node, &right.node) {
            (&PatBox(ref l), &PatBox(ref r)) => {
                self.eq_pat(l, r)
            }
            (&PatEnum(ref lp, ref la), &PatEnum(ref rp, ref ra)) => {
                self.eq_path(lp, rp) &&
                    both(la, ra, |l, r| {
                        over(l, r, |l, r| self.eq_pat(l, r))
                    })
            }
            (&PatIdent(ref lb, ref li, ref lp), &PatIdent(ref rb, ref ri, ref rp)) => {
                lb == rb && li.node.name.as_str() == ri.node.name.as_str() &&
                    both(lp, rp, |l, r| self.eq_pat(l, r))
            }
            (&PatLit(ref l), &PatLit(ref r)) => {
                self.eq_expr(l, r)
            }
            (&PatQPath(ref ls, ref lp), &PatQPath(ref rs, ref rp)) => {
                self.eq_qself(ls, rs) && self.eq_path(lp, rp)
            }
            (&PatTup(ref l), &PatTup(ref r)) => {
                over(l, r, |l, r| self.eq_pat(l, r))
            }
            (&PatRange(ref ls, ref le), &PatRange(ref rs, ref re)) => {
                self.eq_expr(ls, rs) &&
                    self.eq_expr(le, re)
            }
            (&PatRegion(ref le, ref lm), &PatRegion(ref re, ref rm)) => {
                lm == rm && self.eq_pat(le, re)
            }
            (&PatVec(ref ls, ref li, ref le), &PatVec(ref rs, ref ri, ref re)) => {
                over(ls, rs, |l, r| self.eq_pat(l, r)) &&
                    over(le, re, |l, r| self.eq_pat(l, r)) &&
                    both(li, ri, |l, r| self.eq_pat(l, r))
            }
            (&PatWild, &PatWild) => true,
            _ => false,
        }
    }

    fn eq_path(&self, left: &Path, right: &Path) -> bool {
        // The == of idents doesn't work with different contexts,
        // we have to be explicit about hygiene
        left.global == right.global &&
        over(&left.segments,
             &right.segments,
             |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters)
    }

    fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool {
        left.ty.node == right.ty.node && left.position == right.position
    }

    fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
        match (&left.node, &right.node) {
            (&TyVec(ref lvec), &TyVec(ref rvec)) => self.eq_ty(lvec, rvec),
            (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && self.eq_ty(&*lmut.ty, &*rmut.ty),
            (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => {
                lrmut.mutbl == rrmut.mutbl && self.eq_ty(&*lrmut.ty, &*rrmut.ty)
            }
            (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => {
                both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(lpath, rpath)
            }
            (&TyInfer, &TyInfer) => true,
            _ => false,
        }
    }
}

/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`.
fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
    where F: FnMut(&X, &X) -> bool
{
    l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
}

/// Check if two slices are equal as per `eq_fn`.
fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
    where F: FnMut(&X, &X) -> bool
{
    left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
}
<|endoftext|>


<commit_before>use super::capi::*;
use std::ptr::null_mut;

pub struct Judy1 {
    m: Pvoid_t,
}

impl Default for Judy1 {
    fn default() -> Self {
        Self::new()
    }
}

impl Judy1 {
    pub fn new() -> Judy1 {
        Judy1 { m: null_mut() }
    }

    pub fn set(&mut self, index: Word_t) -> bool {
        let prev = unsafe { Judy1Set(&mut self.m, index, null_mut()) };
        prev == 1
    }

    /// Warning: This function requires the keys to be sorted in relation to data already in the array.
    /// That means even if this set of keys is sorted, if it's out of sequence with the keys in
    /// the array then the function will fail.
    pub fn set_bulk_sorted(&mut self, count: Word_t, keys: &[Word_t]) -> bool {
        assert!(
            keys.len() as u64 >= count,
            "Judy1::set_bulk_sorted: Keys array shorter than count argument!"
        );
        unsafe {
            let result = Judy1SetArray(&mut self.m, count, keys.as_ptr(), null_mut());
            result == 0 || result == 1
        }
    }

    pub fn unset(&mut self, index: Word_t) -> bool {
        let prev = unsafe { Judy1Unset(&mut self.m, index, null_mut()) };
        prev == 1
    }

    pub fn test(&mut self, index: Word_t) -> bool {
        1 == unsafe { Judy1Test(self.m, index, null_mut()) }
    }

    pub fn free(&mut self) -> Word_t {
        if self.m.is_null() {
            unsafe {
                let ret = Judy1FreeArray(&mut self.m, null_mut());
                assert!(self.m.is_null());
                ret
            }
        } else {
            0
        }
    }

    pub fn iter(&self) -> Judy1Iterator<'_> {
        Judy1Iterator { j: self, i: 0 }
    }

    pub fn count(&self, index1: Word_t, index2: Word_t) -> Word_t {
        unsafe { Judy1Count(self.m, index1, index2, null_mut()) }
    }

    pub fn clear(&mut self) {
        self.free();
    }

    pub fn len(&self) -> usize {
        self.count(0, Word_t::max_value()) as usize
    }

    pub fn is_empty(&self) -> bool {
        self.m.is_null()
    }
}

pub struct Judy1Iterator<'a> {
    j: &'a Judy1,
    i: Word_t,
}

impl<'a> Iterator for Judy1Iterator<'a> {
    type Item = Word_t;

    fn next(&mut self) -> Option<Word_t> {
        unsafe {
            let v = Judy1Next(self.j.m, &mut self.i, null_mut());
            if v == 0 {
                None
            } else {
                Some(self.i)
            }
        }
    }
}

impl Drop for Judy1 {
    fn drop(&mut self) {
        self.free();
    }
}
<commit_msg>fix logic error in judy1 free<commit_after>use super::capi::*;
use std::ptr::null_mut;

pub struct Judy1 {
    m: Pvoid_t,
}

impl Default for Judy1 {
    fn default() -> Self {
        Self::new()
    }
}

impl Judy1 {
    pub fn new() -> Judy1 {
        Judy1 { m: null_mut() }
    }

    pub fn set(&mut self, index: Word_t) -> bool {
        let prev = unsafe { Judy1Set(&mut self.m, index, null_mut()) };
        prev == 1
    }

    /// Warning: This function requires the keys to be sorted in relation to data already in the array.
    /// That means even if this set of keys is sorted, if it's out of sequence with the keys in
    /// the array then the function will fail.
    pub fn set_bulk_sorted(&mut self, count: Word_t, keys: &[Word_t]) -> bool {
        assert!(
            keys.len() as u64 >= count,
            "Judy1::set_bulk_sorted: Keys array shorter than count argument!"
        );
        unsafe {
            let result = Judy1SetArray(&mut self.m, count, keys.as_ptr(), null_mut());
            result == 0 || result == 1
        }
    }

    pub fn unset(&mut self, index: Word_t) -> bool {
        let prev = unsafe { Judy1Unset(&mut self.m, index, null_mut()) };
        prev == 1
    }

    pub fn test(&mut self, index: Word_t) -> bool {
        1 == unsafe { Judy1Test(self.m, index, null_mut()) }
    }

    pub fn free(&mut self) -> Word_t {
        if !self.m.is_null() {
            unsafe {
                let ret = Judy1FreeArray(&mut self.m, null_mut());
                assert!(self.m.is_null());
                ret
            }
        } else {
            0
        }
    }

    pub fn iter(&self) -> Judy1Iterator<'_> {
        Judy1Iterator { j: self, i: 0 }
    }

    pub fn count(&self, index1: Word_t, index2: Word_t) -> Word_t {
        unsafe { Judy1Count(self.m, index1, index2, null_mut()) }
    }

    pub fn clear(&mut self) {
        self.free();
    }

    pub fn len(&self) -> usize {
        self.count(0, Word_t::max_value()) as usize
    }

    pub fn is_empty(&self) -> bool {
        self.m.is_null()
    }
}

pub struct Judy1Iterator<'a> {
    j: &'a Judy1,
    i: Word_t,
}

impl<'a> Iterator for Judy1Iterator<'a> {
    type Item = Word_t;

    fn next(&mut self) -> Option<Word_t> {
        unsafe {
            let v = Judy1Next(self.j.m, &mut self.i, null_mut());
            if v == 0 {
                None
            } else {
                Some(self.i)
            }
        }
    }
}

impl Drop for Judy1 {
    fn drop(&mut self) {
        self.free();
    }
}
<|endoftext|>


<commit_before>/// # Module variables

use std::ops::{Add, Mul, Sub, Neg};
use self::LpExpression::*;
use std::convert::Into;
use std::rc::Rc;

/// Type of variables. Using to initialize a linear programming variable
///
/// # Exemples
///
/// ```
/// use lp_modeler::variables::{LpVariable, LpType};
///
/// let ref a1 = LpVariable::new("a1", LpType::Integer)
///     .lower_bound(10)
///     .upper_bound(20);
///
/// ```
pub enum LpType {
    /// Binary variable
    Binary,
    /// Integer variable
    Integer,
    /// Reel variable
    Continuous
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum LpExpression {
    BinaryVariable {
        name: String,
    },
    IntegerVariable {
        name: String,
        lower_bound: Option<i32>,
        upper_bound: Option<i32>,
    },
    ContinuousVariable {
        name: String,
        lower_bound: Option<i32>,
        upper_bound: Option<i32>,
    },
    MulExpr(Rc<LpExpression>, Rc<LpExpression>),
    AddExpr(Rc<LpExpression>, Rc<LpExpression>),
    SubExpr(Rc<LpExpression>, Rc<LpExpression>),
    LitVal(i32),
    EmptyExpr
}

pub struct LpVariable;

#[derive(Debug, Clone)]
pub enum Constraint {
    /* Not supported by solver format files (lp file or mps file) !
    Greater,
    Less,
    */
    GreaterOrEqual,
    LessOrEqual,
    Equal
}

#[derive(Debug, Clone)]
pub struct LpConstraint(pub LpExpression, pub Constraint, pub LpExpression);

impl LpVariable {
    pub fn new<S: Into<String>>(name: S, var_type: LpType) -> LpExpression {
        match var_type {
            LpType::Binary => BinaryVariable { name: name.into() },
            LpType::Integer => IntegerVariable { name: name.into(), lower_bound: None, upper_bound: None },
            LpType::Continuous => ContinuousVariable { name: name.into(), lower_bound: None, upper_bound: None }
        }
    }

}

#[allow(dead_code)]
impl LpExpression {
    pub fn lower_bound(&self, lw: i32) -> LpExpression {
        match self {
            &BinaryVariable { name: ref n } =>
                BinaryVariable {
                    name: n.clone()
                },
            &IntegerVariable { name: ref n, lower_bound: _, upper_bound: u } =>
                IntegerVariable {
                    name: n.clone(),
                    lower_bound: Some(lw),
                    upper_bound: u
                },
            &ContinuousVariable { name: ref n, lower_bound: _, upper_bound: u } =>
                ContinuousVariable {
                    name: n.clone(),
                    lower_bound: Some(lw),
                    upper_bound: u
                },
            _ => self.clone()
        }
    }
    pub fn upper_bound(&self, up: i32) -> LpExpression {
        match self {
            &BinaryVariable { name: ref n } =>
                BinaryVariable {
                    name: n.clone()
                },
            &IntegerVariable { name: ref n, lower_bound: l, upper_bound: _ } =>
                IntegerVariable {
                    name: n.clone(),
                    lower_bound: l,
                    upper_bound: Some(up)
                },
            &ContinuousVariable { name: ref n, lower_bound: l, upper_bound: _ } =>
                ContinuousVariable {
                    name: n.clone(),
                    lower_bound: l,
                    upper_bound: Some(up)
                },
            _ => self.clone()
        }
    }

}

pub trait LpOperations<T> where T: Into<LpExpression> {
    fn le(&self, lhs_expr: T) -> LpConstraint;
    fn ge(&self, lhs_expr: T) -> LpConstraint;
    fn equal(&self, lhs_expr: T) -> LpConstraint;
}

impl Into<LpExpression> for i32 {
    fn into(self) -> LpExpression {
        LitVal(self)
    }
}

impl<'a> Into<LpExpression> for &'a LpExpression {
    fn into(self) -> LpExpression {
        self.clone()
    }
}

fn general_form_constraints(cstr: &LpConstraint) -> LpConstraint {
    // TODO: Optimize tailrec
    fn dfs_constant(expr: &LpExpression, acc: i32) -> i32 {
        match expr {
            &MulExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(ref x) = e1 {
                    if let &LitVal(ref y) = e2 {
                        acc+x*y
                    }else{
                        dfs_constant(e2, acc)
                    }
                }else{
                    if let &LitVal(ref y) = e2 {
                        dfs_constant(e1, acc+y)
                    }else {
                        dfs_constant(e2, acc) + dfs_constant(e1, 0)
                    }
                }
            },
            &AddExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(ref x) = e1 {
                    if let &LitVal(ref y) = e2 {
                        acc+x+y
                    }else {
                        dfs_constant(e2, acc+x)
                    }
                }else{
                    if let &LitVal(ref y) = e2 {
                        dfs_constant(e1, acc+y)
                    }else {
                        dfs_constant(e2, acc) + dfs_constant(e1, 0)
                    }
                }
            },
            &SubExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(ref x) = e1 {
                    if let &LitVal(ref y) = e2 {
                        acc+x-y
                    }else {
                        dfs_constant(e2, acc+x)
                    }
                }else{
                    if let &LitVal(ref y) = e2 {
                        dfs_constant(e1, acc-y)
                    }else {
                        dfs_constant(e1, acc) - dfs_constant(e2, 0)
                    }
                }
            },
            _ => acc
        }
    }

    fn dfs_remove_constant(expr: &LpExpression) -> LpExpression {
        match expr {
            &MulExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(..) = e1 {
                    if let &LitVal(..) = e2 {
                        EmptyExpr
                    }else{
                        MulExpr(rc_e1.clone(), Rc::new(dfs_remove_constant(e2)))
                    }
                }else{
                    if let &LitVal(..) = e2 {
                        MulExpr(Rc::new(dfs_remove_constant(e1)), rc_e2.clone())
                    }else {
                        MulExpr(Rc::new(dfs_remove_constant(e1)), Rc::new(dfs_remove_constant(e2)))
                    }
                }
            },
            &AddExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(..) = e1 {
                    if let &LitVal(..) = e2 {
                        EmptyExpr
                    }else {
                        dfs_remove_constant(e2)
                    }
                }else{
                    if let &LitVal(..) = e2 {
                        dfs_remove_constant(e1)
                    }else {
                        AddExpr(Rc::new(dfs_remove_constant(e1)), Rc::new(dfs_remove_constant(e2)))
                    }
                }
            },
            &SubExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(..) = e1 {
                    if let &LitVal(..) = e2 {
                        EmptyExpr
                    }else {
                        dfs_remove_constant(e2)
                    }
                }else{
                    if let &LitVal(..) = e2 {
                        dfs_remove_constant(e1)
                    }else {
                        SubExpr(Rc::new(dfs_remove_constant(e1)), Rc::new(dfs_remove_constant(e2)))
                    }
                }
            },
            _ => expr.clone()
        }
    }

    let &LpConstraint(ref lhs, ref op, ref rhs) = cstr;
    let new_cstr;
    if let &LitVal(0) = rhs {
        new_cstr = cstr.clone();
    }else{
        let ref lhs_constraint = lhs - rhs;
        let constant = dfs_constant(lhs_constraint, 0);
        let lhs_constraint = dfs_remove_constant(lhs_constraint);
        new_cstr = LpConstraint(lhs_constraint, op.clone(), LitVal(-constant));
    }
    new_cstr
}

// <LpExr> op <LpExpr> where LpExpr is implicit
impl<T: Into<LpExpression> + Clone, U> LpOperations<T> for U where U: Into<LpExpression> + Clone {
    /*
    fn lt(&self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::Less, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
    */
    fn le(&self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::LessOrEqual, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
    /*
    fn gt(&self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::Greater, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
    */
    fn ge(&self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::GreaterOrEqual, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
    fn equal( &self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::Equal, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
}

// LpExpr + (LpExpr, &LpExpr, i32)
impl<T> Add<T> for LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn add(self, _rhs: T) -> LpExpression {
        AddExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// &LpExpr + (LpExpr, &LpExpr, i32)
impl<'a, T> Add<T> for &'a LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn add(self, _rhs: T) -> LpExpression {
        AddExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// i32 + &LpExpr
impl<'a> Add<&'a LpExpression> for i32 {
    type Output = LpExpression;
    fn add(self, _rhs: &'a LpExpression) -> LpExpression {
        AddExpr(Rc::new(LitVal(self)), Rc::new(_rhs.clone()))
    }
}

// LpExpr - (LpExpr, &LpExpr, i32)
impl<T> Sub<T> for LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn sub(self, _rhs: T) -> LpExpression {
        SubExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// &LpExpr - (LpExpr, &LpExpr, i32)
impl<'a, T> Sub<T> for &'a LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn sub(self, _rhs: T) -> LpExpression {
        SubExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// i32 - &LpExpr
impl<'a> Sub<&'a LpExpression> for i32 {
    type Output = LpExpression;
    fn sub(self, _rhs: &'a LpExpression) -> LpExpression {
        SubExpr(Rc::new(LitVal(self)), Rc::new(_rhs.clone()))
    }
}

impl<'a> Neg for &'a LpExpression {
    type Output = LpExpression;
    fn neg(self) -> LpExpression {
        MulExpr(Rc::new(LitVal(-1)), Rc::new(self.clone()))
    }
}

// i32 * LpExpr
impl Mul<LpExpression> for i32 {
    type Output = LpExpression;
    fn mul(self, _rhs: LpExpression) -> LpExpression {
        LpExpression::MulExpr(Rc::new(LitVal(self)), Rc::new(_rhs))
    }
}

// i32 * &LpExp
impl<'a> Mul<&'a LpExpression> for i32 {
    type Output = LpExpression;

    fn mul(self, _rhs: &'a LpExpression) -> LpExpression {
        MulExpr(Rc::new(LitVal(self)), Rc::new(_rhs.clone()))
    }
}

/// make a complete expression or a constraint with a vector of expressions
///
/// # Exemples
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::variables::{LpVariable, LpType, lp_sum, LpOperations};
///
/// let mut problem = LpProblem::new("My Problem", LpObjective::Maximize);
/// let ref a = LpVariable::new("a", LpType::Binary);
/// let ref b = LpVariable::new("b", LpType::Binary);
/// let ref c = LpVariable::new("c", LpType::Binary);
///
/// let ref v = vec!(a, b, c);
/// problem += lp_sum(v).equal(10);
/// ```
///
pub fn lp_sum<T>(expr: &Vec<T>) -> LpExpression where T : Into<LpExpression> + Clone {

    let mut expr = expr.clone();
    if let Some(e1) = expr.pop() {
        if let Some(e2) = expr.pop() {
            expr.push(e2);
            AddExpr(Rc::new(e1.into()), Rc::new(lp_sum(&expr)))
        } else {
            e1.into()
        }
    }else{
        EmptyExpr
    }
}

<commit_msg>Remove dead code<commit_after>/// # Module variables

use std::ops::{Add, Mul, Sub, Neg};
use self::LpExpression::*;
use std::convert::Into;
use std::rc::Rc;

/// Type of variables. Using to initialize a linear programming variable
///
/// # Exemples
///
/// ```
/// use lp_modeler::variables::{LpVariable, LpType};
///
/// let ref a1 = LpVariable::new("a1", LpType::Integer)
///     .lower_bound(10)
///     .upper_bound(20);
///
/// ```
pub enum LpType {
    /// Binary variable
    Binary,
    /// Integer variable
    Integer,
    /// Reel variable
    Continuous
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum LpExpression {
    BinaryVariable {
        name: String,
    },
    IntegerVariable {
        name: String,
        lower_bound: Option<i32>,
        upper_bound: Option<i32>,
    },
    ContinuousVariable {
        name: String,
        lower_bound: Option<i32>,
        upper_bound: Option<i32>,
    },
    MulExpr(Rc<LpExpression>, Rc<LpExpression>),
    AddExpr(Rc<LpExpression>, Rc<LpExpression>),
    SubExpr(Rc<LpExpression>, Rc<LpExpression>),
    LitVal(i32),
    EmptyExpr
}

pub struct LpVariable;

#[derive(Debug, Clone)]
pub enum Constraint {
    /* Not supported by solver format files (lp file or mps file) !
    Greater,
    Less,
    */
    GreaterOrEqual,
    LessOrEqual,
    Equal
}

#[derive(Debug, Clone)]
pub struct LpConstraint(pub LpExpression, pub Constraint, pub LpExpression);

impl LpVariable {
    pub fn new<S: Into<String>>(name: S, var_type: LpType) -> LpExpression {
        match var_type {
            LpType::Binary => BinaryVariable { name: name.into() },
            LpType::Integer => IntegerVariable { name: name.into(), lower_bound: None, upper_bound: None },
            LpType::Continuous => ContinuousVariable { name: name.into(), lower_bound: None, upper_bound: None }
        }
    }

}

#[allow(dead_code)]
impl LpExpression {
    pub fn lower_bound(&self, lw: i32) -> LpExpression {
        match self {
            &BinaryVariable { name: ref n } =>
                BinaryVariable {
                    name: n.clone()
                },
            &IntegerVariable { name: ref n, lower_bound: _, upper_bound: u } =>
                IntegerVariable {
                    name: n.clone(),
                    lower_bound: Some(lw),
                    upper_bound: u
                },
            &ContinuousVariable { name: ref n, lower_bound: _, upper_bound: u } =>
                ContinuousVariable {
                    name: n.clone(),
                    lower_bound: Some(lw),
                    upper_bound: u
                },
            _ => self.clone()
        }
    }
    pub fn upper_bound(&self, up: i32) -> LpExpression {
        match self {
            &BinaryVariable { name: ref n } =>
                BinaryVariable {
                    name: n.clone()
                },
            &IntegerVariable { name: ref n, lower_bound: l, upper_bound: _ } =>
                IntegerVariable {
                    name: n.clone(),
                    lower_bound: l,
                    upper_bound: Some(up)
                },
            &ContinuousVariable { name: ref n, lower_bound: l, upper_bound: _ } =>
                ContinuousVariable {
                    name: n.clone(),
                    lower_bound: l,
                    upper_bound: Some(up)
                },
            _ => self.clone()
        }
    }

}

pub trait LpOperations<T> where T: Into<LpExpression> {
    fn le(&self, lhs_expr: T) -> LpConstraint;
    fn ge(&self, lhs_expr: T) -> LpConstraint;
    fn equal(&self, lhs_expr: T) -> LpConstraint;
}

impl Into<LpExpression> for i32 {
    fn into(self) -> LpExpression {
        LitVal(self)
    }
}

impl<'a> Into<LpExpression> for &'a LpExpression {
    fn into(self) -> LpExpression {
        self.clone()
    }
}

fn general_form_constraints(cstr: &LpConstraint) -> LpConstraint {
    // TODO: Optimize tailrec
    fn dfs_constant(expr: &LpExpression, acc: i32) -> i32 {
        match expr {
            &MulExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(ref x) = e1 {
                    if let &LitVal(ref y) = e2 {
                        acc+x*y
                    }else{
                        dfs_constant(e2, acc)
                    }
                }else{
                    if let &LitVal(ref y) = e2 {
                        dfs_constant(e1, acc+y)
                    }else {
                        dfs_constant(e2, acc) + dfs_constant(e1, 0)
                    }
                }
            },
            &AddExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(ref x) = e1 {
                    if let &LitVal(ref y) = e2 {
                        acc+x+y
                    }else {
                        dfs_constant(e2, acc+x)
                    }
                }else{
                    if let &LitVal(ref y) = e2 {
                        dfs_constant(e1, acc+y)
                    }else {
                        dfs_constant(e2, acc) + dfs_constant(e1, 0)
                    }
                }
            },
            &SubExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(ref x) = e1 {
                    if let &LitVal(ref y) = e2 {
                        acc+x-y
                    }else {
                        dfs_constant(e2, acc+x)
                    }
                }else{
                    if let &LitVal(ref y) = e2 {
                        dfs_constant(e1, acc-y)
                    }else {
                        dfs_constant(e1, acc) - dfs_constant(e2, 0)
                    }
                }
            },
            _ => acc
        }
    }

    fn dfs_remove_constant(expr: &LpExpression) -> LpExpression {
        match expr {
            &MulExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(..) = e1 {
                    if let &LitVal(..) = e2 {
                        EmptyExpr
                    }else{
                        MulExpr(rc_e1.clone(), Rc::new(dfs_remove_constant(e2)))
                    }
                }else{
                    if let &LitVal(..) = e2 {
                        MulExpr(Rc::new(dfs_remove_constant(e1)), rc_e2.clone())
                    }else {
                        MulExpr(Rc::new(dfs_remove_constant(e1)), Rc::new(dfs_remove_constant(e2)))
                    }
                }
            },
            &AddExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(..) = e1 {
                    if let &LitVal(..) = e2 {
                        EmptyExpr
                    }else {
                        dfs_remove_constant(e2)
                    }
                }else{
                    if let &LitVal(..) = e2 {
                        dfs_remove_constant(e1)
                    }else {
                        AddExpr(Rc::new(dfs_remove_constant(e1)), Rc::new(dfs_remove_constant(e2)))
                    }
                }
            },
            &SubExpr(ref rc_e1, ref rc_e2) => {
                let ref e1 = **rc_e1;
                let ref e2 = **rc_e2;
                if let &LitVal(..) = e1 {
                    if let &LitVal(..) = e2 {
                        EmptyExpr
                    }else {
                        dfs_remove_constant(e2)
                    }
                }else{
                    if let &LitVal(..) = e2 {
                        dfs_remove_constant(e1)
                    }else {
                        SubExpr(Rc::new(dfs_remove_constant(e1)), Rc::new(dfs_remove_constant(e2)))
                    }
                }
            },
            _ => expr.clone()
        }
    }

    let &LpConstraint(ref lhs, ref op, ref rhs) = cstr;
    let new_cstr;
    if let &LitVal(0) = rhs {
        new_cstr = cstr.clone();
    }else{
        let ref lhs_constraint = lhs - rhs;
        let constant = dfs_constant(lhs_constraint, 0);
        let lhs_constraint = dfs_remove_constant(lhs_constraint);
        new_cstr = LpConstraint(lhs_constraint, op.clone(), LitVal(-constant));
    }
    new_cstr
}

// <LpExr> op <LpExpr> where LpExpr is implicit
impl<T: Into<LpExpression> + Clone, U> LpOperations<T> for U where U: Into<LpExpression> + Clone {
    fn le(&self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::LessOrEqual, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
    fn ge(&self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::GreaterOrEqual, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
    fn equal( &self, lhs_expr: T) -> LpConstraint {
        let c = LpConstraint(self.clone().into(), Constraint::Equal, lhs_expr.clone().into());
        let c = general_form_constraints(&c);
        c
    }
}

// LpExpr + (LpExpr, &LpExpr, i32)
impl<T> Add<T> for LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn add(self, _rhs: T) -> LpExpression {
        AddExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// &LpExpr + (LpExpr, &LpExpr, i32)
impl<'a, T> Add<T> for &'a LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn add(self, _rhs: T) -> LpExpression {
        AddExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// i32 + &LpExpr
impl<'a> Add<&'a LpExpression> for i32 {
    type Output = LpExpression;
    fn add(self, _rhs: &'a LpExpression) -> LpExpression {
        AddExpr(Rc::new(LitVal(self)), Rc::new(_rhs.clone()))
    }
}

// LpExpr - (LpExpr, &LpExpr, i32)
impl<T> Sub<T> for LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn sub(self, _rhs: T) -> LpExpression {
        SubExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// &LpExpr - (LpExpr, &LpExpr, i32)
impl<'a, T> Sub<T> for &'a LpExpression where T: Into<LpExpression> + Clone {
    type Output = LpExpression;
    fn sub(self, _rhs: T) -> LpExpression {
        SubExpr(Rc::new(self.clone()), Rc::new(_rhs.into()))
    }
}

// i32 - &LpExpr
impl<'a> Sub<&'a LpExpression> for i32 {
    type Output = LpExpression;
    fn sub(self, _rhs: &'a LpExpression) -> LpExpression {
        SubExpr(Rc::new(LitVal(self)), Rc::new(_rhs.clone()))
    }
}

impl<'a> Neg for &'a LpExpression {
    type Output = LpExpression;
    fn neg(self) -> LpExpression {
        MulExpr(Rc::new(LitVal(-1)), Rc::new(self.clone()))
    }
}

// i32 * LpExpr
impl Mul<LpExpression> for i32 {
    type Output = LpExpression;
    fn mul(self, _rhs: LpExpression) -> LpExpression {
        LpExpression::MulExpr(Rc::new(LitVal(self)), Rc::new(_rhs))
    }
}

// i32 * &LpExp
impl<'a> Mul<&'a LpExpression> for i32 {
    type Output = LpExpression;

    fn mul(self, _rhs: &'a LpExpression) -> LpExpression {
        MulExpr(Rc::new(LitVal(self)), Rc::new(_rhs.clone()))
    }
}

/// make a complete expression or a constraint with a vector of expressions
///
/// # Exemples
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::variables::{LpVariable, LpType, lp_sum, LpOperations};
///
/// let mut problem = LpProblem::new("My Problem", LpObjective::Maximize);
/// let ref a = LpVariable::new("a", LpType::Binary);
/// let ref b = LpVariable::new("b", LpType::Binary);
/// let ref c = LpVariable::new("c", LpType::Binary);
///
/// let ref v = vec!(a, b, c);
/// problem += lp_sum(v).equal(10);
/// ```
///
pub fn lp_sum<T>(expr: &Vec<T>) -> LpExpression where T : Into<LpExpression> + Clone {

    let mut expr = expr.clone();
    if let Some(e1) = expr.pop() {
        if let Some(e2) = expr.pop() {
            expr.push(e2);
            AddExpr(Rc::new(e1.into()), Rc::new(lp_sum(&expr)))
        } else {
            e1.into()
        }
    }else{
        EmptyExpr
    }
}

<|endoftext|>


<commit_before>use regex::Regex;

static TAGS : Regex = regex!("\\{%.*?%\\}|\\{\\{.*?\\}\\}");
static EXPRESSION : Regex = regex!("\\{%.*?%\\}");
static STATEMENT : Regex = regex!("\\{\\{.*?\\}\\}");
static WHITESPACE : Regex = regex!(r"\s+");

#[deriving(Show, PartialEq)]
enum Token {
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash,

    Identifier,
    SingleStringLiteral,
    DoubleStringLiteral,
    NumberLiteral,
    DotDot,
    ComparisonOperator
}

#[deriving(Show, PartialEq)]
enum Element{
    Statement(Vec<Token>, String),
    Expression(Vec<Token>, String),
    Raw(String)
}

fn split_blocks(text: &str) -> Vec<&str>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in TAGS.find_iter(text) {
        match text.slice(current, begin){
            "" => {}
            t => tokens.push(t)
        };
        tokens.push(text.slice(begin, end));
        current = end;
    }
    match text.slice(current, text.len()){
        "" => {}
        t => tokens.push(t)
    };
    tokens
}

fn tokenize(text: &str) -> Vec<Element> {
    let blocks = split_blocks(text);
    blocks.iter().map(|block| {
        if(EXPRESSION.is_match(*block)){
            Expression(granularize(*block), block.to_string())
        }else if(STATEMENT.is_match(*block)){
            Statement(granularize(*block), block.to_string())
        }else{
            Raw(block.to_string())
        }
    }).collect()
}

fn granularize(block: &str) -> Vec<Token>{
    vec!()
}

#[test]
fn test_split_blocks() {
    assert_eq!(split_blocks("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"),
                vec!["asdlkjfn\n", "{{askdljfbalkjsdbf}}", " asdjlfb"]);
    assert_eq!(split_blocks("asdlkjfn\n{%askdljfbalkjsdbf%} asdjlfb"),
                vec!["asdlkjfn\n", "{%askdljfbalkjsdbf%}", " asdjlfb"]);
}

#[test]
fn test_tokenize() {
    assert_eq!(tokenize("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"), vec![
               Raw("asdlkjfn\n".to_string()), Statement(vec!(), "{{askdljfbalkjsdbf}}".to_string()), Raw(" asdjlfb".to_string())
               ]);
}

<commit_msg>Implement more lexer keywords<commit_after>use regex::Regex;

static TAGS       : Regex = regex!("\\{%.*?%\\}|\\{\\{.*?\\}\\}");
static EXPRESSION : Regex = regex!("\\{%(.*?)%\\}");
static STATEMENT  : Regex = regex!("\\{\\{(.*?)\\}\\}");
static WHITESPACE : Regex = regex!(r"\s+");

static IDENTIFIER            : Regex = regex!(r"[a-zA-Z_][\w-]*\??");
static SINGLE_STRING_LITERAL : Regex = regex!(r"'[^']*'");
static DOUBLE_STRING_LITERAL : Regex = regex!("\"[^\"]*\"");
static NUMBER_LITERAL        : Regex = regex!(r"-?\d+(\.\d+)?");
static DOTDOT                : Regex = regex!(r"\.\.");

#[deriving(Show, PartialEq)]
enum ComparisonOperator{
    Equals, NotEquals,
    LessThan, GreaterThan,
    LessThanEquals, GreaterThanEquals,
    Contains
}

#[deriving(Show, PartialEq)]
enum Token {
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash,

    Identifier(String),
    StringLiteral(String),
    NumberLiteral(String),
    DotDot,
    Comparison(ComparisonOperator)
}

#[deriving(Show, PartialEq)]
enum Element{
    Statement(Vec<Token>, String),
    Expression(Vec<Token>, String),
    Raw(String)
}

fn split_blocks(text: &str) -> Vec<&str>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in TAGS.find_iter(text) {
        match text.slice(current, begin){
            "" => {}
            t => tokens.push(t)
        };
        tokens.push(text.slice(begin, end));
        current = end;
    }
    match text.slice(current, text.len()){
        "" => {}
        t => tokens.push(t)
    };
    tokens
}

fn tokenize(text: &str) -> Vec<Element> {
    split_blocks(text).iter().map(|block| {
        if(EXPRESSION.is_match(*block)){
            let caps = EXPRESSION.captures(*block).unwrap();
            Expression(granularize(caps.at(1)), block.to_string())
        }else if(STATEMENT.is_match(*block)){
            let caps = STATEMENT.captures(*block).unwrap();
            Statement(granularize(caps.at(1)), block.to_string())
        }else{
            Raw(block.to_string())
        }
    }).collect()
}

fn granularize(block: &str) -> Vec<Token>{
    WHITESPACE.split(block).map(|el|{
        match el {
            "|" => Pipe,
            "." => Dot,
            ":" => Colon,
            "," => Comma,
            "[" => OpenSquare,
            "]" => CloseSquare,
            "(" => OpenRound,
            ")" => CloseRound,
            "?" => Question,
            "-" => Dash,

            "=="       => Comparison(Equals),
            "!="       => Comparison(NotEquals),
            "<="       => Comparison(LessThanEquals),
            ">="       => Comparison(GreaterThanEquals),
            "<"        => Comparison(LessThan),
            ">"        => Comparison(GreaterThan),
            "contains" => Comparison(Contains),

            x if DOTDOT.is_match(x) => DotDot,
            x if SINGLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if DOUBLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if NUMBER_LITERAL.is_match(x) => NumberLiteral(x.to_string()),
            x if IDENTIFIER.is_match(x) => Identifier(x.to_string()),
            x => panic!("{} is not a valid identifier", x)
        }
    }).collect()
}

#[test]
fn test_split_blocks() {
    assert_eq!(split_blocks("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"),
                vec!["asdlkjfn\n", "{{askdljfbalkjsdbf}}", " asdjlfb"]);
    assert_eq!(split_blocks("asdlkjfn\n{%askdljfbalkjsdbf%} asdjlfb"),
                vec!["asdlkjfn\n", "{%askdljfbalkjsdbf%}", " asdjlfb"]);
}

#[test]
fn test_tokenize() {
    assert_eq!(tokenize("wat\n{{hello 'world'}} test"), vec![
               Raw("wat\n".to_string()), Statement(vec![Identifier("hello".to_string()), StringLiteral("'world'".to_string())], "{{hello 'world'}}".to_string()), Raw(" test".to_string())
               ]);
}

#[test]
fn test_granularize() {
}

<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader};
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::str;
use std::collections::VecDeque;
use std::path;
use std::process;
use error;

#[derive(PartialEq, Debug)]
pub enum TokenKind {
    Identifier,
    IntNumber,
    FloatNumber,
    String,
    Char,
    Symbol,
    Newline,
}

pub struct Token {
    pub kind: TokenKind,
    pub space: bool, // leading space
    pub val: String,
    pub line: i32,
}

impl Token {
    pub fn new(kind: TokenKind, val: &str, line: i32) -> Token {
        Token {
            kind: kind,
            space: false,
            val: val.to_string(),
            line: line,
        }
    }
}

pub struct Lexer<'a> {
    cur_line: i32,
    filename: String,
    peek: iter::Peekable<str::Chars<'a>>,
    peek_buf: VecDeque<char>,
    buf: VecDeque<Token>,
}

impl<'a> Lexer<'a> {
    pub fn new(filename: String, input: &'a str) -> Lexer<'a> {
        Lexer {
            cur_line: 1,
            filename: filename.to_string(),
            peek: input.chars().peekable(),
            peek_buf: VecDeque::new(),
            buf: VecDeque::new(),
        }
    }
    pub fn get_filename(self) -> String {
        self.filename
    }
    fn peek_get(&mut self) -> Option<&char> {
        if self.peek_buf.len() > 0 {
            self.peek_buf.front()
        } else {
            self.peek.peek()
        }
    }
    fn peek_next(&mut self) -> char {
        if self.peek_buf.len() > 0 {
            self.peek_buf.pop_front().unwrap()
        } else {
            self.peek.next().unwrap()
        }
    }
    fn peek_unget(&mut self, ch: char) {
        self.peek_buf.push_back(ch);
    }
    fn peek_next_char_is(&mut self, ch: char) -> bool {
        let c = self.peek_next();
        let nextc = self.peek_next();
        self.peek_unget(c);
        self.peek_unget(nextc);
        nextc == ch
    }
    fn peek_char_is(&mut self, ch: char) -> bool {
        let line = self.cur_line;
        let errf = || -> Option<&char> {
            error::error_exit(line, format!("expected '{}'", ch).as_str());
            None
        };

        let peekc = self.peek_get().or_else(errf).unwrap();
        *peekc == ch
    }

    fn skip(&mut self, s: &str) -> bool {
        let next = self.read_token();
        let n = next.ok_or("error").unwrap();
        if n.val == s && n.kind != TokenKind::String && n.kind != TokenKind::Char {
            true
        } else {
            self.buf.push_back(n);
            false
        }
    }
    fn unget(&mut self, t: Token) {
        self.buf.push_back(t);
    }

    pub fn read_identifier(&mut self) -> Token {
        let mut ident = String::new();
        loop {
            match self.peek_get() {
                Some(&c) => {
                    match c {
                        'a'...'z' | 'A'...'Z' | '_' | '0'...'9' => ident.push(c),
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek_next();
        }
        Token::new(TokenKind::Identifier, ident.as_str(), self.cur_line)
    }
    fn read_number_literal(&mut self) -> Token {
        let mut num = String::new();
        let mut is_float = false;
        loop {
            match self.peek_get() {
                Some(&c) => {
                    match c {
                        '.' | '0'...'9' => {
                            num.push(c);
                            if c == '.' {
                                is_float = true;
                            }
                        }
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek_next();
        }
        if is_float {
            Token::new(TokenKind::FloatNumber, num.as_str(), self.cur_line)
        } else {
            Token::new(TokenKind::IntNumber, num.as_str(), self.cur_line)
        }
    }
    pub fn read_newline(&mut self) -> Token {
        self.peek_next();
        Token::new(TokenKind::Newline, "", self.cur_line)
    }
    pub fn read_symbol(&mut self) -> Token {
        let c = self.peek_next();
        let mut sym = String::new();
        sym.push(c);
        match c {
            '+' | '-' | '*' | '/' | '%' | '=' | '^' | '!' => {
                if self.peek_char_is('=') {
                    sym.push(self.peek_next());
                }
            }
            '<' | '>' | '&' | '|' => {
                if self.peek_char_is(c) {
                    sym.push(self.peek_next());
                }
                if self.peek_char_is('=') {
                    sym.push(self.peek_next());
                }
            }
            '.' => {
                if self.peek_char_is('.') && self.peek_next_char_is('.') {
                    sym.push(self.peek_next());
                    sym.push(self.peek_next());
                }
            }
            _ => {}
        };
        Token::new(TokenKind::Symbol, sym.as_str(), self.cur_line)
    }
    fn read_string_literal(&mut self) -> Token {
        self.peek_next();
        let mut s = String::new();
        while !self.peek_char_is('\"') {
            s.push(self.peek_next());
        }
        self.peek_next();
        Token::new(TokenKind::String, s.as_str(), self.cur_line)
    }
    fn read_char_literal(&mut self) -> Token {
        self.peek_next();
        let mut s = String::new();
        while !self.peek_char_is('\'') {
            s.push(self.peek_next());
        }
        self.peek_next();
        Token::new(TokenKind::Char, s.as_str(), self.cur_line)
    }

    pub fn do_read_token(&mut self) -> Option<Token> {
        if !self.buf.is_empty() {
            return self.buf.pop_front();
        }

        match self.peek_get() {
            Some(&c) => {
                match c {
                    'a'...'z' | 'A'...'Z' | '_' => Some(self.read_identifier()),
                    ' ' | '\t' => {
                        self.peek_next();
                        // set a leading space
                        fn f(tok: Token) -> Option<Token> {
                            let mut t = tok;
                            t.space = true;
                            Some(t)
                        }
                        self.read_token().and_then(f)
                    }
                    '0'...'9' => Some(self.read_number_literal()),
                    '\"' => Some(self.read_string_literal()),
                    '\'' => Some(self.read_char_literal()),
                    '\n' => Some(self.read_newline()),
                    '/' => {
                        if self.peek_next_char_is('*') {
                            self.peek_next(); // /
                            self.peek_next(); // *
                            while !(self.peek_char_is('*') && self.peek_next_char_is('/')) {
                                self.peek_next();
                            }
                            self.peek_next();
                            self.peek_next();
                            println!("{}", self.peek_get().unwrap());
                            self.do_read_token()
                        } else if self.peek_next_char_is('/') {
                            self.peek_next(); // /
                            self.peek_next(); // /
                            while !self.peek_char_is('\n') {
                                self.peek_next();
                            }
                            self.do_read_token()
                        } else {
                            Some(self.read_symbol())
                        }
                    }
                    _ => Some(self.read_symbol()),
                }
            }
            None => None as Option<Token>,
        }
    }
    pub fn read_token(&mut self) -> Option<Token> {
        let t = self.do_read_token();
        match t {
            Some(tok) => {
                match tok.kind {
                    TokenKind::Newline => self.read_token(),
                    _ => Some(tok),
                }
            }
            _ => t,
        }
    }

    pub fn get(&mut self) -> Option<Token> {
        let t = self.read_token();
        match t {
            Some(tok) => {
                if tok.val == "#" {
                    // preprocessor directive
                    self.read_cpp_directive();
                    self.get()
                } else {
                    Some(tok)
                }
            }
            _ => t,
        }
    }

    // for c preprocessor

    fn read_cpp_directive(&mut self) {
        let t = self.do_read_token(); // cpp directive
        match t.ok_or("error").unwrap().val.as_str() {
            "include" => self.read_cpp_include(),
            "define" => self.read_cpp_define(),
            _ => {}
        }
    }

    fn cpp_try_include(&mut self, filename: &str) -> Option<String> {
        let header_paths = vec!["./include/",
                                "/include/",
                                "/usr/include/",
                                "/usr/include/linux/",
                                "/usr/include/x86_64-linux-gnu/",
                                ""];
        let mut real_filename = String::new();
        let mut found = false;
        for header_path in header_paths {
            real_filename = format!("{}{}", header_path, filename);
            if path::Path::new(real_filename.as_str()).exists() {
                found = true;
                break;
            }
        }
        if found { Some(real_filename) } else { None }
    }
    fn read_cpp_include(&mut self) {
        // this will be a function
        let mut filename = String::new();
        if self.skip("<") {
            while !self.peek_char_is('>') {
                filename.push(*self.peek_get().ok_or("error").unwrap());
                self.peek_next();
            }
            self.peek_next();
        }
        let real_filename = match self.cpp_try_include(filename.as_str()) {
            Some(f) => f,
            _ => {
                println!("error: {}: not found '{}'", self.cur_line, filename);
                process::exit(-1)
            }
        };
        println!("include filename: {}", real_filename);
        let mut file = OpenOptions::new()
            .read(true)
            .open(real_filename.to_string())
            .unwrap();
        let mut body = String::new();
        file.read_to_string(&mut body);
        let mut lexer = Lexer::new(filename, body.as_str());
        loop {
            let t = lexer.get();
            match t {
                Some(tok) => self.buf.push_back(tok),
                None => break,
            }
        }
        println!("end of: {}", real_filename);
    }

    fn read_cpp_define(&mut self) {
        let mcro = self.do_read_token().unwrap();
        assert_eq!(mcro.kind, TokenKind::Identifier);

        if self.skip("(") {
            error::error_exit(self.cur_line, "unsupported");
        }

        println!("macro name: {}", mcro.val);

        let mut body: Vec<Token> = Vec::new();
        print!("macro body: ");
        loop {
            let c = self.do_read_token().unwrap();
            if c.kind == TokenKind::Newline {
                break;
            }
            print!("{}{}", if c.space { " " } else { "" }, c.val);
            body.push(c);
        }
        println!();
    }
}
<commit_msg>a little impl of macro<commit_after>use std::io::{BufRead, BufReader};
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::str;
use std::collections::VecDeque;
use std::path;
use std::process;
use std::collections::HashMap;
use error;

enum Macro {
    Object(Vec<Token>),
    // FuncLile()
}

#[derive(PartialEq, Debug)]
pub enum TokenKind {
    Identifier,
    IntNumber,
    FloatNumber,
    String,
    Char,
    Symbol,
    Newline,
}

pub struct Token {
    pub kind: TokenKind,
    pub space: bool, // leading space
    pub val: String,
    pub line: i32,
}

impl Token {
    pub fn new(kind: TokenKind, val: &str, line: i32) -> Token {
        Token {
            kind: kind,
            space: false,
            val: val.to_string(),
            line: line,
        }
    }
}

pub struct Lexer<'a> {
    cur_line: i32,
    filename: String,
    peek: iter::Peekable<str::Chars<'a>>,
    peek_buf: VecDeque<char>,
    buf: VecDeque<Token>,
    macro_map: HashMap<String, Macro>,
}

impl<'a> Lexer<'a> {
    pub fn new(filename: String, input: &'a str) -> Lexer<'a> {
        Lexer {
            cur_line: 1,
            filename: filename.to_string(),
            peek: input.chars().peekable(),
            peek_buf: VecDeque::new(),
            buf: VecDeque::new(),
            macro_map: HashMap::new(),
        }
    }
    pub fn get_filename(self) -> String {
        self.filename
    }
    fn peek_get(&mut self) -> Option<&char> {
        if self.peek_buf.len() > 0 {
            self.peek_buf.front()
        } else {
            self.peek.peek()
        }
    }
    fn peek_next(&mut self) -> char {
        if self.peek_buf.len() > 0 {
            self.peek_buf.pop_front().unwrap()
        } else {
            self.peek.next().unwrap()
        }
    }
    fn peek_unget(&mut self, ch: char) {
        self.peek_buf.push_back(ch);
    }
    fn peek_next_char_is(&mut self, ch: char) -> bool {
        let c = self.peek_next();
        let nextc = self.peek_next();
        self.peek_unget(c);
        self.peek_unget(nextc);
        nextc == ch
    }
    fn peek_char_is(&mut self, ch: char) -> bool {
        let line = self.cur_line;
        let errf = || -> Option<&char> {
            error::error_exit(line, format!("expected '{}'", ch).as_str());
            None
        };

        let peekc = self.peek_get().or_else(errf).unwrap();
        *peekc == ch
    }

    fn skip(&mut self, s: &str) -> bool {
        let next = self.read_token();
        let n = next.ok_or("error").unwrap();
        if n.val == s && n.kind != TokenKind::String && n.kind != TokenKind::Char {
            true
        } else {
            self.buf.push_back(n);
            false
        }
    }
    fn unget(&mut self, t: Token) {
        self.buf.push_back(t);
    }

    pub fn read_identifier(&mut self) -> Token {
        let mut ident = String::new();
        loop {
            match self.peek_get() {
                Some(&c) => {
                    match c {
                        'a'...'z' | 'A'...'Z' | '_' | '0'...'9' => ident.push(c),
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek_next();
        }
        Token::new(TokenKind::Identifier, ident.as_str(), self.cur_line)
    }
    fn read_number_literal(&mut self) -> Token {
        let mut num = String::new();
        let mut is_float = false;
        loop {
            match self.peek_get() {
                Some(&c) => {
                    match c {
                        '.' | '0'...'9' => {
                            num.push(c);
                            if c == '.' {
                                is_float = true;
                            }
                        }
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek_next();
        }
        if is_float {
            Token::new(TokenKind::FloatNumber, num.as_str(), self.cur_line)
        } else {
            Token::new(TokenKind::IntNumber, num.as_str(), self.cur_line)
        }
    }
    pub fn read_newline(&mut self) -> Token {
        self.peek_next();
        Token::new(TokenKind::Newline, "", self.cur_line)
    }
    pub fn read_symbol(&mut self) -> Token {
        let c = self.peek_next();
        let mut sym = String::new();
        sym.push(c);
        match c {
            '+' | '-' | '*' | '/' | '%' | '=' | '^' | '!' => {
                if self.peek_char_is('=') {
                    sym.push(self.peek_next());
                }
            }
            '<' | '>' | '&' | '|' => {
                if self.peek_char_is(c) {
                    sym.push(self.peek_next());
                }
                if self.peek_char_is('=') {
                    sym.push(self.peek_next());
                }
            }
            '.' => {
                if self.peek_char_is('.') && self.peek_next_char_is('.') {
                    sym.push(self.peek_next());
                    sym.push(self.peek_next());
                }
            }
            _ => {}
        };
        Token::new(TokenKind::Symbol, sym.as_str(), self.cur_line)
    }
    fn read_string_literal(&mut self) -> Token {
        self.peek_next();
        let mut s = String::new();
        while !self.peek_char_is('\"') {
            s.push(self.peek_next());
        }
        self.peek_next();
        Token::new(TokenKind::String, s.as_str(), self.cur_line)
    }
    fn read_char_literal(&mut self) -> Token {
        self.peek_next();
        let mut s = String::new();
        while !self.peek_char_is('\'') {
            s.push(self.peek_next());
        }
        self.peek_next();
        Token::new(TokenKind::Char, s.as_str(), self.cur_line)
    }

    pub fn do_read_token(&mut self) -> Option<Token> {
        if !self.buf.is_empty() {
            return self.buf.pop_front();
        }

        match self.peek_get() {
            Some(&c) => {
                match c {
                    'a'...'z' | 'A'...'Z' | '_' => Some(self.read_identifier()),
                    ' ' | '\t' => {
                        self.peek_next();
                        // set a leading space
                        fn f(tok: Token) -> Option<Token> {
                            let mut t = tok;
                            t.space = true;
                            Some(t)
                        }
                        self.read_token().and_then(f)
                    }
                    '0'...'9' => Some(self.read_number_literal()),
                    '\"' => Some(self.read_string_literal()),
                    '\'' => Some(self.read_char_literal()),
                    '\n' => Some(self.read_newline()),
                    '\\' => {
                        self.peek_next();
                        self.read_token()
                    }
                    '/' => {
                        if self.peek_next_char_is('*') {
                            self.peek_next(); // /
                            self.peek_next(); // *
                            while !(self.peek_char_is('*') && self.peek_next_char_is('/')) {
                                self.peek_next();
                            }
                            self.peek_next();
                            self.peek_next();
                            println!("{}", self.peek_get().unwrap());
                            self.do_read_token()
                        } else if self.peek_next_char_is('/') {
                            self.peek_next(); // /
                            self.peek_next(); // /
                            while !self.peek_char_is('\n') {
                                self.peek_next();
                            }
                            self.do_read_token()
                        } else {
                            Some(self.read_symbol())
                        }
                    }
                    _ => Some(self.read_symbol()),
                }
            }
            None => None as Option<Token>,
        }
    }
    pub fn read_token(&mut self) -> Option<Token> {
        let t = self.do_read_token();
        match t {
            Some(tok) => {
                match tok.kind {
                    TokenKind::Newline => self.read_token(),
                    _ => Some(tok),
                }
            }
            _ => t,
        }
    }

    pub fn get(&mut self) -> Option<Token> {
        let t = self.read_token();
        match t {
            Some(tok) => {
                if tok.val == "#" {
                    // preprocessor directive
                    self.read_cpp_directive();
                    self.get()
                } else {
                    Some(tok)
                }
            }
            _ => t,
        }
    }

    // for c preprocessor

    fn read_cpp_directive(&mut self) {
        let t = self.do_read_token(); // cpp directive
        match t.ok_or("error").unwrap().val.as_str() {
            "include" => self.read_cpp_include(),
            "define" => self.read_cpp_define(),
            _ => {}
        }
    }

    fn cpp_try_include(&mut self, filename: &str) -> Option<String> {
        let header_paths = vec!["./include/",
                                "/include/",
                                "/usr/include/",
                                "/usr/include/linux/",
                                "/usr/include/x86_64-linux-gnu/",
                                ""];
        let mut real_filename = String::new();
        let mut found = false;
        for header_path in header_paths {
            real_filename = format!("{}{}", header_path, filename);
            if path::Path::new(real_filename.as_str()).exists() {
                found = true;
                break;
            }
        }
        if found { Some(real_filename) } else { None }
    }
    fn read_cpp_include(&mut self) {
        // this will be a function
        let mut filename = String::new();
        if self.skip("<") {
            while !self.peek_char_is('>') {
                filename.push(*self.peek_get().ok_or("error").unwrap());
                self.peek_next();
            }
            self.peek_next();
        }
        let real_filename = match self.cpp_try_include(filename.as_str()) {
            Some(f) => f,
            _ => {
                println!("error: {}: not found '{}'", self.cur_line, filename);
                process::exit(-1)
            }
        };
        println!("include filename: {}", real_filename);
        let mut file = OpenOptions::new()
            .read(true)
            .open(real_filename.to_string())
            .unwrap();
        let mut body = String::new();
        file.read_to_string(&mut body);
        let mut lexer = Lexer::new(filename, body.as_str());
        loop {
            let t = lexer.get();
            match t {
                Some(tok) => self.buf.push_back(tok),
                None => break,
            }
        }
        // copying macros
        for (key, val) in lexer.macro_map {
            self.macro_map.insert(key, val);
        }
        println!("end of: {}", real_filename);
    }

    fn read_cpp_define(&mut self) {
        let mcro = self.do_read_token().unwrap();
        assert_eq!(mcro.kind, TokenKind::Identifier);

        // TODO: func like macro is unsupported now..
        if self.skip("(") {
            error::error_exit(self.cur_line, "unsupported");
        }

        println!("\tmacro name: {}", mcro.val);

        let mut body: Vec<Token> = Vec::new();
        print!("\tmacro body: ");
        loop {
            let c = self.do_read_token().unwrap();
            if c.kind == TokenKind::Newline {
                break;
            }
            print!("{}{}", if c.space { " " } else { "" }, c.val);
            body.push(c);
        }
        println!();
        self.macro_map.insert(mcro.val, Macro::Object(body));
    }
}
<|endoftext|>


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

use scanner::Scanner;
use regex::Regex;

const COMPARISON           : &'static str = r"^(==|!=|<>|<=?|>=?|contains)";
const SINGLE_STRING_LITERAL: &'static str = r"^'[^']*'";
const DOUBLE_STRING_LITERAL: &'static str = r#"^"[^"]*""#;
const NUMBER_LITERAL:        &'static str = r"^-?\d+(\.\d+)?";
const IDENTIFIER:            &'static str = r"^[a-zA-Z_][\w-]*\??";
const RANGE_OP:              &'static str = r"^\.\.";

#[derive(Clone, Debug, PartialEq)]
pub enum Token {
    Comparison(String),
    Identifier(String),
    Number(String),
    String(String),
    Range(String),
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash
}

macro_rules! token {
    (Comparison   => $e:expr) => (Token::Comparison(String::from($e)));
    (Identifier   => $e:expr) => (Token::Identifier(String::from($e)));
    (Number       => $e:expr) => (Token::Number(String::from($e)));
    (String       => $e:expr) => (Token::String(String::from($e)));
    (Range)       => (Token::Range("..".into()));
    (Pipe)        => (Token::Pipe);
    (Dot)         => (Token::Dot);
    (Colon)       => (Token::Colon);
    (Comma)       => (Token::Comma);
    (OpenSquare)  => (Token::OpenSquare);
    (CloseSquare) => (Token::CloseSquare);
    (OpenRound)   => (Token::OpenRound);
    (CloseRound)  => (Token::CloseRound);
    (Question)    => (Token::Question);
    (Dash)        => (Token::Dash);
}

pub struct Tokens<'t> {
    scanner: &'t Scanner<'t>,
    specials: HashMap<&'t str, Token>,
    matchers: Vec<Regex>
}

impl<'t> Tokens<'t> {
    fn new<'a>(scanner: &'a Scanner<'a>) -> Tokens<'a> {
        let mut specials = HashMap::new();
        specials.insert("|", Token::Pipe);
        specials.insert(".", Token::Dot);
        specials.insert(":", Token::Colon);
        specials.insert(",", Token::Comma);
        specials.insert("[", Token::OpenSquare);
        specials.insert("]", Token::CloseSquare);
        specials.insert("(", Token::OpenRound);
        specials.insert(")", Token::CloseRound);
        specials.insert("?", Token::Question);
        specials.insert("-", Token::Dash);

        let matchers = vec![
            Regex::new(COMPARISON).unwrap(),
            Regex::new(SINGLE_STRING_LITERAL).unwrap(),
            Regex::new(DOUBLE_STRING_LITERAL).unwrap(),
            Regex::new(NUMBER_LITERAL).unwrap(),
            Regex::new(IDENTIFIER).unwrap(),
            Regex::new(RANGE_OP).unwrap()
        ];

        Tokens { scanner: scanner, specials: specials, matchers: matchers }
    }

    fn token_for(&self, pattern: &Regex, value: &str) -> Token {
        match pattern.as_str() {
            COMPARISON            => token!(Comparison => value),
            SINGLE_STRING_LITERAL => token!(String => value),
            DOUBLE_STRING_LITERAL => token!(String => value),
            NUMBER_LITERAL        => token!(Number => value),
            IDENTIFIER            => token!(Identifier => value),
            RANGE_OP              => token!(Range),
            _                     => unreachable!() // already been checked for existence
        }
    }

    fn next_match(&self) -> Option<Token> {
        match self.matchers.iter().find(|&m| self.scanner.check(m)) {
            Some(regex) => self.matched_token(&regex),
            None => self.matched_special()
        }
    }

    fn matched_token(&self, pattern: &Regex) -> Option<Token> {
        let value = self.scanner.scan(pattern).unwrap();
        Some(self.token_for(pattern, value))
    }

    fn matched_special(&self) -> Option<Token> {
        match self.scanner.get_char() {
            Some(character) => {
                match self.specials.get(character) {
                    Some(token) => Some((*token).clone()),
                    None => unreachable!("Syntax Error")
                }
            },
            None => None
        }
    }
}

impl<'t> Iterator for Tokens<'t> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_match()
    }
}

pub struct Lexer<'t> {
    scanner: Scanner<'t>
}

impl<'t> Lexer<'t> {
    pub fn new<'a>(source: &'a str) -> Lexer<'a> {
        Lexer { scanner: Scanner::new(source) }
    }

    pub fn tokens(&self) -> Tokens {
        Tokens::new(&self.scanner)
    }
}

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

    #[test]
    fn new_creates_a_new_instance() {
        let lexer = Lexer::new("doSomthing | filter");
        assert_eq!("doSomthing | filter", lexer.scanner.rest().unwrap());
    }

    #[test]
    fn tokens_when_given_a_blank_string() {
        let lexer              = Lexer::new("");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_when_given_a_whitespace_only_string() {
        let lexer              = Lexer::new("  \t \n\r ");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_parses_identifiers() {
        let lexer              = Lexer::new("high five?");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "high"), tokens[0]);
        assert_eq!(token!(Identifier => "five?"), tokens[1]);
    }

    #[test]
    fn tokens_knows_that_identifiers_dont_start_with_numbers() {
        let lexer              = Lexer::new("2foo 5.0bar");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(4, tokens.len());
        assert_eq!(token!(Number => "2"), tokens[0]);
        assert_eq!(token!(Identifier => "foo"), tokens[1]);
        assert_eq!(token!(Number => "5.0"), tokens[2]);
        assert_eq!(token!(Identifier => "bar"), tokens[3]);
    }

    #[test]
    fn tokens_parses_string_literals() {
        let lexer              = Lexer::new(r#" 'this is a test""' "wat 'lol'" "#);
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(String => r#"'this is a test""'"#), tokens[0]);
        assert_eq!(token!(String => r#""wat 'lol'""#), tokens[1]);
    }

    #[test]
    fn tokens_parses_integers() {
        let lexer              = Lexer::new("hi 50");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "hi"), tokens[0]);
        assert_eq!(token!(Number => "50"), tokens[1]);
    }

    #[test]
    fn tokens_parses_floats() {
        let lexer              = Lexer::new("hi 5.0");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "hi"), tokens[0]);
        assert_eq!(token!(Number => "5.0"), tokens[1]);
    }

    #[test]
    fn tokens_parses_comparisons() {
        let lexer              = Lexer::new("== <> contains");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Comparison => "=="), tokens[0]);
        assert_eq!(token!(Comparison => "<>"), tokens[1]);
        assert_eq!(token!(Comparison => "contains"), tokens[2]);
    }

    #[test]
    fn tokens_parses_range_operator() {
        let lexer              = Lexer::new("1..10");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Number => "1"), tokens[0]);
        assert_eq!(token!(Range), tokens[1]);
        assert_eq!(token!(Number => "10"), tokens[2]);
    }

    #[test]
    fn tokens_parses_special_characters() {
        let lexer              = Lexer::new("[hi], (| .:) - ?cool");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(12, tokens.len());
        assert_eq!(token!(OpenSquare), tokens[0]);
        assert_eq!(token!(Identifier => "hi"), tokens[1]);
        assert_eq!(token!(CloseSquare), tokens[2]);
        assert_eq!(token!(Comma), tokens[3]);
        assert_eq!(token!(OpenRound), tokens[4]);
        assert_eq!(token!(Pipe), tokens[5]);
        assert_eq!(token!(Dot), tokens[6]);
        assert_eq!(token!(Colon), tokens[7]);
        assert_eq!(token!(CloseRound), tokens[8]);
        assert_eq!(token!(Dash), tokens[9]);
        assert_eq!(token!(Question), tokens[10]);
        assert_eq!(token!(Identifier => "cool"), tokens[11]);
    }

    #[test]
    fn tokens_skips_internal_whitespace() {
        let lexer              = Lexer::new("five|\n\t  ==");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Identifier => "five"), tokens[0]);
        assert_eq!(token!(Pipe), tokens[1]);
        assert_eq!(token!(Comparison => "=="), tokens[2]);
    }

    #[test]
    #[should_panic(expected = "Syntax Error")]
    fn tokens_freaks_out_with_syntax_error() {
        let lexer              = Lexer::new("%");
        let tokens: Vec<Token> = lexer.tokens().collect();
    }
}
<commit_msg>cleaning up the token! macro<commit_after>use std::collections::HashMap;

use scanner::Scanner;
use regex::Regex;

const COMPARISON           : &'static str = r"^(==|!=|<>|<=?|>=?|contains)";
const SINGLE_STRING_LITERAL: &'static str = r"^'[^']*'";
const DOUBLE_STRING_LITERAL: &'static str = r#"^"[^"]*""#;
const NUMBER_LITERAL:        &'static str = r"^-?\d+(\.\d+)?";
const IDENTIFIER:            &'static str = r"^[a-zA-Z_][\w-]*\??";
const RANGE_OP:              &'static str = r"^\.\.";

#[derive(Clone, Debug, PartialEq)]
pub enum Token {
    Comparison(String),
    Identifier(String),
    Number(String),
    String(String),
    Range(String),
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash
}

macro_rules! token {
    (Range)               => (token!(Range, ".."));
    ($e:ident)            => (Token::$e);
    ($e:ident, $str:expr) => (Token::$e(String::from($str)))
}

pub struct Tokens<'t> {
    scanner: &'t Scanner<'t>,
    specials: HashMap<&'t str, Token>,
    matchers: Vec<Regex>
}

impl<'t> Tokens<'t> {
    fn new<'a>(scanner: &'a Scanner<'a>) -> Tokens<'a> {
        let mut specials = HashMap::new();
        specials.insert("|", Token::Pipe);
        specials.insert(".", Token::Dot);
        specials.insert(":", Token::Colon);
        specials.insert(",", Token::Comma);
        specials.insert("[", Token::OpenSquare);
        specials.insert("]", Token::CloseSquare);
        specials.insert("(", Token::OpenRound);
        specials.insert(")", Token::CloseRound);
        specials.insert("?", Token::Question);
        specials.insert("-", Token::Dash);

        let matchers = vec![
            Regex::new(COMPARISON).unwrap(),
            Regex::new(SINGLE_STRING_LITERAL).unwrap(),
            Regex::new(DOUBLE_STRING_LITERAL).unwrap(),
            Regex::new(NUMBER_LITERAL).unwrap(),
            Regex::new(IDENTIFIER).unwrap(),
            Regex::new(RANGE_OP).unwrap()
        ];

        Tokens { scanner: scanner, specials: specials, matchers: matchers }
    }

    fn token_for(&self, pattern: &Regex, value: &str) -> Token {
        match pattern.as_str() {
            COMPARISON            => token!(Comparison, value),
            SINGLE_STRING_LITERAL => token!(String, value),
            DOUBLE_STRING_LITERAL => token!(String, value),
            NUMBER_LITERAL        => token!(Number, value),
            IDENTIFIER            => token!(Identifier, value),
            RANGE_OP              => token!(Range),
            _                     => unreachable!() // already been checked for existence
        }
    }

    fn next_match(&self) -> Option<Token> {
        match self.matchers.iter().find(|&m| self.scanner.check(m)) {
            Some(regex) => self.matched_token(&regex),
            None => self.matched_special()
        }
    }

    fn matched_token(&self, pattern: &Regex) -> Option<Token> {
        let value = self.scanner.scan(pattern).unwrap();
        Some(self.token_for(pattern, value))
    }

    fn matched_special(&self) -> Option<Token> {
        match self.scanner.get_char() {
            Some(character) => {
                match self.specials.get(character) {
                    Some(token) => Some((*token).clone()),
                    None => unreachable!("Syntax Error")
                }
            },
            None => None
        }
    }
}

impl<'t> Iterator for Tokens<'t> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_match()
    }
}

pub struct Lexer<'t> {
    scanner: Scanner<'t>
}

impl<'t> Lexer<'t> {
    pub fn new<'a>(source: &'a str) -> Lexer<'a> {
        Lexer { scanner: Scanner::new(source) }
    }

    pub fn tokens(&self) -> Tokens {
        Tokens::new(&self.scanner)
    }
}

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

    #[test]
    fn new_creates_a_new_instance() {
        let lexer = Lexer::new("doSomthing | filter");
        assert_eq!("doSomthing | filter", lexer.scanner.rest().unwrap());
    }

    #[test]
    fn tokens_when_given_a_blank_string() {
        let lexer              = Lexer::new("");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_when_given_a_whitespace_only_string() {
        let lexer              = Lexer::new("  \t \n\r ");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_parses_identifiers() {
        let lexer              = Lexer::new("high five?");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier, "high"), tokens[0]);
        assert_eq!(token!(Identifier, "five?"), tokens[1]);
    }

    #[test]
    fn tokens_knows_that_identifiers_dont_start_with_numbers() {
        let lexer              = Lexer::new("2foo 5.0bar");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(4, tokens.len());
        assert_eq!(token!(Number, "2"), tokens[0]);
        assert_eq!(token!(Identifier, "foo"), tokens[1]);
        assert_eq!(token!(Number, "5.0"), tokens[2]);
        assert_eq!(token!(Identifier, "bar"), tokens[3]);
    }

    #[test]
    fn tokens_parses_string_literals() {
        let lexer              = Lexer::new(r#" 'this is a test""' "wat 'lol'" "#);
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(String, r#"'this is a test""'"#), tokens[0]);
        assert_eq!(token!(String, r#""wat 'lol'""#), tokens[1]);
    }

    #[test]
    fn tokens_parses_integers() {
        let lexer              = Lexer::new("hi 50");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier, "hi"), tokens[0]);
        assert_eq!(token!(Number, "50"), tokens[1]);
    }

    #[test]
    fn tokens_parses_floats() {
        let lexer              = Lexer::new("hi 5.0");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier, "hi"), tokens[0]);
        assert_eq!(token!(Number, "5.0"), tokens[1]);
    }

    #[test]
    fn tokens_parses_comparisons() {
        let lexer              = Lexer::new("== <> contains");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Comparison, "=="), tokens[0]);
        assert_eq!(token!(Comparison, "<>"), tokens[1]);
        assert_eq!(token!(Comparison, "contains"), tokens[2]);
    }

    #[test]
    fn tokens_parses_range_operator() {
        let lexer              = Lexer::new("1..10");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Number, "1"), tokens[0]);
        assert_eq!(token!(Range), tokens[1]);
        assert_eq!(token!(Number, "10"), tokens[2]);
    }

    #[test]
    fn tokens_parses_special_characters() {
        let lexer              = Lexer::new("[hi], (| .:) - ?cool");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(12, tokens.len());
        assert_eq!(token!(OpenSquare), tokens[0]);
        assert_eq!(token!(Identifier, "hi"), tokens[1]);
        assert_eq!(token!(CloseSquare), tokens[2]);
        assert_eq!(token!(Comma), tokens[3]);
        assert_eq!(token!(OpenRound), tokens[4]);
        assert_eq!(token!(Pipe), tokens[5]);
        assert_eq!(token!(Dot), tokens[6]);
        assert_eq!(token!(Colon), tokens[7]);
        assert_eq!(token!(CloseRound), tokens[8]);
        assert_eq!(token!(Dash), tokens[9]);
        assert_eq!(token!(Question), tokens[10]);
        assert_eq!(token!(Identifier, "cool"), tokens[11]);
    }

    #[test]
    fn tokens_skips_internal_whitespace() {
        let lexer              = Lexer::new("five|\n\t  ==");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Identifier, "five"), tokens[0]);
        assert_eq!(token!(Pipe), tokens[1]);
        assert_eq!(token!(Comparison, "=="), tokens[2]);
    }

    #[test]
    #[should_panic(expected = "Syntax Error")]
    fn tokens_freaks_out_with_syntax_error() {
        let lexer              = Lexer::new("%");
        let tokens: Vec<Token> = lexer.tokens().collect();
    }
}
<|endoftext|>