<commit_before>extern crate rand;

pub mod macaroni {
    use rand;
    use std::collections::HashMap;
    use std::io;
    use std::rc::Rc;

    const DIGITS: &'static [u8] = b"0123456789";
    const EPSILON: f64 = 0.000001;
    const PRECISION: i32 = 10;

    #[derive(Clone)]
    pub enum Val {
        Num(f64),
        Arr(Vec<Val>)
    }

    use std::fmt;
    impl fmt::Debug for Val {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match self {
                &Val::Num(n) => write!(f, "{}", n),
                &Val::Arr(ref a) => write!(f, "{:?}", a)
            }
        }
    }

    #[derive(Clone)]
    struct Variable {
        val: Val,
        var: Option<String>
    }

    impl Variable {
        fn by_name(name: String) -> Variable {
            Variable { val: Val::Num(0f64), var: Some(name) }
        }
        fn new_num(n: f64) -> Variable {
            Variable { val: Val::Num(n), var: None }
        }
        fn new_arr(a: Vec<Val>) -> Variable {
            Variable { val: Val::Arr(a), var: None }
        }
    }

    #[derive(Clone)]
    enum Token {
        Var(Variable),
        Op { func: Rc<Fn(&[Variable]) -> Option<Variable>>, arity: usize },
        Label(String),
        Goto(String),
        Set(String)
    }

    pub struct Macaroni {
        vars: HashMap<String, Val>
    }

    impl Macaroni {
        pub fn new() -> Macaroni {
            Macaroni { vars: HashMap::<String, Val>::new() }
        }

        pub fn run(&mut self, code: String) -> Option<Val> {
            let tokens = self.tokenize(code);
            self.run_tokens(&tokens)
        }

        fn tokenize(&self, code: String) -> Vec<Token> {
            let mut tokens = Vec::<String>::new();
            let mut token = String::new();
            for ch in code.chars() {
                if token.starts_with("\"") {
                    token.push(ch);
                    if ch == '"' {
                        tokens.push(token);
                        token = String::new();
                    }
                } else { match ch {
                    'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | '-' => {
                        token.push(ch);
                    },
                    ' ' | '\n' | '\t' => {
                        if !token.is_empty() {
                            tokens.push(token);
                            token = String::new();
                        }
                    },
                    '"' | '/' | '\\' | ':' => {
                        if token.is_empty() {
                            token.push(ch);
                        } else {
                            panic!("unexpected {}", token);
                        }
                    },
                    _ => { panic!("unrecognized char {}", ch); }
                } }
            }
            if !token.is_empty() { tokens.push(token); }
            tokens.iter().map(|t|
                if t.chars().all(|ch| ch.is_digit(10) || ch == '-') {
                    Token::Var(Variable::new_num(t.parse::<f64>().unwrap()))
                } else { match t.chars().next().unwrap() {
                    '"' => {
                        Token::Var(Variable::new_arr(Macaroni::string_to_arr(
                            &t[1..t.len() - 1].to_string())))
                    },
                    '/' => {
                        Token::Label(t[1..t.len()].to_string())
                    },
                    '\\' => {
                        Token::Goto(t[1..t.len()].to_string())
                    },
                    ':' => {
                        Token::Set(t[1..t.len()].to_string())
                    },
                    _ => { match &t[..] {
                        "add" => Token::Op {
                            func: Rc::new(Macaroni::add), arity: 2
                        },
                        "multiply" => Token::Op {
                            func: Rc::new(Macaroni::multiply), arity: 2
                        },
                        "floor" => Token::Op {
                            func: Rc::new(Macaroni::floor), arity: 1
                        },
                        "pow" => Token::Op {
                            func: Rc::new(Macaroni::pow), arity: 2
                        },
                        "tobase" => Token::Op {
                            func: Rc::new(Macaroni::tobase), arity: 2
                        },
                        "concat" => Token::Op {
                            func: Rc::new(Macaroni::concat), arity: 2
                        },
                        "wrap" => Token::Op {
                            func: Rc::new(Macaroni::wrap), arity: 1
                        },
                        "print" => Token::Op {
                            func: Rc::new(Macaroni::print), arity: 1
                        },
                        "read" => Token::Op {
                            func: Rc::new(Macaroni::read), arity: 0
                        },
                        "rand" => Token::Op {
                            func: Rc::new(Macaroni::rand), arity: 0
                        },
                        _ => Token::Var(Variable::by_name(t.clone()))
                    } }
                } }).collect::<Vec<Token>>()
        }

        fn run_tokens(&mut self, program: &[Token]) -> Option<Val> {
            let mut label_addrs: HashMap<String, usize> = HashMap::new();
            let mut i: usize = 0;
            let mut to_set: Option<String> = None;
            let mut last_val: Option<Val> = None;
            while let Some(t) = program.get(i) {
                match t {
                    &Token::Set(ref var_name) => {
                        to_set = Some(var_name.clone());
                        i += 1;
                        continue;
                    },
                    &Token::Op { .. } => {
                        last_val = self.execute_op(&program, &mut i)
                            .map(|x| x.val);
                    },
                    &Token::Label(ref label) => {
                        label_addrs.entry(label.clone()).or_insert(i);
                        i += 1;
                    },
                    &Token::Goto(ref label) => {
                        i = label_addrs.entry(label.clone())
                            .or_insert_with(||
                                self.find_label(program, label, i)
                                    .expect(&format!("{:#08x}: is a GOTO to \
                                                     label {:?}, which does \
                                                     not exist", i, label)[..])
                            ).clone();
                    },
                    &Token::Var(ref v) => {
                        last_val = Some(self.uv(v).val.clone());
                        i += 1;
                    }
                }
                if let Some(ref var_name) = to_set {
                    self.vars.insert(var_name.clone(), last_val.expect(
                        &format!("{:08x}: cannot set to null", i)));
                    last_val = None;
                }
                to_set = None;
            }
            last_val
        }

        fn execute_op(&self, program: &[Token], i: &mut usize) -> Option<Variable> {
            let (func, arity) = match program.get(i.clone()) {
                Some(&Token::Op { ref func, arity }) => (func, arity),
                Some(_) => panic!("Macaroni::execute_op() called on {:#08x}, \
                                  but instruction is not OP", i),
                None => panic!("Macaroni::execute_op() called on out-of-bounds \
                               index {:#08x}", i)
            };
            *i += 1;
            let mut args: Vec<Variable> = Vec::with_capacity(arity);
            while args.len() < arity {
                match program.get(i.clone()) {
                    Some(&Token::Var(ref v)) => {
                        args.push(self.uv(v));
                        *i += 1;
                    },
                    Some(&Token::Op { .. }) => {
                        match self.execute_op(program, i) {
                            Some(v) => args.push(v),
                            None => panic!("nested OP ending before {:#08x} \
                                           returned nothing", i)
                        }
                    }
                    Some(_) => panic!("{:#08x} is not valid as an OP argument; \
                                      it should be a VAR or an OP", i),
                    None => panic!("{:#08x}: expected OP argument (VAR or OP); \
                                   found end of program", i)
                }
            }
            func(&args[..])
        }

        /// Updates the `val` part of a variable, when `var` is Some().
        fn uv(&self, v: &Variable) -> Variable {
            if let Some(ref var_name) = v.var {
                Variable {
                    val: self.vars.get(var_name)
                        .map_or(Val::Num(0f64), |x| x.clone()),
                    var: v.var.clone()
                }
            } else { v.clone() }
        }

        /// Searches the program for the specified label. Returns the position
        /// of the label in the program, or `None` if it was not found.
        ///
        /// `index` merely specifies a starting point. The entire `program`
        /// is always searched, starting at `index` and wrapping around
        /// if necessary.
        ///
        /// # Examples
        ///
        /// ```
        /// use Token::*;
        ///
        /// let print_func = Box::new(|s| println!("{}", s));
        /// let program = vec![
        ///     Label(String::from("loop")),
        ///     Op({ func: print, arity: 1 }),
        ///     Variable(String::from("Hello, world!")),
        ///     Goto(String::from("loop"))
        /// ];
        /// assert_eq!(find_label(program, String::from("loop"), 0), Some(0));
        /// assert_eq!(find_label(program, String::from("cleanup"), 0), None);
        /// ```
        fn find_label(&self, program: &[Token], desired_label: &str,
                index: usize) -> Option<usize> {
            let enumerated = program.iter().enumerate();
            for (i, token) in enumerated.clone()
                                        .skip(index)
                                        .chain(enumerated.take(index)) {
                if let Token::Label(ref label) = *token {
                    if label == desired_label {
                        return Some(i);
                    }
                }
            }
            None
        }

        fn add(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("add called with Arr")
            } + match args[1].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("add called with Arr")
            }))
        }

        fn multiply(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("multiply called with Arr")
            } * match args[1].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("multiply called with Arr")
            }))
        }

        fn floor(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("floor called with Arr")
            }.floor()))
        }

        fn pow(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("pow called with Arr")
            }.powf(match args[1].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("pow called with Arr")
            })))
        }

        fn tobase(args: &[Variable]) -> Option<Variable> {
            match args[0].val { Val::Num(n) => {
                match args[1].val { Val::Num(m) => {
                    let (base, mut ipart, mut fpart) =
                        (m as i64, n.floor() as i64, n - n.floor());
                    let neg = ipart < 0;

                    // convert integer part
                    let mut nb = String::new();
                    while ipart != 0 {
                        nb.insert(0, DIGITS[(ipart % base) as usize] as char);
                        ipart /= base;
                    }

                    // handle negatives and zero (we must do this
                    // before converting float part)
                    if neg { nb.insert(0, '-'); }
                    if nb.is_empty() { nb.push('0'); }

                    // convert float part
                    if fpart > EPSILON {
                        nb.push('.');
                        for _ in 0..PRECISION {
                            if fpart <= EPSILON { break; }
                            fpart *= base as f64;
                            let digit = fpart.floor();
                            nb.push(DIGITS[digit as usize] as char);
                            fpart -= digit;
                        }
                    }

                    Some(Variable::new_arr(Macaroni::string_to_arr(&nb)))
                }, Val::Arr(_) => panic!("tobase called with Arr") }
            }, Val::Arr(_) => panic!("tobase called with Arr") }
        }

        fn concat(args: &[Variable]) -> Option<Variable> {
            let mut arr = match args[0].val {
                Val::Arr(ref a) => a,
                Val::Num(_) => panic!("concat called with Num")
            }.clone();
            arr.extend(match args[1].val {
                Val::Arr(ref a) => a,
                Val::Num(_) => panic!("concat called with Num")
            }.clone().into_iter());
            Some(Variable::new_arr(arr))
        }

        fn wrap(args: &[Variable]) -> Option<Variable> {
            let ref x = args[0];
            Some(Variable::new_arr(vec![x.val.clone()]))
        }

        fn print(args: &[Variable]) -> Option<Variable> {
            let ref x = args[0];
            print!("{}", match x.val {
                Val::Arr(ref s) => Macaroni::arr_to_string(s),
                Val::Num(_) => panic!("print called with Num")
            });
            None
        }

        fn read(_: &[Variable]) -> Option<Variable> {
            let mut line = String::new();
            io::stdin().read_line(&mut line).unwrap();
            Some(Variable::new_arr(Macaroni::string_to_arr(&line)))
        }

        fn rand(_: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(rand::random()))
        }

        fn arr_to_string(arr: &Vec<Val>) -> String {
            arr.iter().map(|x| match x {
                &Val::Num(n) => n,
                &Val::Arr(_) => panic!("arr_to_string called with non-string")
            } as u8 as char).collect::<String>()
        }

        fn string_to_arr(str: &String) -> Vec<Val> {
            str.chars().map(|c| Val::Num(c as u8 as f64)).collect()
        }
    }
}
<commit_msg>implement length<commit_after>extern crate rand;

pub mod macaroni {
    use rand;
    use std::collections::HashMap;
    use std::io;
    use std::rc::Rc;

    const DIGITS: &'static [u8] = b"0123456789";
    const EPSILON: f64 = 0.000001;
    const PRECISION: i32 = 10;

    #[derive(Clone)]
    pub enum Val {
        Num(f64),
        Arr(Vec<Val>)
    }

    use std::fmt;
    impl fmt::Debug for Val {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match self {
                &Val::Num(n) => write!(f, "{}", n),
                &Val::Arr(ref a) => write!(f, "{:?}", a)
            }
        }
    }

    #[derive(Clone)]
    struct Variable {
        val: Val,
        var: Option<String>
    }

    impl Variable {
        fn by_name(name: String) -> Variable {
            Variable { val: Val::Num(0f64), var: Some(name) }
        }
        fn new_num(n: f64) -> Variable {
            Variable { val: Val::Num(n), var: None }
        }
        fn new_arr(a: Vec<Val>) -> Variable {
            Variable { val: Val::Arr(a), var: None }
        }
    }

    #[derive(Clone)]
    enum Token {
        Var(Variable),
        Op { func: Rc<Fn(&[Variable]) -> Option<Variable>>, arity: usize },
        Label(String),
        Goto(String),
        Set(String)
    }

    pub struct Macaroni {
        vars: HashMap<String, Val>
    }

    impl Macaroni {
        pub fn new() -> Macaroni {
            Macaroni { vars: HashMap::<String, Val>::new() }
        }

        pub fn run(&mut self, code: String) -> Option<Val> {
            let tokens = self.tokenize(code);
            self.run_tokens(&tokens)
        }

        fn tokenize(&self, code: String) -> Vec<Token> {
            let mut tokens = Vec::<String>::new();
            let mut token = String::new();
            for ch in code.chars() {
                if token.starts_with("\"") {
                    token.push(ch);
                    if ch == '"' {
                        tokens.push(token);
                        token = String::new();
                    }
                } else { match ch {
                    'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | '-' => {
                        token.push(ch);
                    },
                    ' ' | '\n' | '\t' => {
                        if !token.is_empty() {
                            tokens.push(token);
                            token = String::new();
                        }
                    },
                    '"' | '/' | '\\' | ':' => {
                        if token.is_empty() {
                            token.push(ch);
                        } else {
                            panic!("unexpected {}", token);
                        }
                    },
                    _ => { panic!("unrecognized char {}", ch); }
                } }
            }
            if !token.is_empty() { tokens.push(token); }
            tokens.iter().map(|t|
                if t.chars().all(|ch| ch.is_digit(10) || ch == '-') {
                    Token::Var(Variable::new_num(t.parse::<f64>().unwrap()))
                } else { match t.chars().next().unwrap() {
                    '"' => {
                        Token::Var(Variable::new_arr(Macaroni::string_to_arr(
                            &t[1..t.len() - 1].to_string())))
                    },
                    '/' => {
                        Token::Label(t[1..t.len()].to_string())
                    },
                    '\\' => {
                        Token::Goto(t[1..t.len()].to_string())
                    },
                    ':' => {
                        Token::Set(t[1..t.len()].to_string())
                    },
                    _ => { match &t[..] {
                        "add" => Token::Op {
                            func: Rc::new(Macaroni::add), arity: 2
                        },
                        "multiply" => Token::Op {
                            func: Rc::new(Macaroni::multiply), arity: 2
                        },
                        "floor" => Token::Op {
                            func: Rc::new(Macaroni::floor), arity: 1
                        },
                        "pow" => Token::Op {
                            func: Rc::new(Macaroni::pow), arity: 2
                        },
                        "tobase" => Token::Op {
                            func: Rc::new(Macaroni::tobase), arity: 2
                        },
                        "concat" => Token::Op {
                            func: Rc::new(Macaroni::concat), arity: 2
                        },
                        "length" => Token::Op {
                            func: Rc::new(Macaroni::length), arity: 1
                        },
                        "wrap" => Token::Op {
                            func: Rc::new(Macaroni::wrap), arity: 1
                        },
                        "print" => Token::Op {
                            func: Rc::new(Macaroni::print), arity: 1
                        },
                        "read" => Token::Op {
                            func: Rc::new(Macaroni::read), arity: 0
                        },
                        "rand" => Token::Op {
                            func: Rc::new(Macaroni::rand), arity: 0
                        },
                        _ => Token::Var(Variable::by_name(t.clone()))
                    } }
                } }).collect::<Vec<Token>>()
        }

        fn run_tokens(&mut self, program: &[Token]) -> Option<Val> {
            let mut label_addrs: HashMap<String, usize> = HashMap::new();
            let mut i: usize = 0;
            let mut to_set: Option<String> = None;
            let mut last_val: Option<Val> = None;
            while let Some(t) = program.get(i) {
                match t {
                    &Token::Set(ref var_name) => {
                        to_set = Some(var_name.clone());
                        i += 1;
                        continue;
                    },
                    &Token::Op { .. } => {
                        last_val = self.execute_op(&program, &mut i)
                            .map(|x| x.val);
                    },
                    &Token::Label(ref label) => {
                        label_addrs.entry(label.clone()).or_insert(i);
                        i += 1;
                    },
                    &Token::Goto(ref label) => {
                        i = label_addrs.entry(label.clone())
                            .or_insert_with(||
                                self.find_label(program, label, i)
                                    .expect(&format!("{:#08x}: is a GOTO to \
                                                     label {:?}, which does \
                                                     not exist", i, label)[..])
                            ).clone();
                    },
                    &Token::Var(ref v) => {
                        last_val = Some(self.uv(v).val.clone());
                        i += 1;
                    }
                }
                if let Some(ref var_name) = to_set {
                    self.vars.insert(var_name.clone(), last_val.expect(
                        &format!("{:08x}: cannot set to null", i)));
                    last_val = None;
                }
                to_set = None;
            }
            last_val
        }

        fn execute_op(&self, program: &[Token], i: &mut usize) -> Option<Variable> {
            let (func, arity) = match program.get(i.clone()) {
                Some(&Token::Op { ref func, arity }) => (func, arity),
                Some(_) => panic!("Macaroni::execute_op() called on {:#08x}, \
                                  but instruction is not OP", i),
                None => panic!("Macaroni::execute_op() called on out-of-bounds \
                               index {:#08x}", i)
            };
            *i += 1;
            let mut args: Vec<Variable> = Vec::with_capacity(arity);
            while args.len() < arity {
                match program.get(i.clone()) {
                    Some(&Token::Var(ref v)) => {
                        args.push(self.uv(v));
                        *i += 1;
                    },
                    Some(&Token::Op { .. }) => {
                        match self.execute_op(program, i) {
                            Some(v) => args.push(v),
                            None => panic!("nested OP ending before {:#08x} \
                                           returned nothing", i)
                        }
                    }
                    Some(_) => panic!("{:#08x} is not valid as an OP argument; \
                                      it should be a VAR or an OP", i),
                    None => panic!("{:#08x}: expected OP argument (VAR or OP); \
                                   found end of program", i)
                }
            }
            func(&args[..])
        }

        /// Updates the `val` part of a variable, when `var` is Some().
        fn uv(&self, v: &Variable) -> Variable {
            if let Some(ref var_name) = v.var {
                Variable {
                    val: self.vars.get(var_name)
                        .map_or(Val::Num(0f64), |x| x.clone()),
                    var: v.var.clone()
                }
            } else { v.clone() }
        }

        /// Searches the program for the specified label. Returns the position
        /// of the label in the program, or `None` if it was not found.
        ///
        /// `index` merely specifies a starting point. The entire `program`
        /// is always searched, starting at `index` and wrapping around
        /// if necessary.
        ///
        /// # Examples
        ///
        /// ```
        /// use Token::*;
        ///
        /// let print_func = Box::new(|s| println!("{}", s));
        /// let program = vec![
        ///     Label(String::from("loop")),
        ///     Op({ func: print, arity: 1 }),
        ///     Variable(String::from("Hello, world!")),
        ///     Goto(String::from("loop"))
        /// ];
        /// assert_eq!(find_label(program, String::from("loop"), 0), Some(0));
        /// assert_eq!(find_label(program, String::from("cleanup"), 0), None);
        /// ```
        fn find_label(&self, program: &[Token], desired_label: &str,
                index: usize) -> Option<usize> {
            let enumerated = program.iter().enumerate();
            for (i, token) in enumerated.clone()
                                        .skip(index)
                                        .chain(enumerated.take(index)) {
                if let Token::Label(ref label) = *token {
                    if label == desired_label {
                        return Some(i);
                    }
                }
            }
            None
        }

        fn add(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("add called with Arr")
            } + match args[1].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("add called with Arr")
            }))
        }

        fn multiply(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("multiply called with Arr")
            } * match args[1].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("multiply called with Arr")
            }))
        }

        fn floor(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("floor called with Arr")
            }.floor()))
        }

        fn pow(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("pow called with Arr")
            }.powf(match args[1].val {
                Val::Num(n) => n,
                Val::Arr(_) => panic!("pow called with Arr")
            })))
        }

        fn tobase(args: &[Variable]) -> Option<Variable> {
            match args[0].val { Val::Num(n) => {
                match args[1].val { Val::Num(m) => {
                    let (base, mut ipart, mut fpart) =
                        (m as i64, n.floor() as i64, n - n.floor());
                    let neg = ipart < 0;

                    // convert integer part
                    let mut nb = String::new();
                    while ipart != 0 {
                        nb.insert(0, DIGITS[(ipart % base) as usize] as char);
                        ipart /= base;
                    }

                    // handle negatives and zero (we must do this
                    // before converting float part)
                    if neg { nb.insert(0, '-'); }
                    if nb.is_empty() { nb.push('0'); }

                    // convert float part
                    if fpart > EPSILON {
                        nb.push('.');
                        for _ in 0..PRECISION {
                            if fpart <= EPSILON { break; }
                            fpart *= base as f64;
                            let digit = fpart.floor();
                            nb.push(DIGITS[digit as usize] as char);
                            fpart -= digit;
                        }
                    }

                    Some(Variable::new_arr(Macaroni::string_to_arr(&nb)))
                }, Val::Arr(_) => panic!("tobase called with Arr") }
            }, Val::Arr(_) => panic!("tobase called with Arr") }
        }

        fn concat(args: &[Variable]) -> Option<Variable> {
            let mut arr = match args[0].val {
                Val::Arr(ref a) => a,
                Val::Num(_) => panic!("concat called with Num")
            }.clone();
            arr.extend(match args[1].val {
                Val::Arr(ref a) => a,
                Val::Num(_) => panic!("concat called with Num")
            }.clone().into_iter());
            Some(Variable::new_arr(arr))
        }

        fn length(args: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(match args[0].val {
                Val::Arr(ref a) => a.len() as f64,
                Val::Num(_) => panic!("length called with Num")
            }))
        }

        fn wrap(args: &[Variable]) -> Option<Variable> {
            let ref x = args[0];
            Some(Variable::new_arr(vec![x.val.clone()]))
        }

        fn print(args: &[Variable]) -> Option<Variable> {
            let ref x = args[0];
            print!("{}", match x.val {
                Val::Arr(ref s) => Macaroni::arr_to_string(s),
                Val::Num(_) => panic!("print called with Num")
            });
            None
        }

        fn read(_: &[Variable]) -> Option<Variable> {
            let mut line = String::new();
            io::stdin().read_line(&mut line).unwrap();
            Some(Variable::new_arr(Macaroni::string_to_arr(&line)))
        }

        fn rand(_: &[Variable]) -> Option<Variable> {
            Some(Variable::new_num(rand::random()))
        }

        fn arr_to_string(arr: &Vec<Val>) -> String {
            arr.iter().map(|x| match x {
                &Val::Num(n) => n,
                &Val::Arr(_) => panic!("arr_to_string called with non-string")
            } as u8 as char).collect::<String>()
        }

        fn string_to_arr(str: &String) -> Vec<Val> {
            str.chars().map(|c| Val::Num(c as u8 as f64)).collect()
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int, c_short, c_void};

pub type chtype = u64; // chtypes 64 bits by default
pub type attr_t = chtype;
pub type PDCursesBool = u8;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct WINDOW {
    // definition of a window
    pub _cury: i32, // current pseudo-cursor
    pub _curx: i32,
    pub _maxy: i32, // max window coordinates
    pub _maxx: i32,
    pub _begy: i32, // origin on screen
    pub _begx: i32,
    pub _flags: i32, // window properties
    pub _attrs: chtype, // standard attributes and colors
    pub bkgd: chtype, // background, normally blank
    pub _clear: PDCursesBool, // causes clear at next refresh
    pub _leaveit: PDCursesBool, // leaves cursor where it is
    pub _scroll: PDCursesBool, // allows window scrolling
    pub _nodelay: PDCursesBool, // input character wait flag
    pub _immed: PDCursesBool, // immediate update flag
    pub _sync: PDCursesBool, // synchronise window ancestors
    pub _use_keypad: PDCursesBool, // flags keypad key mode active
    pub _y: *mut *mut chtype, // pointer to line pointer array
    pub _firstch: *mut i32, // first changed character in line
    pub _lastch: *mut i32, // last changed character in line
    pub _tmarg: i32, // top of scrolling region
    pub _bmarg: i32, // bottom of scrolling region
    pub _delayms: i32, // milliseconds of delay for getch()
    pub _parx: i32, // coords relative to parent (0,0)
    pub _pary: i32,
    pub _parent: *mut WINDOW, // subwin's pointer to parent win
}

#[link(name="pdcurses",kind="static")]
extern "C" {
    // ----------------------------------------------------------------------
    //
    //  PDCurses Function Declarations
    //
    //

    // Standard

    pub fn addch(_: chtype) -> c_int;
    pub fn addchnstr(_: *const chtype, _: c_int) -> c_int;
    pub fn addchstr(_: *const chtype) -> c_int;
    pub fn addnstr(_: *const c_char, _: c_int) -> c_int;
    pub fn addstr(_: *const c_char) -> c_int;
    pub fn attroff(_: chtype) -> c_int;
    pub fn attron(_: chtype) -> c_int;
    pub fn attrset(_: chtype) -> c_int;
    pub fn attr_get(_: *mut attr_t, _: *mut c_short, _: *mut c_void) -> c_int;
    pub fn attr_off(_: attr_t, _: *mut c_void) -> c_int;
    pub fn attr_on(_: attr_t, _: *mut c_void) -> c_int;
    pub fn attr_set(_: attr_t, _: c_short, _: *mut c_void) -> c_int;

    pub fn cbreak() -> c_int;
    pub fn echo() -> c_int;
    pub fn endwin() -> c_int;
    pub fn getch() -> c_int;
    pub fn initscr() -> *mut WINDOW;
    pub fn nocbreak() -> c_int;
    pub fn nodelay(_: *mut WINDOW, _: bool) -> c_int;
    pub fn printw(_: *const c_char) -> c_int;
    pub fn refresh() -> c_int;
    pub fn wgetch(_: *mut WINDOW) -> c_int;
}
<commit_msg>Added all the bindings for functions starting with 'b'<commit_after>extern crate libc;

use libc::{c_char, c_int, c_short, c_void};

pub type chtype = u64; // chtypes 64 bits by default
pub type attr_t = chtype;
pub type PDCursesBool = u8;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct WINDOW {
    // definition of a window
    pub _cury: i32, // current pseudo-cursor
    pub _curx: i32,
    pub _maxy: i32, // max window coordinates
    pub _maxx: i32,
    pub _begy: i32, // origin on screen
    pub _begx: i32,
    pub _flags: i32, // window properties
    pub _attrs: chtype, // standard attributes and colors
    pub bkgd: chtype, // background, normally blank
    pub _clear: PDCursesBool, // causes clear at next refresh
    pub _leaveit: PDCursesBool, // leaves cursor where it is
    pub _scroll: PDCursesBool, // allows window scrolling
    pub _nodelay: PDCursesBool, // input character wait flag
    pub _immed: PDCursesBool, // immediate update flag
    pub _sync: PDCursesBool, // synchronise window ancestors
    pub _use_keypad: PDCursesBool, // flags keypad key mode active
    pub _y: *mut *mut chtype, // pointer to line pointer array
    pub _firstch: *mut i32, // first changed character in line
    pub _lastch: *mut i32, // last changed character in line
    pub _tmarg: i32, // top of scrolling region
    pub _bmarg: i32, // bottom of scrolling region
    pub _delayms: i32, // milliseconds of delay for getch()
    pub _parx: i32, // coords relative to parent (0,0)
    pub _pary: i32,
    pub _parent: *mut WINDOW, // subwin's pointer to parent win
}

#[link(name="pdcurses",kind="static")]
extern "C" {
    // ----------------------------------------------------------------------
    //
    //  PDCurses Function Declarations
    //
    //

    // Standard

    pub fn addch(_: chtype) -> c_int;
    pub fn addchnstr(_: *const chtype, _: c_int) -> c_int;
    pub fn addchstr(_: *const chtype) -> c_int;
    pub fn addnstr(_: *const c_char, _: c_int) -> c_int;
    pub fn addstr(_: *const c_char) -> c_int;
    pub fn attroff(_: chtype) -> c_int;
    pub fn attron(_: chtype) -> c_int;
    pub fn attrset(_: chtype) -> c_int;
    pub fn attr_get(_: *mut attr_t, _: *mut c_short, _: *mut c_void) -> c_int;
    pub fn attr_off(_: attr_t, _: *mut c_void) -> c_int;
    pub fn attr_on(_: attr_t, _: *mut c_void) -> c_int;
    pub fn attr_set(_: attr_t, _: c_short, _: *mut c_void) -> c_int;

    pub fn baudrate() -> c_int;
    pub fn beep() -> c_int;
    pub fn bkgd(_: chtype) -> c_int;
    pub fn bkgdset(_: chtype);
    pub fn border(_: chtype,
                  _: chtype,
                  _: chtype,
                  _: chtype,
                  _: chtype,
                  _: chtype,
                  _: chtype,
                  _: chtype)
                  -> c_int;
    pub fn pdc_box(_: *mut WINDOW, _: chtype, _: chtype) -> c_int;

    pub fn cbreak() -> c_int;
    pub fn echo() -> c_int;
    pub fn endwin() -> c_int;
    pub fn getch() -> c_int;
    pub fn initscr() -> *mut WINDOW;
    pub fn nocbreak() -> c_int;
    pub fn nodelay(_: *mut WINDOW, _: bool) -> c_int;
    pub fn printw(_: *const c_char) -> c_int;
    pub fn refresh() -> c_int;
    pub fn wgetch(_: *mut WINDOW) -> c_int;
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::thread;

const LF: u8 = 10;
const CR: u8 = 13;
const QUOTE: u8 = 34;
const COMMA: u8 = 44;

// Error messages
pub const UNEXPECTED_EOL: &'static str = "Unexpected end of line";
pub const UNEXPECTED_CHAR: &'static str = "Unexpected character after quote";
pub const EXPECTED_LF: &'static str = "Expected linefeed after carriage return";

enum CSVState {
    Start,
    NonQuotedValue,
    QuotedValue,
    QuoteQuote,
    ExpectLF,
    Error,
}

type CSVResult = Result<CSVState, &'static str>;

type ByteParser = fn(u8) -> CSVResult;

#[derive(Debug, PartialEq, Eq)]
pub struct CSVError {
    pub line: i32,
    pub col: i32,
    pub text: &'static str,
}

fn parse_start(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_non_quoted(byte: u8) -> CSVResult {
    match byte {
        COMMA => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        LF => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_quoted(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuoteQuote),
        CR => Err(UNEXPECTED_EOL),
        LF => Err(UNEXPECTED_EOL),
        _ => Ok(CSVState::QuotedValue),
    }
}

fn parse_quote_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        LF => Ok(CSVState::Start),
        _ => Err(UNEXPECTED_CHAR),
    }
}

fn parse_cr(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Err(EXPECTED_LF),
    }
}

fn parse_err(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Ok(CSVState::Error),
    }
}

fn next_state(state: CSVState, byte: u8) -> CSVResult {
    let parse_fn: ByteParser = match state {
        CSVState::Start => parse_start,
        CSVState::NonQuotedValue => parse_non_quoted,
        CSVState::QuotedValue => parse_quoted,
        CSVState::QuoteQuote => parse_quote_quote,
        CSVState::ExpectLF => parse_cr,
        CSVState::Error => parse_err,
    };
    parse_fn(byte)
}

pub fn publish_errors_for_csv<T: Read + Send + 'static>(reader: T) -> Receiver<CSVError> {
    let (sender, receiver) = channel();

    thread::spawn(move || {
        let mut state = CSVState::Start;
        let mut line = 1;
        let mut col = 0;

        for b in reader.bytes() {
            let byte = b.unwrap();

            state = match next_state(state, byte) {
                Ok(new_state) => new_state,
                Err(error) => {
                    sender.send(CSVError {
                        line: line,
                        col: col,
                        text: error,
                    }).unwrap();
                    match error {
                        UNEXPECTED_EOL => CSVState::Start,
                        _ => CSVState::Error
                    }
                }
            };

            if byte == LF {
                line += 1;
                col = 0;
            } else {
                col += 1;
            }
        }
    });

    receiver
}
<commit_msg>Collapse matching arms<commit_after>use std::io::Read;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::thread;

const LF: u8 = 10;
const CR: u8 = 13;
const QUOTE: u8 = 34;
const COMMA: u8 = 44;

// Error messages
pub const UNEXPECTED_EOL: &'static str = "Unexpected end of line";
pub const UNEXPECTED_CHAR: &'static str = "Unexpected character after quote";
pub const EXPECTED_LF: &'static str = "Expected linefeed after carriage return";

enum CSVState {
    Start,
    NonQuotedValue,
    QuotedValue,
    QuoteQuote,
    ExpectLF,
    Error,
}

type CSVResult = Result<CSVState, &'static str>;

type ByteParser = fn(u8) -> CSVResult;

#[derive(Debug, PartialEq, Eq)]
pub struct CSVError {
    pub line: i32,
    pub col: i32,
    pub text: &'static str,
}

fn parse_start(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_non_quoted(byte: u8) -> CSVResult {
    match byte {
        COMMA | LF => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_quoted(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuoteQuote),
        CR | LF => Err(UNEXPECTED_EOL),
        _ => Ok(CSVState::QuotedValue),
    }
}

fn parse_quote_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA | LF => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        _ => Err(UNEXPECTED_CHAR),
    }
}

fn parse_cr(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Err(EXPECTED_LF),
    }
}

fn parse_err(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Ok(CSVState::Error),
    }
}

fn next_state(state: CSVState, byte: u8) -> CSVResult {
    let parse_fn: ByteParser = match state {
        CSVState::Start => parse_start,
        CSVState::NonQuotedValue => parse_non_quoted,
        CSVState::QuotedValue => parse_quoted,
        CSVState::QuoteQuote => parse_quote_quote,
        CSVState::ExpectLF => parse_cr,
        CSVState::Error => parse_err,
    };
    parse_fn(byte)
}

pub fn publish_errors_for_csv<T: Read + Send + 'static>(reader: T) -> Receiver<CSVError> {
    let (sender, receiver) = channel();

    thread::spawn(move || {
        let mut state = CSVState::Start;
        let mut line = 1;
        let mut col = 0;

        for b in reader.bytes() {
            let byte = b.unwrap();

            state = match next_state(state, byte) {
                Ok(new_state) => new_state,
                Err(error) => {
                    sender.send(CSVError {
                        line: line,
                        col: col,
                        text: error,
                    }).unwrap();
                    match error {
                        UNEXPECTED_EOL => CSVState::Start,
                        _ => CSVState::Error
                    }
                }
            };

            if byte == LF {
                line += 1;
                col = 0;
            } else {
                col += 1;
            }
        }
    });

    receiver
}
<|endoftext|>


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

#![feature(iter_arith, result_expect, path_ext, slice_bytes)]
#![warn(missing_docs)]

//! Melvin is pure Rust library for configuring [LVM](https://www.sourceware.org/lvm2/).

extern crate byteorder;
extern crate crc;
extern crate unix_socket;
extern crate nix;
extern crate libc;
extern crate uuid;
extern crate time;

pub mod parser;
pub mod lvmetad;
pub mod pvlabel;
pub mod dm;
pub mod lv;
pub mod vg;
pub mod pv;
mod util;
<commit_msg>Hide stuff in public API<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![feature(iter_arith, result_expect, path_ext, slice_bytes)]
#![warn(missing_docs)]

//! Melvin is pure Rust library for configuring [LVM](https://www.sourceware.org/lvm2/).

extern crate byteorder;
extern crate crc;
extern crate unix_socket;
extern crate nix;
extern crate libc;
extern crate uuid;
extern crate time;

pub mod dm;
pub mod parser;
mod lvmetad;
mod pvlabel;
mod lv;
mod vg;
mod pv;
mod util;

pub use pvlabel::{PvHeader, pvheader_scan};
pub use vg::VG;
pub use pv::PV;
pub use lv::LV;
pub use lvmetad::vg_list;
<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

//! Frippy is an IRC bot that runs plugins on each message
//! received.
//!
//! # Example
//! ```no_run
//! extern crate frippy;
//!
//! frippy::run();
//! ```

#[macro_use]
extern crate log;
#[macro_use]
extern crate plugin_derive;

extern crate irc;
extern crate tokio_core;
extern crate futures;
extern crate glob;

mod plugin;
mod plugins;

use std::thread::spawn;
use std::sync::{Arc, Mutex};
use glob::glob;

use irc::client::prelude::*;
use irc::proto::Command::PRIVMSG;
use irc::error::Error as IrcError;

use tokio_core::reactor::Core;
use futures::future;

use plugin::*;

// Lock the mutex and ignore if it is poisoned
macro_rules! lock_plugin {
    ($e:expr) => {
        match $e.lock() {
            Ok(plugin) => plugin,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

/// Runs the bot
///
/// # Remarks
///
/// This blocks the current thread while the bot is running
pub fn run() {

    // Load all toml files in the configs directory
    let mut configs = Vec::new();
    for toml in glob("configs/*.toml").unwrap() {
        match toml {
            Ok(path) => {
                info!("Loading {}", path.to_str().unwrap());
                match Config::load(path) {
                    Ok(v) => configs.push(v),
                    Err(e) => error!("Incorrect config file {}", e),
                }
            },
            Err(e) => error!("Failed to read path {}", e),
        }
    }

    // Without configs the bot would just idle
    if configs.is_empty() {
        error!("No config file found");
        return;
    }

    // The list of plugins in use
    let plugins: Vec<Arc<Mutex<Plugin>>> =
        vec![Arc::new(Mutex::new(plugins::emoji::Emoji::new())),
             Arc::new(Mutex::new(plugins::currency::Currency::new()))];

    // We need the plugins' names to make sure the user gets a response
    // if they use an incorrect plugin name
    let plugin_names: Vec<String> = plugins
        .iter()
        .map(|p| lock_plugin!(p).name().to_lowercase())
        .collect();

    info!("Plugins loaded: {}", plugin_names.join(", "));

    // Create an event loop to run the connections on.
    let mut reactor = Core::new().unwrap();

    // Open a connection and add work for each config
    for config in configs {
        let fut = IrcServer::new_future(reactor.handle(), &config).unwrap();

        let server = match reactor.run(fut) {
            Ok(v) => {
                info!("Connected to server");
                v
            }
            Err(e) => {
                error!("Failed to connect: {}", e);
                return;
            }
        };

        match server.identify() {
            Ok(_) => info!("Identified"),
            Err(e) => error!("Failed to identify: {}", e),
        };

        // TODO Duplicate clone...
        let plugins = plugins.clone();
        let plugin_names = plugin_names.clone();

        let task = server
            .stream()
            .for_each(move |message| process_msg(&server, &plugin_names, plugins.clone(), message))
            .map_err(|e| Err(e).unwrap());

        reactor.handle().spawn(task);
    }

    // Run the main loop forever
    reactor.run(future::empty::<(), ()>()).unwrap();
}

fn process_msg(server: &IrcServer,
               plugin_names: &[String],
               plugins: Vec<Arc<Mutex<Plugin>>>,
               message: Message)
               -> Result<(), IrcError> {

    if let Command::JOIN(ref channel, _, _) = message.command {
        info!("Joined {}", channel);
    }

    let message = Arc::new(message);
    // Check for possible command and save the result for later
    let command = get_command(&server.current_nickname().to_lowercase(), &message);

    // Check if the first token of the command is valid
    if let Some(ref c) = command {
        if c.tokens.is_empty() {
            let help = format!("Use \"{} help\" to get help", server.current_nickname());
            server.send_notice(&c.source, &help).unwrap();

        } else if "help" == &c.tokens[0].to_lowercase() {
            send_help_message(server, c).unwrap();

        } else if !plugin_names.contains(&c.tokens[0].to_lowercase()) {

            let help = format!("\"{} {}\" is not a command, \
                                try \"{0} help\" instead.",
                               server.current_nickname(),
                               c.tokens[0]);

            server.send_notice(&c.source, &help).unwrap();
        }
    }

    for plugin in plugins {
        // Send the message to the plugin if the plugin needs it
        if lock_plugin!(plugin).is_allowed(server, &message) {

            // Clone everything before the move
            // The server uses an Arc internally too
            let plugin = Arc::clone(&plugin);
            let message = Arc::clone(&message);
            let server = server.clone();

            // Execute the plugin in another thread
            spawn(move || { lock_plugin!(plugin).execute(&server, &message).unwrap(); });
        }

        // Check if the command is for this plugin
        if let Some(mut c) = command.clone() {

            // Skip empty commands
            if c.tokens.is_empty() {
                continue;
            }

            if lock_plugin!(plugin).name().to_lowercase() == c.tokens[0].to_lowercase() {

                // The first token contains the name of the plugin
                let name = c.tokens.remove(0);

                // Clone the server for the move - it uses an Arc internally
                let server = server.clone();
                spawn(move || {
                          if let Err(e) = lock_plugin!(plugin).command(&server, c) {
                              error!("Error in {} - {}", name, e);
                          };
                      });
            }
        }
    }
    Ok(())
}

fn send_help_message(server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> {
    server.send_notice(&command.source, "Help has not been added yet.")
}

fn get_command(nick: &str, message: &Message) -> Option<PluginCommand> {

    // Get the actual message out of PRIVMSG
    if let PRIVMSG(_, ref content) = message.command {

        // Split content by spaces and filter empty tokens
        let mut tokens: Vec<String> = content.split(' ').map(ToOwned::to_owned).collect();

        // Commands start with our name
        if tokens[0].to_lowercase().starts_with(nick) {

            // Remove the bot's name from the first token
            tokens[0].drain(..nick.len());

            // We assume that only ':' and ',' are used as suffixes on IRC
            // If there are any other chars we assume that it is not ment for the bot
            tokens[0] = tokens[0]
                .chars()
                .filter(|&c| !":,".contains(c))
                .collect();
            if !tokens[0].is_empty() {
                return None;
            }

            // The first token contained the name of the bot
            tokens.remove(0);

            Some(PluginCommand {
                     source: message.source_nickname().unwrap().to_string(),
                     target: message.response_target().unwrap().to_string(),
                     tokens: tokens,
                 })
        } else {
            None
        }
    } else {
        None
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Display possible error when trying to create a connection<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

//! Frippy is an IRC bot that runs plugins on each message
//! received.
//!
//! # Example
//! ```no_run
//! extern crate frippy;
//!
//! frippy::run();
//! ```

#[macro_use]
extern crate log;
#[macro_use]
extern crate plugin_derive;

extern crate irc;
extern crate tokio_core;
extern crate futures;
extern crate glob;

mod plugin;
mod plugins;

use std::thread::spawn;
use std::sync::{Arc, Mutex};
use glob::glob;

use irc::client::prelude::*;
use irc::proto::Command::PRIVMSG;
use irc::error::Error as IrcError;

use tokio_core::reactor::Core;
use futures::future;

use plugin::*;

// Lock the mutex and ignore if it is poisoned
macro_rules! lock_plugin {
    ($e:expr) => {
        match $e.lock() {
            Ok(plugin) => plugin,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

/// Runs the bot
///
/// # Remarks
///
/// This blocks the current thread while the bot is running
pub fn run() {

    // Load all toml files in the configs directory
    let mut configs = Vec::new();
    for toml in glob("configs/*.toml").unwrap() {
        match toml {
            Ok(path) => {
                info!("Loading {}", path.to_str().unwrap());
                match Config::load(path) {
                    Ok(v) => configs.push(v),
                    Err(e) => error!("Incorrect config file {}", e),
                }
            },
            Err(e) => error!("Failed to read path {}", e),
        }
    }

    // Without configs the bot would just idle
    if configs.is_empty() {
        error!("No config file found");
        return;
    }

    // The list of plugins in use
    let plugins: Vec<Arc<Mutex<Plugin>>> =
        vec![Arc::new(Mutex::new(plugins::emoji::Emoji::new())),
             Arc::new(Mutex::new(plugins::currency::Currency::new()))];

    // We need the plugins' names to make sure the user gets a response
    // if they use an incorrect plugin name
    let plugin_names: Vec<String> = plugins
        .iter()
        .map(|p| lock_plugin!(p).name().to_lowercase())
        .collect();

    info!("Plugins loaded: {}", plugin_names.join(", "));

    // Create an event loop to run the connections on.
    let mut reactor = Core::new().unwrap();

    // Open a connection and add work for each config
    for config in configs {
        let fut = match IrcServer::new_future(reactor.handle(), &config) {
            Ok(v) => v,
            Err(e) => {
                error!("Failed to connect: {}", e);
                return;
            }
        };

        let server = match reactor.run(fut) {
            Ok(v) => {
                info!("Connected to server");
                v
            }
            Err(e) => {
                error!("Failed to connect: {}", e);
                return;
            }
        };

        match server.identify() {
            Ok(_) => info!("Identified"),
            Err(e) => error!("Failed to identify: {}", e),
        };

        // TODO Duplicate clone...
        let plugins = plugins.clone();
        let plugin_names = plugin_names.clone();

        let task = server
            .stream()
            .for_each(move |message| process_msg(&server, &plugin_names, plugins.clone(), message))
            .map_err(|e| Err(e).unwrap());

        reactor.handle().spawn(task);
    }

    // Run the main loop forever
    reactor.run(future::empty::<(), ()>()).unwrap();
}

fn process_msg(server: &IrcServer,
               plugin_names: &[String],
               plugins: Vec<Arc<Mutex<Plugin>>>,
               message: Message)
               -> Result<(), IrcError> {

    if let Command::JOIN(ref channel, _, _) = message.command {
        info!("Joined {}", channel);
    }

    let message = Arc::new(message);
    // Check for possible command and save the result for later
    let command = get_command(&server.current_nickname().to_lowercase(), &message);

    // Check if the first token of the command is valid
    if let Some(ref c) = command {
        if c.tokens.is_empty() {
            let help = format!("Use \"{} help\" to get help", server.current_nickname());
            server.send_notice(&c.source, &help).unwrap();

        } else if "help" == &c.tokens[0].to_lowercase() {
            send_help_message(server, c).unwrap();

        } else if !plugin_names.contains(&c.tokens[0].to_lowercase()) {

            let help = format!("\"{} {}\" is not a command, \
                                try \"{0} help\" instead.",
                               server.current_nickname(),
                               c.tokens[0]);

            server.send_notice(&c.source, &help).unwrap();
        }
    }

    for plugin in plugins {
        // Send the message to the plugin if the plugin needs it
        if lock_plugin!(plugin).is_allowed(server, &message) {

            // Clone everything before the move
            // The server uses an Arc internally too
            let plugin = Arc::clone(&plugin);
            let message = Arc::clone(&message);
            let server = server.clone();

            // Execute the plugin in another thread
            spawn(move || { lock_plugin!(plugin).execute(&server, &message).unwrap(); });
        }

        // Check if the command is for this plugin
        if let Some(mut c) = command.clone() {

            // Skip empty commands
            if c.tokens.is_empty() {
                continue;
            }

            if lock_plugin!(plugin).name().to_lowercase() == c.tokens[0].to_lowercase() {

                // The first token contains the name of the plugin
                let name = c.tokens.remove(0);

                // Clone the server for the move - it uses an Arc internally
                let server = server.clone();
                spawn(move || {
                          if let Err(e) = lock_plugin!(plugin).command(&server, c) {
                              error!("Error in {} - {}", name, e);
                          };
                      });
            }
        }
    }
    Ok(())
}

fn send_help_message(server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> {
    server.send_notice(&command.source, "Help has not been added yet.")
}

fn get_command(nick: &str, message: &Message) -> Option<PluginCommand> {

    // Get the actual message out of PRIVMSG
    if let PRIVMSG(_, ref content) = message.command {

        // Split content by spaces and filter empty tokens
        let mut tokens: Vec<String> = content.split(' ').map(ToOwned::to_owned).collect();

        // Commands start with our name
        if tokens[0].to_lowercase().starts_with(nick) {

            // Remove the bot's name from the first token
            tokens[0].drain(..nick.len());

            // We assume that only ':' and ',' are used as suffixes on IRC
            // If there are any other chars we assume that it is not ment for the bot
            tokens[0] = tokens[0]
                .chars()
                .filter(|&c| !":,".contains(c))
                .collect();
            if !tokens[0].is_empty() {
                return None;
            }

            // The first token contained the name of the bot
            tokens.remove(0);

            Some(PluginCommand {
                     source: message.source_nickname().unwrap().to_string(),
                     target: message.response_target().unwrap().to_string(),
                     tokens: tokens,
                 })
        } else {
            None
        }
    } else {
        None
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>//!  Linear algebra package for [rust-ndarray](https://github.com/bluss/rust-ndarray) using LAPACK via [stainless-steel/lapack](https://github.com/stainless-steel/lapack)

extern crate blas;
extern crate lapack;
extern crate num_traits;
extern crate num_complex;
extern crate rand;
#[macro_use(s)]
extern crate ndarray;
#[macro_use]
extern crate enum_error_derive;
#[macro_use]
extern crate derive_new;

#[macro_use]
pub mod types;
pub mod error;
pub mod layout;
pub mod lapack_traits;

pub mod cholesky;
pub mod eigh;
pub mod opnorm;
pub mod qr;
pub mod solve;
pub mod svd;
pub mod triangular;

pub mod generate;
pub mod assert;
pub mod norm;
pub mod trace;

pub use assert::*;
pub use generate::*;
pub use layout::*;
pub use types::*;

pub use cholesky::*;
pub use eigh::*;
pub use norm::*;
pub use opnorm::*;
pub use qr::*;
pub use solve::*;
pub use svd::*;
pub use trace::*;
pub use triangular::*;
<commit_msg>Add crate doc<commit_after>//!  Linear algebra package for [rust-ndarray](https://github.com/bluss/rust-ndarray) using LAPACK via [stainless-steel/lapack](https://github.com/stainless-steel/lapack)
//!
//!  Linear algebra methods
//!  -----------------------
//!  - [QR decomposition](qr/trait.QR.html)
//!  - [singular value decomposition](svd/trait.SVD.html)
//!  - [solve linear problem](solve/index.html)
//!  - [solve linear problem for triangular matrix](triangular/trait.SolveTriangular.html)
//!  - [inverse matrix](solve/trait.Inverse.html)
//!  - [eigenvalue decomposition for Hermite matrix](eigh/trait.Eigh.html)
//!
//!  Utilites
//!  -----------
//!  - [assertions for array](index.html#macros)
//!  - [generator functions](generate/index.html)
//!  - [Scalar trait](types/trait.Field.html)

extern crate blas;
extern crate lapack;
extern crate num_traits;
extern crate num_complex;
extern crate rand;
#[macro_use(s)]
extern crate ndarray;
#[macro_use]
extern crate enum_error_derive;
#[macro_use]
extern crate derive_new;

#[macro_use]
pub mod types;
pub mod error;
pub mod layout;
pub mod lapack_traits;

pub mod cholesky;
pub mod eigh;
pub mod opnorm;
pub mod qr;
pub mod solve;
pub mod svd;
pub mod triangular;

pub mod generate;
pub mod assert;
pub mod norm;
pub mod trace;

pub use assert::*;
pub use generate::*;
pub use layout::*;
pub use types::*;

pub use cholesky::*;
pub use eigh::*;
pub use norm::*;
pub use opnorm::*;
pub use qr::*;
pub use solve::*;
pub use svd::*;
pub use trace::*;
pub use triangular::*;
<|endoftext|>


<commit_before>//! Implementation for `arr!` macro.

use super::ArrayLength;
use core::ops::Add;
use typenum::U1;

/// Helper trait for `arr!` macro
pub trait AddLength<T, N: ArrayLength<T>>: ArrayLength<T> {
    /// Resulting length
    type Output: ArrayLength<T>;
}

impl<T, N1, N2> AddLength<T, N2> for N1
where
    N1: ArrayLength<T> + Add<N2>,
    N2: ArrayLength<T>,
    <N1 as Add<N2>>::Output: ArrayLength<T>,
{
    type Output = <N1 as Add<N2>>::Output;
}

/// Helper type for `arr!` macro
pub type Inc<T, U> = <U as AddLength<T, U1>>::Output;

#[doc(hidden)]
#[macro_export]
macro_rules! arr_impl {
    ($T:ty; $N:ty, [$($x:expr),*], []) => ({
        unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) }
    });
    ($T:ty; $N:ty, [], [$x1:expr]) => (
        arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [])
    );
    ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => (
        arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+])
    );
    ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => (
        arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [])
    );
    ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
        arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($x),+])
    );
}

/// Macro allowing for easy generation of Generic Arrays.
/// Example: `let test = arr![u32; 1, 2, 3];`
#[macro_export]
macro_rules! arr {
    ($T:ty; $(,)*) => ({
        unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) }
    });
    ($T:ty; $($x:expr),* $(,)*) => (
        arr_impl!($T; $crate::typenum::U0, [], [$($x),*])
    );
    ($($x:expr,)+) => (arr![$($x),*]);
    () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`")
}
<commit_msg>Allow arr! to be imported with use syntax<commit_after>//! Implementation for `arr!` macro.

use super::ArrayLength;
use core::ops::Add;
use typenum::U1;

/// Helper trait for `arr!` macro
pub trait AddLength<T, N: ArrayLength<T>>: ArrayLength<T> {
    /// Resulting length
    type Output: ArrayLength<T>;
}

impl<T, N1, N2> AddLength<T, N2> for N1
where
    N1: ArrayLength<T> + Add<N2>,
    N2: ArrayLength<T>,
    <N1 as Add<N2>>::Output: ArrayLength<T>,
{
    type Output = <N1 as Add<N2>>::Output;
}

/// Helper type for `arr!` macro
pub type Inc<T, U> = <U as AddLength<T, U1>>::Output;

#[doc(hidden)]
#[macro_export]
macro_rules! arr_impl {
    ($T:ty; $N:ty, [$($x:expr),*], []) => ({
        unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) }
    });
    ($T:ty; $N:ty, [], [$x1:expr]) => (
        $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [])
    );
    ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => (
        $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+])
    );
    ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => (
        $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [])
    );
    ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
        $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($x),+])
    );
}

/// Macro allowing for easy generation of Generic Arrays.
/// Example: `let test = arr![u32; 1, 2, 3];`
#[macro_export]
macro_rules! arr {
    ($T:ty; $(,)*) => ({
        unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) }
    });
    ($T:ty; $($x:expr),* $(,)*) => (
        $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*])
    );
    ($($x:expr,)+) => (arr![$($x),*]);
    () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`")
}
<|endoftext|>


<commit_before>/*!
  This module provides the syntax extension `iterator!()` that enables mapping, filtering and
  nesting of iterators using a comprehension syntax.
*/

#![feature(macro_rules,phase)]

#![crate_name = "iteratorcomprehensions"]
#![crate_type = "lib"]

/**
  Contains the macros that implement the comprehension syntax.
*/
pub mod macros {
  #![macro_escape]

  /**
    Turns a comma separated list of identifiers into a nested tuple pattern.

    ```notrust
    arglist(i) -> i
    arglist(i, j) -> (j, i)
    arglist(i, j, k) -> (k, (j, i))
    ```
  */
  #[macro_export]
  macro_rules! arglist(
    (
      $var:ident
    ) => (
      $var
    );
    (
      $var:ident $(, $vars:ident)+
    ) => (
      (arglist!($($vars),+), $var)
    );
  );

  /**
    Main implementation of the `iterator!()` extension.
  */
  #[macro_export]
  macro_rules! iterator_tail(
    (
      (),
      (),
      (
        $map:expr
        for $var:ident in $gen:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $gen
        ),
        ($var),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      (),
      (),
      (
        $map:expr
        for $var:ident in $gen:expr
        if $filter:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $gen
          .filter(|&$var| { $filter } )
        ),
        ($var),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      ($head:expr),
      ($($envs:ident),+),
      (
        $map:expr
        for $var:ident in $gen:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $head
          .flat_map(|arglist!($($envs),+)| {
            ::std::iter::repeat(arglist!($($envs),+)).zip($gen)
          })
        ),
        ($var $(, $envs)*),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      ($head:expr),
      ($($envs:ident),+),
      (
        $map:expr
        for $var:ident in $gen:expr
        if $filter:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $head
          .flat_map(|arglist!($($envs),+)| {
            ::std::iter::repeat(arglist!($($envs),+)).zip($gen)
          })
          .filter(|&arglist!($var $(, $envs)+)| { $filter })
        ),
        ($var $(, $envs)*),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      ($head:expr),
      ($($envs:ident),+),
      (
        $map:expr
      )
    ) => (
      $head
      .map(|arglist!($($envs),+)| { $map })
    );
  );

  /**
    The `iterator!()` macro implements the following comprehension syntax:

    ```notrust
    iterator!(
      map_expr for var_1 in gen_expr_1 [if filter_expr_1]
      [… for var_n in gen_expr_n [if filter_expr]]
    )
    ```

    * `var_1`… `var_n` identify the iteration variables associated with each of the nested
      iterators.
    * `gen_expr_1`… `gen_expr_n` are expressions that evaluate to an `Iterator`. `gen_expr_i` can
      refer to all "outer" iteration variables `var_1`… `var_(i-1)`.
    * `map_expr` is an expression that constructs the elements of the iterator comprehension from
      the iteration variables.
    * `filter_expr_1`… `filter_expr_n` are expressions that evaluate to a boolean which filters
      the iterator elements based on the "outer" iteration variables.

    `iterator!()` evaluates to an expression which itself implements the `Iterator` trait.

    The expression

    ```notrust
    iterator!(
      (i, j) for i in range(0i, 3i) for j in range(0i, i + 1i) if (i + j) % 2 == 0
    )
    ```
    evaluates to an iterator that contains the elements

    ```notrust
    (0,0), (1,1), (2,0), (2,2)
    ```
  */
  #[macro_export]
  macro_rules! iterator(
    (
      $map:expr
      $(
        for $vars:ident in $gens:expr
        $(if $filters:expr)*
      )+
    ) => (
      iterator_tail!(
        (),
        (),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )+
        )
      )
    );
  );
}

#[cfg(test)]
mod tests {
  #[test]
  fn iterator1_test() {
    let xs: Vec<int> = iterator!( i for i in range(0i, 3i) ).collect();
    assert_eq!(xs, vec!(0, 1, 2));
  }

  #[test]
  fn iterator1_map_test() {
    let xs: Vec<int> = iterator!( i + 1 for i in range(0i, 3i) ).collect();
    assert_eq!(xs, vec!(1, 2, 3));
  }

  #[test]
  fn iterator1_filter_test() {
    let xs: Vec<int> = iterator!( i for i in range(0i, 3i) if i % 2 == 1 ).collect();
    assert_eq!(xs, vec!(1));
  }

  #[test]
  fn iterator1_filter_map_test() {
    let xs: Vec<int> = iterator!( i * 2 for i in range(0i, 3i) if i % 2 == 1 ).collect();
    assert_eq!(xs, vec!(2));
  }

  #[test]
  fn iterator2_map_test() {
    let xs: Vec<int> = iterator!( i * j for i in range(1i, 3i) for j in range(2i, 4i) ).collect();
    assert_eq!(xs, vec!(2, 3, 4, 6));
  }

  #[test]
  fn iterator2_filter_map_test() {
    let xs: Vec<int> = iterator!(
      i / j for i in range(6i, 9i) for j in range(1i, 4i) if i % j == 0
    ).collect();
    assert_eq!(xs, vec!(6, 3, 2, 7, 8, 4));
  }

  #[test]
  fn iterator2_example_test() {
    let xs: Vec<(int,int)> = iterator!(
      (i, j) for i in range(0i, 3i) for j in range(0i, i + 1i) if (i + j) % 2 == 0
    ).collect();
    assert_eq!(xs, vec!((0, 0), (1, 1), (2, 0), (2, 2)));
  }

  #[test]
  fn iterator3_map_test() {
    let a = vec!(1i, 2i);
    let b = vec!(3i, 5i);
    let c = vec!(7i, 11i);
    let xs: Vec<int> = iterator!(
      *i * *j * *k for i in a.iter() for j in b.iter() for k in c.iter()
    ).collect();
    assert_eq!(xs, vec!(21, 33, 35, 55, 42, 66, 70, 110));
  }

  #[test]
  fn iterator3_filter_map_test() {
    let xs: Vec<(int, int, int)> = iterator!(
      (i, j, k) for i in range(0i, 10i) for j in range(0i, 10i) for k in range(0i, 10i)
      if i == 1 && j == 2 && k == 3
    ).collect();
    assert_eq!(xs, vec!((1, 2, 3)));
  }

  #[test]
  fn iterator3_empty_test() {
    let xs: Vec<int> = iterator!(
      i * j * k for i in range(0i, 2i) for j in range(0i, i) for k in range(0i, 1i)
    ).collect();
    assert_eq!(xs, vec!(0));
  }

  #[test]
  fn iterator6_test() {
    let mut xs = iterator!(
      (i, j, k, l, m, n)
      for i in range(0i, 5i)
      for j in range(0i, 5i)
      for k in range(0i, 5i)
      for l in range(0i, 5i)
      for m in range(0i, 5i)
      for n in range(0i, 5i)
    );
    assert_eq!(xs.next().unwrap(), (0, 0, 0, 0, 0, 0));
    assert_eq!(xs.next().unwrap(), (0, 0, 0, 0, 0, 1));
    assert_eq!(xs.last().unwrap(), (4, 4, 4, 4, 4, 4));
  }
}
<commit_msg>Add pythagorean triples test.<commit_after>/*!
  This module provides the syntax extension `iterator!()` that enables mapping, filtering and
  nesting of iterators using a comprehension syntax.
*/

#![feature(macro_rules,phase)]

#![crate_name = "iteratorcomprehensions"]
#![crate_type = "lib"]

/**
  Contains the macros that implement the comprehension syntax.
*/
pub mod macros {
  #![macro_escape]

  /**
    Turns a comma separated list of identifiers into a nested tuple pattern.

    ```notrust
    arglist(i) -> i
    arglist(i, j) -> (j, i)
    arglist(i, j, k) -> (k, (j, i))
    ```
  */
  #[macro_export]
  macro_rules! arglist(
    (
      $var:ident
    ) => (
      $var
    );
    (
      $var:ident $(, $vars:ident)+
    ) => (
      (arglist!($($vars),+), $var)
    );
  );

  /**
    Main implementation of the `iterator!()` extension.
  */
  #[macro_export]
  macro_rules! iterator_tail(
    (
      (),
      (),
      (
        $map:expr
        for $var:ident in $gen:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $gen
        ),
        ($var),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      (),
      (),
      (
        $map:expr
        for $var:ident in $gen:expr
        if $filter:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $gen
          .filter(|&$var| { $filter } )
        ),
        ($var),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      ($head:expr),
      ($($envs:ident),+),
      (
        $map:expr
        for $var:ident in $gen:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $head
          .flat_map(|arglist!($($envs),+)| {
            ::std::iter::repeat(arglist!($($envs),+)).zip($gen)
          })
        ),
        ($var $(, $envs)*),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      ($head:expr),
      ($($envs:ident),+),
      (
        $map:expr
        for $var:ident in $gen:expr
        if $filter:expr
        $(
          for $vars:ident in $gens:expr
          $(if $filters:expr)*
        )*
      )
    ) => (
      iterator_tail!(
        (
          $head
          .flat_map(|arglist!($($envs),+)| {
            ::std::iter::repeat(arglist!($($envs),+)).zip($gen)
          })
          .filter(|&arglist!($var $(, $envs)+)| { $filter })
        ),
        ($var $(, $envs)*),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )*
        )
      )
    );
    (
      ($head:expr),
      ($($envs:ident),+),
      (
        $map:expr
      )
    ) => (
      $head
      .map(|arglist!($($envs),+)| { $map })
    );
  );

  /**
    The `iterator!()` macro implements the following comprehension syntax:

    ```notrust
    iterator!(
      map_expr for var_1 in gen_expr_1 [if filter_expr_1]
      [… for var_n in gen_expr_n [if filter_expr]]
    )
    ```

    * `var_1`… `var_n` identify the iteration variables associated with each of the nested
      iterators.
    * `gen_expr_1`… `gen_expr_n` are expressions that evaluate to an `Iterator`. `gen_expr_i` can
      refer to all "outer" iteration variables `var_1`… `var_(i-1)`.
    * `map_expr` is an expression that constructs the elements of the iterator comprehension from
      the iteration variables.
    * `filter_expr_1`… `filter_expr_n` are expressions that evaluate to a boolean which filters
      the iterator elements based on the "outer" iteration variables.

    `iterator!()` evaluates to an expression which itself implements the `Iterator` trait.

    The expression

    ```notrust
    iterator!(
      (i, j) for i in range(0i, 3i) for j in range(0i, i + 1i) if (i + j) % 2 == 0
    )
    ```
    evaluates to an iterator that contains the elements

    ```notrust
    (0,0), (1,1), (2,0), (2,2)
    ```
  */
  #[macro_export]
  macro_rules! iterator(
    (
      $map:expr
      $(
        for $vars:ident in $gens:expr
        $(if $filters:expr)*
      )+
    ) => (
      iterator_tail!(
        (),
        (),
        (
          $map
          $(
            for $vars in $gens
            $(if $filters)*
          )+
        )
      )
    );
  );
}

#[cfg(test)]
mod tests {
  #[test]
  fn iterator1_test() {
    let xs: Vec<int> = iterator!( i for i in range(0i, 3i) ).collect();
    assert_eq!(xs, vec!(0, 1, 2));
  }

  #[test]
  fn iterator1_map_test() {
    let xs: Vec<int> = iterator!( i + 1 for i in range(0i, 3i) ).collect();
    assert_eq!(xs, vec!(1, 2, 3));
  }

  #[test]
  fn iterator1_filter_test() {
    let xs: Vec<int> = iterator!( i for i in range(0i, 3i) if i % 2 == 1 ).collect();
    assert_eq!(xs, vec!(1));
  }

  #[test]
  fn iterator1_filter_map_test() {
    let xs: Vec<int> = iterator!( i * 2 for i in range(0i, 3i) if i % 2 == 1 ).collect();
    assert_eq!(xs, vec!(2));
  }

  #[test]
  fn iterator2_map_test() {
    let xs: Vec<int> = iterator!( i * j for i in range(1i, 3i) for j in range(2i, 4i) ).collect();
    assert_eq!(xs, vec!(2, 3, 4, 6));
  }

  #[test]
  fn iterator2_filter_map_test() {
    let xs: Vec<int> = iterator!(
      i / j for i in range(6i, 9i) for j in range(1i, 4i) if i % j == 0
    ).collect();
    assert_eq!(xs, vec!(6, 3, 2, 7, 8, 4));
  }

  #[test]
  fn iterator2_example_test() {
    let xs: Vec<(int,int)> = iterator!(
      (i, j) for i in range(0i, 3i) for j in range(0i, i + 1i) if (i + j) % 2 == 0
    ).collect();
    assert_eq!(xs, vec!((0, 0), (1, 1), (2, 0), (2, 2)));
  }

  #[test]
  fn iterator3_map_test() {
    let a = vec!(1i, 2i);
    let b = vec!(3i, 5i);
    let c = vec!(7i, 11i);
    let xs: Vec<int> = iterator!(
      *i * *j * *k for i in a.iter() for j in b.iter() for k in c.iter()
    ).collect();
    assert_eq!(xs, vec!(21, 33, 35, 55, 42, 66, 70, 110));
  }

  #[test]
  fn iterator3_filter_map_test() {
    let xs: Vec<(int, int, int)> = iterator!(
      (i, j, k) for i in range(0i, 10i) for j in range(0i, 10i) for k in range(0i, 10i)
      if i == 1 && j == 2 && k == 3
    ).collect();
    assert_eq!(xs, vec!((1, 2, 3)));
  }

  #[test]
  fn iterator3_empty_test() {
    let xs: Vec<int> = iterator!(
      i * j * k for i in range(0i, 2i) for j in range(0i, i) for k in range(0i, 1i)
    ).collect();
    assert_eq!(xs, vec!(0));
  }

  #[test]
  fn iterator6_test() {
    let mut xs = iterator!(
      (i, j, k, l, m, n)
      for i in range(0i, 5i)
      for j in range(0i, 5i)
      for k in range(0i, 5i)
      for l in range(0i, 5i)
      for m in range(0i, 5i)
      for n in range(0i, 5i)
    );
    assert_eq!(xs.next().unwrap(), (0, 0, 0, 0, 0, 0));
    assert_eq!(xs.next().unwrap(), (0, 0, 0, 0, 0, 1));
    assert_eq!(xs.last().unwrap(), (4, 4, 4, 4, 4, 4));
  }

  #[test]
  fn pythagorean_triples_test() {
    let triples = {
      use std::iter::count;
      iterator!(
        (a, b, c)
        for c in count(1u, 1u)
        for a in range(1u, c)
        for b in range(a, c)
        if a * a + b * b == c * c
      )
    };
    let xs: Vec<(uint, uint, uint)> = triples.take(3).collect();

    assert_eq!(xs, vec!((3u, 4u, 5u), (6, 8, 10), (5, 12, 13)));
  }
}
<|endoftext|>


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

use BinaryOp::*;
use Data::*;
use Expression::*;

#[derive(Clone,Debug,PartialEq)]
pub enum Data {
    Nil,
    Boolean(bool),
    Number(f64),
    Str(String),
}

#[derive(Clone,Debug)]
pub enum Expression {
    NilLiteral,
    BooleanLiteral(bool),
    NumberLiteral(f64),
    StrLiteral(String),
    Variable(String),
    Assignment{left: String, right: Box<Expression>},
    FunctionCall{name: String, args: Vec<Expression>},
    BinaryExpr{left: Box<Expression>, op: BinaryOp, right: Box<Expression>},
    IfExpr{cond: Box<Expression>, body: Box<Expression>, else_branch: Option<Box<Expression>>},
}

impl Expression {
    pub fn eval(&self, p: &mut Program) -> Data {
        match self {
            &NilLiteral => Nil,
            &BooleanLiteral(b) => Boolean(b),
            &NumberLiteral(n) => Number(n),
            &StrLiteral(ref s) => Str(s.clone()),
            &Variable(ref name) => {
                match p.vars.get(name) {
                    Some(d) => d.clone(),
                    None => Nil,
                }
            },
            &Assignment{ref left, ref right} => {
                let res = right.eval(p);
                p.vars.insert(left.clone(), res.clone());
                res
            },
            &FunctionCall{ref name, ref args} => {
                let f = match name.as_ref() {
                    "println" => println,
                    _ => return Nil,
                };

                let mut new_args = Vec::new();
                for item in args.iter() {
                    new_args.push(item.eval(p));
                }

                f(&new_args)
            },
            &BinaryExpr{ref left, ref op, ref right} => {
                let (left_data, right_data) = (left.eval(p), right.eval(p));
                op.eval(&left_data, &right_data)
            },
            &IfExpr{ref cond, ref body, ref else_branch} => {
                if cond.eval(p) == Boolean(true) {
                    body.eval(p)
                } else if let &Some(ref b) = else_branch {
                    b.eval(p)
                } else {
                    Nil
                }
            },
        }
    }
}

#[derive(Clone,Debug)]
pub enum BinaryOp {
    Add,
    Sub,
    Mul,
    Div,
    Eq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

impl BinaryOp {
    fn eval(&self, left: &Data, right: &Data) -> Data {
        match (self, left, right) {
            (&Add, &Number(l), &Number(r)) => Number(l+r),
            (&Sub, &Number(l), &Number(r)) => Number(l-r),
            (&Mul, &Number(l), &Number(r)) => Number(l*r),
            (&Div, &Number(l), &Number(r)) => Number(l/r),
            (&Eq, _, _) => Boolean(left == right),
            (&Lt, &Number(l), &Number(r)) => Boolean(l < r),
            (&LtEq, &Number(l), &Number(r)) => Boolean(l <= r),
            (&Gt, &Number(l), &Number(r)) => Boolean(l > r),
            (&GtEq, &Number(l), &Number(r)) => Boolean(l >= r),
            _ => Nil,
        }
    }
}

pub struct Program {
    pub vars: HashMap<String, Data>,
    pub funcs: HashMap<String, i64>,
}

impl Program {
    pub fn new() -> Self {
        Program {
            vars: HashMap::new(),
            funcs: HashMap::new(),
        }
    }

    pub fn eval(&mut self, e: &Expression) -> Data {
        e.eval(self)
    }
}

pub fn println(v: &Vec<Data>) -> Data {
    for item in v {
        print!("{:?}", item);
    }
    println!("");
    Data::Nil
}

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

    #[test]
    fn test_variables() {
        let ast = vec![
            Assignment {
                left: "x".to_owned(),
                right: Box::new(NumberLiteral(2.0)),
            },
            Assignment {
                left: "y".to_owned(),
                right: Box::new(Variable("x".to_owned())),
            },
            Assignment {
                left: "z".to_owned(),
                right: Box::new(Variable("w".to_owned())),
            },
            Assignment {
                left: "y".to_owned(),
                right: Box::new(BinaryExpr {
                    left: Box::new(Variable("y".to_owned())),
                    op: Add,
                    right: Box::new(NumberLiteral(1.0)),
                }),
            },
        ];

        let mut p = Program::new();
        for exp in ast {
            p.eval(&exp);
        }

        assert_eq!(p.vars.get("w"), None);
        assert_eq!(p.vars.get("x"), Some(&Number(2.0)));
        assert_eq!(p.vars.get("y"), Some(&Number(3.0)));
        assert_eq!(p.vars.get("z"), Some(&Nil));
    }

    #[test]
    fn test_binary_expr() {
        let cases = vec![
            // Add
            (Add, Number(1.0), Number(2.0), Number(3.0)),
            (Add, Boolean(false), Number(2.0), Nil),
            (Add, Number(2.0), Str("1.0".to_owned()), Nil),
            // Sub
            (Sub, Number(1.0), Number(2.0), Number(-1.0)),
            (Sub, Boolean(false), Number(2.0), Nil),
            (Sub, Number(2.0), Str("1.0".to_owned()), Nil),
            // Mul
            (Mul, Number(1.5), Number(2.0), Number(3.0)),
            (Mul, Boolean(false), Number(2.0), Nil),
            (Mul, Number(2.0), Str("1.0".to_owned()), Nil),
            // Div
            (Div, Number(1.0), Number(2.0), Number(0.5)),
            (Div, Boolean(false), Number(2.0), Nil),
            (Div, Number(2.0), Str("1.0".to_owned()), Nil),
            // Eq
            (Eq, Number(2.0), Number(2.0), Boolean(true)),
            (Eq, Number(-2.0), Number(2.0), Boolean(false)),
            (Eq, Str("foo".to_owned()), Str("foo".to_owned()), Boolean(true)),
            (Eq, Str("foo".to_owned()), Str("bar".to_owned()), Boolean(false)),
            (Eq, Boolean(false), Boolean(false), Boolean(true)),
            (Eq, Boolean(true), Boolean(true), Boolean(true)),
            (Eq, Boolean(true), Boolean(false), Boolean(false)),
            (Eq, Nil, Boolean(false), Boolean(false)),
            (Eq, Nil, Nil, Boolean(true)),
            // Lt
            (Lt, Number(-1.0), Number(0.5), Boolean(true)),
            (Lt, Number(1.0), Number(1.0), Boolean(false)),
            (Lt, Number(1.0), Number(0.5), Boolean(false)),
            // LtEq
            (LtEq, Number(-1.0), Number(0.5), Boolean(true)),
            (LtEq, Number(1.0), Number(1.0), Boolean(true)),
            (LtEq, Number(1.0), Number(0.5), Boolean(false)),
            // Gt
            (Gt, Number(-1.0), Number(0.5), Boolean(false)),
            (Gt, Number(1.0), Number(1.0), Boolean(false)),
            (Gt, Number(1.0), Number(0.5), Boolean(true)),
            // GtEq
            (GtEq, Number(-1.0), Number(0.5), Boolean(false)),
            (GtEq, Number(1.0), Number(1.0), Boolean(true)),
            (GtEq, Number(1.0), Number(0.5), Boolean(true)),
        ];

        for (op, left, right, exp) in cases {
            assert_eq!(op.eval(&left, &right), exp);
        }
    }

    #[test]
    fn test_if_expr() {
        let mut p = Program::new();

        let cases = vec![
            (BooleanLiteral(true), NumberLiteral(1.0), None, Number(1.0)),
            (BooleanLiteral(true), NumberLiteral(1.0), Some(NumberLiteral(2.0)), Number(1.0)),
            (BooleanLiteral(false), NumberLiteral(1.0), None, Nil),
            (BooleanLiteral(false), NumberLiteral(1.0), Some(NumberLiteral(2.0)), Number(2.0)),
        ];

        for (cond, body, else_branch, exp) in cases {
            let x = IfExpr {
                cond: Box::new(cond),
                body: Box::new(body),
                else_branch: else_branch.map(|e| Box::new(e)),
            };

            assert_eq!(x.eval(&mut p), exp);
        }
    }
}
<commit_msg>Add while loop<commit_after>use std::collections::HashMap;

use BinaryOp::*;
use Data::*;
use Expression::*;

#[derive(Clone,Debug,PartialEq)]
pub enum Data {
    Nil,
    Boolean(bool),
    Number(f64),
    Str(String),
}

#[derive(Clone,Debug)]
pub enum Expression {
    NilLiteral,
    BooleanLiteral(bool),
    NumberLiteral(f64),
    StrLiteral(String),
    Variable(String),
    Assignment{left: String, right: Box<Expression>},
    FunctionCall{name: String, args: Vec<Expression>},
    BinaryExpr{left: Box<Expression>, op: BinaryOp, right: Box<Expression>},
    IfExpr{cond: Box<Expression>, body: Box<Expression>, else_branch: Option<Box<Expression>>},
    WhileLoop{cond: Box<Expression>, body: Box<Expression>},
}

impl Expression {
    pub fn eval(&self, p: &mut Program) -> Data {
        match self {
            &NilLiteral => Nil,
            &BooleanLiteral(b) => Boolean(b),
            &NumberLiteral(n) => Number(n),
            &StrLiteral(ref s) => Str(s.clone()),
            &Variable(ref name) => {
                match p.vars.get(name) {
                    Some(d) => d.clone(),
                    None => Nil,
                }
            },
            &Assignment{ref left, ref right} => {
                let res = right.eval(p);
                p.vars.insert(left.clone(), res.clone());
                res
            },
            &FunctionCall{ref name, ref args} => {
                let f = match name.as_ref() {
                    "println" => println,
                    _ => return Nil,
                };

                let mut new_args = Vec::new();
                for item in args.iter() {
                    new_args.push(item.eval(p));
                }

                f(&new_args)
            },
            &BinaryExpr{ref left, ref op, ref right} => {
                let (left_data, right_data) = (left.eval(p), right.eval(p));
                op.eval(&left_data, &right_data)
            },
            &IfExpr{ref cond, ref body, ref else_branch} => {
                if cond.eval(p) != Boolean(false) {
                    body.eval(p)
                } else if let &Some(ref b) = else_branch {
                    b.eval(p)
                } else {
                    Nil
                }
            },
            &WhileLoop{ref cond, ref body} => {
                let mut last_data = Nil;
                loop {
                    if let Boolean(false) = cond.eval(p) {
                        break
                    }

                    last_data = body.eval(p);
                }

                last_data
            },
        }
    }
}

#[derive(Clone,Debug)]
pub enum BinaryOp {
    Add,
    Sub,
    Mul,
    Div,
    Eq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

impl BinaryOp {
    fn eval(&self, left: &Data, right: &Data) -> Data {
        match (self, left, right) {
            (&Add, &Number(l), &Number(r)) => Number(l+r),
            (&Sub, &Number(l), &Number(r)) => Number(l-r),
            (&Mul, &Number(l), &Number(r)) => Number(l*r),
            (&Div, &Number(l), &Number(r)) => Number(l/r),
            (&Eq, _, _) => Boolean(left == right),
            (&Lt, &Number(l), &Number(r)) => Boolean(l < r),
            (&LtEq, &Number(l), &Number(r)) => Boolean(l <= r),
            (&Gt, &Number(l), &Number(r)) => Boolean(l > r),
            (&GtEq, &Number(l), &Number(r)) => Boolean(l >= r),
            _ => Nil,
        }
    }
}

pub struct Program {
    pub vars: HashMap<String, Data>,
    pub funcs: HashMap<String, i64>,
}

impl Program {
    pub fn new() -> Self {
        Program {
            vars: HashMap::new(),
            funcs: HashMap::new(),
        }
    }

    pub fn eval(&mut self, e: &Expression) -> Data {
        e.eval(self)
    }
}

pub fn println(v: &Vec<Data>) -> Data {
    for item in v {
        print!("{:?}", item);
    }
    println!("");
    Data::Nil
}

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

    #[test]
    fn test_variables() {
        let ast = vec![
            Assignment {
                left: "x".to_owned(),
                right: Box::new(NumberLiteral(2.0)),
            },
            Assignment {
                left: "y".to_owned(),
                right: Box::new(Variable("x".to_owned())),
            },
            Assignment {
                left: "z".to_owned(),
                right: Box::new(Variable("w".to_owned())),
            },
            Assignment {
                left: "y".to_owned(),
                right: Box::new(BinaryExpr {
                    left: Box::new(Variable("y".to_owned())),
                    op: Add,
                    right: Box::new(NumberLiteral(1.0)),
                }),
            },
        ];

        let mut p = Program::new();
        for exp in ast {
            p.eval(&exp);
        }

        assert_eq!(p.vars.get("w"), None);
        assert_eq!(p.vars.get("x"), Some(&Number(2.0)));
        assert_eq!(p.vars.get("y"), Some(&Number(3.0)));
        assert_eq!(p.vars.get("z"), Some(&Nil));
    }

    #[test]
    fn test_binary_expr() {
        let cases = vec![
            // Add
            (Add, Number(1.0), Number(2.0), Number(3.0)),
            (Add, Boolean(false), Number(2.0), Nil),
            (Add, Number(2.0), Str("1.0".to_owned()), Nil),
            // Sub
            (Sub, Number(1.0), Number(2.0), Number(-1.0)),
            (Sub, Boolean(false), Number(2.0), Nil),
            (Sub, Number(2.0), Str("1.0".to_owned()), Nil),
            // Mul
            (Mul, Number(1.5), Number(2.0), Number(3.0)),
            (Mul, Boolean(false), Number(2.0), Nil),
            (Mul, Number(2.0), Str("1.0".to_owned()), Nil),
            // Div
            (Div, Number(1.0), Number(2.0), Number(0.5)),
            (Div, Boolean(false), Number(2.0), Nil),
            (Div, Number(2.0), Str("1.0".to_owned()), Nil),
            // Eq
            (Eq, Number(2.0), Number(2.0), Boolean(true)),
            (Eq, Number(-2.0), Number(2.0), Boolean(false)),
            (Eq, Str("foo".to_owned()), Str("foo".to_owned()), Boolean(true)),
            (Eq, Str("foo".to_owned()), Str("bar".to_owned()), Boolean(false)),
            (Eq, Boolean(false), Boolean(false), Boolean(true)),
            (Eq, Boolean(true), Boolean(true), Boolean(true)),
            (Eq, Boolean(true), Boolean(false), Boolean(false)),
            (Eq, Nil, Boolean(false), Boolean(false)),
            (Eq, Nil, Nil, Boolean(true)),
            // Lt
            (Lt, Number(-1.0), Number(0.5), Boolean(true)),
            (Lt, Number(1.0), Number(1.0), Boolean(false)),
            (Lt, Number(1.0), Number(0.5), Boolean(false)),
            // LtEq
            (LtEq, Number(-1.0), Number(0.5), Boolean(true)),
            (LtEq, Number(1.0), Number(1.0), Boolean(true)),
            (LtEq, Number(1.0), Number(0.5), Boolean(false)),
            // Gt
            (Gt, Number(-1.0), Number(0.5), Boolean(false)),
            (Gt, Number(1.0), Number(1.0), Boolean(false)),
            (Gt, Number(1.0), Number(0.5), Boolean(true)),
            // GtEq
            (GtEq, Number(-1.0), Number(0.5), Boolean(false)),
            (GtEq, Number(1.0), Number(1.0), Boolean(true)),
            (GtEq, Number(1.0), Number(0.5), Boolean(true)),
        ];

        for (op, left, right, exp) in cases {
            assert_eq!(op.eval(&left, &right), exp);
        }
    }

    #[test]
    fn test_if_expr() {
        let mut p = Program::new();

        let cases = vec![
            (BooleanLiteral(true), NumberLiteral(1.0), None, Number(1.0)),
            (BooleanLiteral(true), NumberLiteral(1.0), Some(NumberLiteral(2.0)), Number(1.0)),
            (BooleanLiteral(false), NumberLiteral(1.0), None, Nil),
            (BooleanLiteral(false), NumberLiteral(1.0), Some(NumberLiteral(2.0)), Number(2.0)),
        ];

        for (cond, body, else_branch, exp) in cases {
            let x = IfExpr {
                cond: Box::new(cond),
                body: Box::new(body),
                else_branch: else_branch.map(|e| Box::new(e)),
            };

            assert_eq!(x.eval(&mut p), exp);
        }
    }

    #[test]
    fn test_while_loop() {
        let mut p = Program::new();
        p.eval(&Assignment{left: "x".to_owned(), right: Box::new(NumberLiteral(0.0))});

        let out = p.eval(&WhileLoop {
            cond: Box::new(BinaryExpr {
                left: Box::new(Variable("x".to_owned())),
                op: Lt,
                right: Box::new(NumberLiteral(5.0)),
            }),
            body: Box::new(Assignment {
                left: "x".to_owned(),
                right: Box::new(BinaryExpr {
                    left: Box::new(Variable("x".to_owned())),
                    op: Add,
                    right: Box::new(NumberLiteral(1.0)),
                }),
            }),
        });

        assert_eq!(out, Number(5.0));
        assert_eq!(p.eval(&Variable("x".to_owned())), Number(5.0));
    }
}
<|endoftext|>