<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

extern crate collections = "collections";

use std::from_str::FromStr;
use collections::hashmap::HashMap;

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    let parsed_items = parse_str(program);
    println!("{}", parsed_items.print());
}

pub struct Env {
    entries: HashMap<~str, Expr>,
    outer: Option<~Env>
}

#[deriving(Eq, Show, Clone)]
pub enum Expr {
    Atom(AtomVal),
    List(Vec<~Expr>)
}

#[deriving(Eq, Show, Clone)]
pub enum AtomVal {
    Symbol(~str),
    Integer(i64),
    Float(f64)
}

fn eval(expr: Expr, env: Env) -> (Expr, Env) {
    match expr {
        Atom(Symbol(ref var_name)) => (env.find(var_name), env),
        val @ Atom(_) => (val, env),
        _ => fail!("un-implemented case")
    }
}

fn parse_str(input: ~str) -> Expr {
    parse(&mut tokenize(input))
}

fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

fn parse(tokens: &mut Vec<~str>) -> Expr {
    let current_token =
        tokens.shift().expect("calling parse() w/ empty token list; shouldn't happen");
    match current_token {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box parse(tokens));
            }
            tokens.shift();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Expr::new_atom(x)
    }
}

impl Env {
    pub fn new(params: Option<Vec<~str>>, args: Option<Vec<Expr>>, outer: Option<~Env>) -> Env {
        let mut entries = HashMap::new();
        if params.is_some() && args.is_some() {
            let params = params.expect("params should be a value");
            let args = args.expect("args should be a value");
            if params.len() == args.len() {
                for ctr in range(0,params.len()) {
                    entries.insert(params.get(ctr).to_owned(),
                                   args.get(ctr).clone());
                }
            } else {
                fail!("params and args length doesn't match")
            }
        }
        else if params.is_none() && args.is_none() {
            // do nothing!
        } else {
            fail!("cannot have params & args unset")
        }
        Env { entries: entries, outer: outer }
    }

    pub fn find(&self, symbol: &~str) -> Expr {
        match self.entries.find(symbol) {
            Some(expr) => expr.clone(),
            None => {
                match &self.outer {
                    &Some(ref outer_env) => outer_env.find(symbol),
                    &None => fail!("No variable named {} defined in the environment."
                                  , *symbol)
                }
            }
        }
    }
}

impl Expr {
    pub fn new_atom(input: ~str) -> Expr {
        let first_char = input.char_at(0);
        match first_char {
            '0' | '1' | '2' | '3' | '4' | '5' |
            '6' | '7' | '8' | '9' => {
                match input.contains(".") {
                    true => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Float(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    },
                    false => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Integer(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    }
                }
            },
            _ => Atom(Symbol(input))
        }
    }

    pub fn is_atom(&self) -> bool {
        match *self {
            Atom(_) => true,
            _ => false
        }
    }

    pub fn print(&self) -> ~str {
        match self {
            &List(ref items) => {
                let out = items.iter().map(|i| i.print())
                    .fold(~"(", |m, v| m + v + " ");
                out.trim() + ")"
            },
            &Atom(ref v) => v.print()
        }
    }
    pub fn un_cons(self) -> (Expr, Option<Expr>) {
        match self {
            Atom(v) => (Atom(v), None),
            List(mut items) => {
                if items.len() == 0 {
                    fail!("cannot build car/cdr of empty list");
                }
                let car = items.shift()
                    .expect("at least one item in the least; shouldn't happen");
                (*car, Some(List(items)))
            }
        }
    }
}

impl AtomVal {
    pub fn print(&self) -> ~str {
        match self {
            &Symbol(ref v) => v.to_owned(),
            &Integer(ref v) => v.to_str(),
            &Float(ref v) => v.to_str()
        }
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, parse, Atom, List, Symbol, Integer, Float};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
        assert_eq!(tokens.get(0).to_owned(), ~"(");
        assert_eq!(tokens.get(1).to_owned(), ~"foo");
        assert_eq!(tokens.get(2).to_owned(), ~"12");
        assert_eq!(tokens.get(3).to_owned(), ~"3");
        assert_eq!(tokens.get(4).to_owned(), ~")");
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_str_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Symbol(val)) => {
                assert_eq!(val, ~"bar")
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_an_int_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"42");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Integer(val)) => {
                assert_eq!(val, 42)
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_float_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"1.1");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Float(val)) => {
                assert_eq!(val, 1.1)
            },
            _ => assert!(false)
        }
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_parse_it() {
        let tokens = &mut tokenize(~"(bar 12 45)");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(3 == items_len);
                assert_eq!(items.get(0).is_atom(), true);
                assert_eq!(*items.get(0), ~Atom(Symbol(~"bar")));
                assert_eq!(items.get(1).is_atom(), true);
                assert_eq!(*items.get(1), ~Atom(Integer(12)));
                assert_eq!(items.get(2).is_atom(), true);
                assert_eq!(*items.get(2), ~Atom(Integer(45)));
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_a_nested_list() {
        let tokens = &mut tokenize(~"((2 3) bar 12 (hee (hah)))");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(4 == items_len);
                match *items.get(0) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Integer(2)));
                        assert_eq!(*items.get(1), ~Atom(Integer(3)));
                    },
                    _ => fail!("shoulda got a list")
                }
                assert_eq!(*items.get(1), ~Atom(Symbol(~"bar")));
                assert_eq!(*items.get(2), ~Atom(Integer(12)));
                match *items.get(3) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Symbol(~"hee")));
                        match *items.get(1) {
                            ~List(ref items) => {
                                assert_eq!(items.len(), 1);
                                assert_eq!(*items.get(0), ~Atom(Symbol(~"hah")));
                            },
                            _ => fail!("shoulda got a list")
                        }
                    },
                    _ => fail!("shoulda got a list")
                }
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn parsed_tokens_of_a_list_of_atoms_and_a_nested_list_should_to_str_correctly() {
        let input = ~"((2 3) bar 12 (hee (hah)))";
        let tokens = &mut tokenize(input.to_owned());
        let parsed_item = parse(tokens);
        let output = parsed_item.print();
        assert_eq!(input, output);
    }
}

#[cfg(test)]
mod eval_test {
    mod un_cons {
        use super::super::{parse_str, Atom, List, Symbol, Integer, Float,
                           Env, eval};
        #[test]
        fn an_atom_expr_returns_the_atom_in_the_car_with_none_in_the_cdr() {
            let expr = parse_str(~"x");
            let (car, cdr) = expr.un_cons();
            assert_eq!(car, Atom(Symbol(~"x")));
            assert_eq!(cdr, None);
        }

        #[test]
        fn a_list_with_one_atom_element_returns_an_atom_car_and_an_empty_list_in_the_cdr() {
            let expr = parse_str(~"(x)");
            let (car, cdr) = expr.un_cons();
            assert_eq!(car, Atom(Symbol(~"x")));
            match cdr.expect("should be a value here") {
                List(items) => assert_eq!(items.len(), 0),
                _ => fail!("expected a list")
            }
        }

        #[test]
        fn a_list_with_multiple_elements_returns_the_first_car_and_the_rust_in_the_cdr() {
            let expr = parse_str(~"(y 2 3)");
            let (car, cdr) = expr.un_cons();
            assert_eq!(car, Atom(Symbol(~"y")));
            match cdr.expect("should be a value here") {
                List(items) => {
                    assert_eq!(items.len(), 2)
                },
                _ => fail!("expected a list")
            }
        }

        #[test]
        #[should_fail]
        fn calling_extract_on_an_empty_list_should_fail() {
            let expr = parse_str(~"()");
            expr.un_cons();
        }

        #[test]
        fn given_a_symbol_in_the_env_then_calling_eval_should_resolve_its_value() {
            let env = Env::new(
                Some(vec!(~"x")),
                Some(vec!(Atom(Integer(42)))),
                None);
            let in_expr = parse_str(~"x");
            let (out_expr, _) = eval(in_expr, env);
            assert_eq!(out_expr, Atom(Integer(42)));
        }

        #[test]
        #[should_fail]
        fn given_a_symbol_NOT_in_the_env_then_calling_eval_should_fail() {
            let env = Env::new(None, None, None);
            let in_expr = parse_str(~"x");
            eval(in_expr, env);
        }

        #[test]
        fn given_a_float_literal_then_calling_eval_should_return_it_back() {
            let env = Env::new(None, None, None);
            let in_expr = parse_str(~"34.3");
            let (out_expr, _) = eval(in_expr, env);
            assert_eq!(out_expr, Atom(Float(34.3)));
        }

        #[test]
        fn given_a_integer_literal_then_calling_eval_should_return_it_back() {
            let env = Env::new(None, None, None);
            let in_expr = parse_str(~"34");
            let (out_expr, _) = eval(in_expr, env);
            assert_eq!(out_expr, Atom(Integer(34)));
        }
    }

    mod env_tests {
        use super::super::{Env};

        #[test]
        fn a_new_env_with_no_parent_params_or_vars_should_be_set_up_empty() {
            let _env = Env::new(None, None, None);
        }
    }
}
<commit_msg>adjust bad year range on copyright notice<commit_after>// Copyright 2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

extern crate collections = "collections";

use std::from_str::FromStr;
use collections::hashmap::HashMap;

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    let parsed_items = parse_str(program);
    println!("{}", parsed_items.print());
}

pub struct Env {
    entries: HashMap<~str, Expr>,
    outer: Option<~Env>
}

#[deriving(Eq, Show, Clone)]
pub enum Expr {
    Atom(AtomVal),
    List(Vec<~Expr>)
}

#[deriving(Eq, Show, Clone)]
pub enum AtomVal {
    Symbol(~str),
    Integer(i64),
    Float(f64)
}

fn eval(expr: Expr, env: Env) -> (Expr, Env) {
    match expr {
        Atom(Symbol(ref var_name)) => (env.find(var_name), env),
        val @ Atom(_) => (val, env),
        _ => fail!("un-implemented case")
    }
}

fn parse_str(input: ~str) -> Expr {
    parse(&mut tokenize(input))
}

fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

fn parse(tokens: &mut Vec<~str>) -> Expr {
    let current_token =
        tokens.shift().expect("calling parse() w/ empty token list; shouldn't happen");
    match current_token {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box parse(tokens));
            }
            tokens.shift();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Expr::new_atom(x)
    }
}

impl Env {
    pub fn new(params: Option<Vec<~str>>, args: Option<Vec<Expr>>, outer: Option<~Env>) -> Env {
        let mut entries = HashMap::new();
        if params.is_some() && args.is_some() {
            let params = params.expect("params should be a value");
            let args = args.expect("args should be a value");
            if params.len() == args.len() {
                for ctr in range(0,params.len()) {
                    entries.insert(params.get(ctr).to_owned(),
                                   args.get(ctr).clone());
                }
            } else {
                fail!("params and args length doesn't match")
            }
        }
        else if params.is_none() && args.is_none() {
            // do nothing!
        } else {
            fail!("cannot have params & args unset")
        }
        Env { entries: entries, outer: outer }
    }

    pub fn find(&self, symbol: &~str) -> Expr {
        match self.entries.find(symbol) {
            Some(expr) => expr.clone(),
            None => {
                match &self.outer {
                    &Some(ref outer_env) => outer_env.find(symbol),
                    &None => fail!("No variable named {} defined in the environment."
                                  , *symbol)
                }
            }
        }
    }
}

impl Expr {
    pub fn new_atom(input: ~str) -> Expr {
        let first_char = input.char_at(0);
        match first_char {
            '0' | '1' | '2' | '3' | '4' | '5' |
            '6' | '7' | '8' | '9' => {
                match input.contains(".") {
                    true => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Float(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    },
                    false => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Integer(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    }
                }
            },
            _ => Atom(Symbol(input))
        }
    }

    pub fn is_atom(&self) -> bool {
        match *self {
            Atom(_) => true,
            _ => false
        }
    }

    pub fn print(&self) -> ~str {
        match self {
            &List(ref items) => {
                let out = items.iter().map(|i| i.print())
                    .fold(~"(", |m, v| m + v + " ");
                out.trim() + ")"
            },
            &Atom(ref v) => v.print()
        }
    }
    pub fn un_cons(self) -> (Expr, Option<Expr>) {
        match self {
            Atom(v) => (Atom(v), None),
            List(mut items) => {
                if items.len() == 0 {
                    fail!("cannot build car/cdr of empty list");
                }
                let car = items.shift()
                    .expect("at least one item in the least; shouldn't happen");
                (*car, Some(List(items)))
            }
        }
    }
}

impl AtomVal {
    pub fn print(&self) -> ~str {
        match self {
            &Symbol(ref v) => v.to_owned(),
            &Integer(ref v) => v.to_str(),
            &Float(ref v) => v.to_str()
        }
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, parse, Atom, List, Symbol, Integer, Float};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
        assert_eq!(tokens.get(0).to_owned(), ~"(");
        assert_eq!(tokens.get(1).to_owned(), ~"foo");
        assert_eq!(tokens.get(2).to_owned(), ~"12");
        assert_eq!(tokens.get(3).to_owned(), ~"3");
        assert_eq!(tokens.get(4).to_owned(), ~")");
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_str_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Symbol(val)) => {
                assert_eq!(val, ~"bar")
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_an_int_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"42");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Integer(val)) => {
                assert_eq!(val, 42)
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_float_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"1.1");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Float(val)) => {
                assert_eq!(val, 1.1)
            },
            _ => assert!(false)
        }
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_parse_it() {
        let tokens = &mut tokenize(~"(bar 12 45)");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(3 == items_len);
                assert_eq!(items.get(0).is_atom(), true);
                assert_eq!(*items.get(0), ~Atom(Symbol(~"bar")));
                assert_eq!(items.get(1).is_atom(), true);
                assert_eq!(*items.get(1), ~Atom(Integer(12)));
                assert_eq!(items.get(2).is_atom(), true);
                assert_eq!(*items.get(2), ~Atom(Integer(45)));
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_a_nested_list() {
        let tokens = &mut tokenize(~"((2 3) bar 12 (hee (hah)))");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(4 == items_len);
                match *items.get(0) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Integer(2)));
                        assert_eq!(*items.get(1), ~Atom(Integer(3)));
                    },
                    _ => fail!("shoulda got a list")
                }
                assert_eq!(*items.get(1), ~Atom(Symbol(~"bar")));
                assert_eq!(*items.get(2), ~Atom(Integer(12)));
                match *items.get(3) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Symbol(~"hee")));
                        match *items.get(1) {
                            ~List(ref items) => {
                                assert_eq!(items.len(), 1);
                                assert_eq!(*items.get(0), ~Atom(Symbol(~"hah")));
                            },
                            _ => fail!("shoulda got a list")
                        }
                    },
                    _ => fail!("shoulda got a list")
                }
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn parsed_tokens_of_a_list_of_atoms_and_a_nested_list_should_to_str_correctly() {
        let input = ~"((2 3) bar 12 (hee (hah)))";
        let tokens = &mut tokenize(input.to_owned());
        let parsed_item = parse(tokens);
        let output = parsed_item.print();
        assert_eq!(input, output);
    }
}

#[cfg(test)]
mod eval_test {
    mod un_cons {
        use super::super::{parse_str, Atom, List, Symbol, Integer, Float,
                           Env, eval};
        #[test]
        fn an_atom_expr_returns_the_atom_in_the_car_with_none_in_the_cdr() {
            let expr = parse_str(~"x");
            let (car, cdr) = expr.un_cons();
            assert_eq!(car, Atom(Symbol(~"x")));
            assert_eq!(cdr, None);
        }

        #[test]
        fn a_list_with_one_atom_element_returns_an_atom_car_and_an_empty_list_in_the_cdr() {
            let expr = parse_str(~"(x)");
            let (car, cdr) = expr.un_cons();
            assert_eq!(car, Atom(Symbol(~"x")));
            match cdr.expect("should be a value here") {
                List(items) => assert_eq!(items.len(), 0),
                _ => fail!("expected a list")
            }
        }

        #[test]
        fn a_list_with_multiple_elements_returns_the_first_car_and_the_rust_in_the_cdr() {
            let expr = parse_str(~"(y 2 3)");
            let (car, cdr) = expr.un_cons();
            assert_eq!(car, Atom(Symbol(~"y")));
            match cdr.expect("should be a value here") {
                List(items) => {
                    assert_eq!(items.len(), 2)
                },
                _ => fail!("expected a list")
            }
        }

        #[test]
        #[should_fail]
        fn calling_extract_on_an_empty_list_should_fail() {
            let expr = parse_str(~"()");
            expr.un_cons();
        }

        #[test]
        fn given_a_symbol_in_the_env_then_calling_eval_should_resolve_its_value() {
            let env = Env::new(
                Some(vec!(~"x")),
                Some(vec!(Atom(Integer(42)))),
                None);
            let in_expr = parse_str(~"x");
            let (out_expr, _) = eval(in_expr, env);
            assert_eq!(out_expr, Atom(Integer(42)));
        }

        #[test]
        #[should_fail]
        fn given_a_symbol_NOT_in_the_env_then_calling_eval_should_fail() {
            let env = Env::new(None, None, None);
            let in_expr = parse_str(~"x");
            eval(in_expr, env);
        }

        #[test]
        fn given_a_float_literal_then_calling_eval_should_return_it_back() {
            let env = Env::new(None, None, None);
            let in_expr = parse_str(~"34.3");
            let (out_expr, _) = eval(in_expr, env);
            assert_eq!(out_expr, Atom(Float(34.3)));
        }

        #[test]
        fn given_a_integer_literal_then_calling_eval_should_return_it_back() {
            let env = Env::new(None, None, None);
            let in_expr = parse_str(~"34");
            let (out_expr, _) = eval(in_expr, env);
            assert_eq!(out_expr, Atom(Integer(34)));
        }
    }

    mod env_tests {
        use super::super::{Env};

        #[test]
        fn a_new_env_with_no_parent_params_or_vars_should_be_set_up_empty() {
            let _env = Env::new(None, None, None);
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use config::*;
use rand::*;
use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
use regex::Regex;
use regex::NoExpand;

pub struct Word {
    pub syllables : String,
    pub graphemes : String,
    pub syllable_rewrite_history : Vec<(String, String)>,
    pub grapheme_rewrite_history : Vec<(String, String)>,
    pub syllable_rejects : Vec<String>,
    pub grapheme_rejects : Vec<String>,
}

pub struct WordFactory {
    pub first_syllable_list : Vec<Weighted<String>>,
    pub last_syllable_list : Vec<Weighted<String>>,
    pub normal_syllable_list : Vec<Weighted<String>>,

    pub graphemes : Vec<(String, Vec<Weighted<String>>)>,

    pub rewrites : RewriteGroup,

    pub rejects : RejectGroup,

    pub generate_settings : GenerateSettings,
}

pub trait WordGenerator {
//    fn new(
//        &mut self,
//        first_syllables : &Vec<Weighted<String>>,
//        last_syllables : &Vec<Weighted<String>>,
//        normal_syllables : &Vec<Weighted<String>>,
//        graphemes : &Vec<(String, Vec<Weighted<String>>)>,
//        settings: &GenerateSettings);
    fn generate_syllables(&self, word: &mut Word);
    fn generate_graphemes(&self, word: &mut Word);
    fn rewrite_syllables(&self, word: &mut Word);
    fn rewrite_graphemes(&self, word: &mut Word);
    fn mark_syllable_rejects(&self, word: &mut Word);
    fn mark_grapheme_rejects(&self, word: &mut Word);
}

impl WordGenerator for WordFactory {
    fn generate_syllables(&self, word: &mut Word) {
        let mut rng = rand::thread_rng();

        let mut current_chance_for_syllable : f32 = 1.0;
        let mut syllable_count : usize = 0;
        let mut syllable_loop_iter = rng.gen_iter::<f32>();

        loop {
            let result = syllable_loop_iter.next();
            match result {
                Some(x) => {
                    if x < current_chance_for_syllable && syllable_count < self.generate_settings.max_syllables {
                        syllable_count = syllable_count + 1;
                        current_chance_for_syllable *= 1.0-self.generate_settings.syllable_decay_rate;
                    } else {
                        break
                    }
                }
                None => { break }
            }
        }

        word.syllables = match syllable_count {
            1 => {
                get_random_from_weighted(&self.first_syllable_list)
            },
            2 => {
                let mut temp_word = get_random_from_weighted(&self.first_syllable_list);
                temp_word.push_str(&get_random_from_weighted(&self.last_syllable_list));
                temp_word
            },
            _ => {
                let mut temp_word = get_random_from_weighted(&self.first_syllable_list);
                for _ in 1..(syllable_count - 1) {
                    temp_word.push_str(&get_random_from_weighted(&self.normal_syllable_list));
                }
                temp_word.push_str(&get_random_from_weighted(&self.last_syllable_list));
                temp_word
            },
        };
    }

    fn generate_graphemes(&self, word: &mut Word) {
        assert!(!word.syllables.is_empty(), "Cannot call generate_graphemes on a word without a syllable string");

        let mut grapheme_vector = Vec::new();
        for grapheme in get_word_syllables(&word).graphemes(false) {
            grapheme_vector.push(syllable_element_to_random_grapheme(&self.graphemes, &String::from_str(&grapheme)));
        }

        word.graphemes = grapheme_vector.iter().fold(String::new(), |accumulator : String, character| { let mut new_str = String::from_str(&accumulator); new_str.push_str(&character); new_str});
    }
    fn rewrite_syllables(&self, word: &mut Word) {
        for rewrite in &self.rewrites.syllable_rewrites {
            let rewritten_string = apply_single_rewrite(&rewrite.pattern, &rewrite.replace, &word.syllables);
            word.syllable_rewrite_history.push((rewrite.pattern.clone(), rewritten_string));
        }
    }
    fn rewrite_graphemes(&self, word: &mut Word) {
        for rewrite in &self.rewrites.grapheme_rewrites {
            let rewritten_string = apply_single_rewrite(&rewrite.pattern, &rewrite.replace, &word.graphemes);
            word.grapheme_rewrite_history.push((rewrite.pattern.clone(), rewritten_string));
        }
    }
    fn mark_syllable_rejects(&self, word: &mut Word) {
        for reject in &self.rejects.syllable_rejects {
            let reject_regex : Regex = match Regex::new(&reject) {
                Ok(res) => res,
                Err(err) => panic!("Error '{}' with regex '{}' in a reject, please verify that it is valid", err, &reject)
            };
            if reject_regex.is_match(&get_word_syllables(&word)) {
                word.syllable_rejects.push(reject.clone());
            }
        }
    }
    fn mark_grapheme_rejects(&self, word: &mut Word) {
        for reject in &self.rejects.grapheme_rejects {
            let reject_regex : Regex = match Regex::new(&reject) {
                Ok(res) => res,
                Err(err) => panic!("Error '{}' with regex '{}' in a reject, please verify that it is valid", err, &reject)
            };
            if reject_regex.is_match(&get_word_syllables(&word)) {
                word.grapheme_rejects.push(reject.clone());
            }
        }
    }
}

fn apply_single_rewrite(rewrite : &String, replace : &String, source : &String) -> String {
    let rewrite_regex : Regex = match Regex::new(&rewrite) {
        Ok(res) => res,
        Err(err) => panic!("Error '{}' with regex '{}' in a rewrite, please verify that it is valid", err, &rewrite)
    };
    rewrite_regex.replace_all(&source, NoExpand(replace))
}

fn syllable_element_to_random_grapheme(grapheme_groups : &Vec<(String, Vec<Weighted<String>>)>, syllable_element : &String) -> String {
    let matching_grapheme_group : Vec<Weighted<String>> = match grapheme_groups.iter().filter(|ref i| i.0 == *syllable_element).map(|ref i| i.1.clone()).last() {
        Some(res) => res,

        None => panic!("No grapheme group found for syllable element {}, check your syllable sets and rewrites", &syllable_element)
    };
    get_random_from_weighted(&matching_grapheme_group)
}

fn get_random_from_weighted(values : &Vec<Weighted<String>>) -> String {

    let mut local_values : Vec<Weighted<String>> = values.clone();

    let selector : WeightedChoice<String> = WeightedChoice::new(&mut local_values);
    let mut rng = rand::thread_rng();

    selector.ind_sample(&mut rng)
}

//temporary function to properly obtain rewritten syllables and graphemes for a word, needs to be refactored into a word trait
pub fn get_word_syllables(word : &Word) -> String {
    match word.syllable_rewrite_history.last() {
        Some(result) => result.1.clone(),
        None => word.syllables.clone()
    }
}
pub fn get_word_graphemes(word : &Word) -> String {
    match word.grapheme_rewrite_history.last() {
        Some(result) => result.1.clone(),
        None => word.syllables.clone()
    }
}
<commit_msg>fixed bug that would cause grapheme regexes to try to match to word syllables<commit_after>extern crate rand;

use config::*;
use rand::*;
use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
use regex::Regex;
use regex::NoExpand;

pub struct Word {
    pub syllables : String,
    pub graphemes : String,
    pub syllable_rewrite_history : Vec<(String, String)>,
    pub grapheme_rewrite_history : Vec<(String, String)>,
    pub syllable_rejects : Vec<String>,
    pub grapheme_rejects : Vec<String>,
}

pub struct WordFactory {
    pub first_syllable_list : Vec<Weighted<String>>,
    pub last_syllable_list : Vec<Weighted<String>>,
    pub normal_syllable_list : Vec<Weighted<String>>,

    pub graphemes : Vec<(String, Vec<Weighted<String>>)>,

    pub rewrites : RewriteGroup,

    pub rejects : RejectGroup,

    pub generate_settings : GenerateSettings,
}

pub trait WordGenerator {
//    fn new(
//        &mut self,
//        first_syllables : &Vec<Weighted<String>>,
//        last_syllables : &Vec<Weighted<String>>,
//        normal_syllables : &Vec<Weighted<String>>,
//        graphemes : &Vec<(String, Vec<Weighted<String>>)>,
//        settings: &GenerateSettings);
    fn generate_syllables(&self, word: &mut Word);
    fn generate_graphemes(&self, word: &mut Word);
    fn rewrite_syllables(&self, word: &mut Word);
    fn rewrite_graphemes(&self, word: &mut Word);
    fn mark_syllable_rejects(&self, word: &mut Word);
    fn mark_grapheme_rejects(&self, word: &mut Word);
}

impl WordGenerator for WordFactory {
    fn generate_syllables(&self, word: &mut Word) {
        let mut rng = rand::thread_rng();

        let mut current_chance_for_syllable : f32 = 1.0;
        let mut syllable_count : usize = 0;
        let mut syllable_loop_iter = rng.gen_iter::<f32>();

        loop {
            let result = syllable_loop_iter.next();
            match result {
                Some(x) => {
                    if x < current_chance_for_syllable && syllable_count < self.generate_settings.max_syllables {
                        syllable_count = syllable_count + 1;
                        current_chance_for_syllable *= 1.0-self.generate_settings.syllable_decay_rate;
                    } else {
                        break
                    }
                }
                None => { break }
            }
        }

        word.syllables = match syllable_count {
            1 => {
                get_random_from_weighted(&self.first_syllable_list)
            },
            2 => {
                let mut temp_word = get_random_from_weighted(&self.first_syllable_list);
                temp_word.push_str(&get_random_from_weighted(&self.last_syllable_list));
                temp_word
            },
            _ => {
                let mut temp_word = get_random_from_weighted(&self.first_syllable_list);
                for _ in 1..(syllable_count - 1) {
                    temp_word.push_str(&get_random_from_weighted(&self.normal_syllable_list));
                }
                temp_word.push_str(&get_random_from_weighted(&self.last_syllable_list));
                temp_word
            },
        };
    }

    fn generate_graphemes(&self, word: &mut Word) {
        assert!(!word.syllables.is_empty(), "Cannot call generate_graphemes on a word without a syllable string");

        let mut grapheme_vector = Vec::new();
        for grapheme in get_word_syllables(&word).graphemes(false) {
            grapheme_vector.push(syllable_element_to_random_grapheme(&self.graphemes, &String::from_str(&grapheme)));
        }

        word.graphemes = grapheme_vector.iter().fold(String::new(), |accumulator : String, character| { let mut new_str = String::from_str(&accumulator); new_str.push_str(&character); new_str});
    }
    fn rewrite_syllables(&self, word: &mut Word) {
        for rewrite in &self.rewrites.syllable_rewrites {
            let rewritten_string = apply_single_rewrite(&rewrite.pattern, &rewrite.replace, &word.syllables);
            word.syllable_rewrite_history.push((rewrite.pattern.clone(), rewritten_string));
        }
    }
    fn rewrite_graphemes(&self, word: &mut Word) {
        for rewrite in &self.rewrites.grapheme_rewrites {
            let rewritten_string = apply_single_rewrite(&rewrite.pattern, &rewrite.replace, &word.graphemes);
            word.grapheme_rewrite_history.push((rewrite.pattern.clone(), rewritten_string));
        }
    }
    fn mark_syllable_rejects(&self, word: &mut Word) {
        for reject in &self.rejects.syllable_rejects {
            let reject_regex : Regex = match Regex::new(&reject) {
                Ok(res) => res,
                Err(err) => panic!("Error '{}' with regex '{}' in a reject, please verify that it is valid", err, &reject)
            };
            if reject_regex.is_match(&get_word_syllables(&word)) {
                word.syllable_rejects.push(reject.clone());
            }
        }
    }
    fn mark_grapheme_rejects(&self, word: &mut Word) {
        for reject in &self.rejects.grapheme_rejects {
            let reject_regex : Regex = match Regex::new(&reject) {
                Ok(res) => res,
                Err(err) => panic!("Error '{}' with regex '{}' in a reject, please verify that it is valid", err, &reject)
            };
            if reject_regex.is_match(&get_word_graphemes(&word)) {
                word.grapheme_rejects.push(reject.clone());
            }
        }
    }
}

fn apply_single_rewrite(rewrite : &String, replace : &String, source : &String) -> String {
    let rewrite_regex : Regex = match Regex::new(&rewrite) {
        Ok(res) => res,
        Err(err) => panic!("Error '{}' with regex '{}' in a rewrite, please verify that it is valid", err, &rewrite)
    };
    rewrite_regex.replace_all(&source, NoExpand(replace))
}

fn syllable_element_to_random_grapheme(grapheme_groups : &Vec<(String, Vec<Weighted<String>>)>, syllable_element : &String) -> String {
    let matching_grapheme_group : Vec<Weighted<String>> = match grapheme_groups.iter().filter(|ref i| i.0 == *syllable_element).map(|ref i| i.1.clone()).last() {
        Some(res) => res,

        None => panic!("No grapheme group found for syllable element {}, check your syllable sets and rewrites", &syllable_element)
    };
    get_random_from_weighted(&matching_grapheme_group)
}

fn get_random_from_weighted(values : &Vec<Weighted<String>>) -> String {

    let mut local_values : Vec<Weighted<String>> = values.clone();

    let selector : WeightedChoice<String> = WeightedChoice::new(&mut local_values);
    let mut rng = rand::thread_rng();

    selector.ind_sample(&mut rng)
}

//temporary function to properly obtain rewritten syllables and graphemes for a word, needs to be refactored into a word trait
pub fn get_word_syllables(word : &Word) -> String {
    match word.syllable_rewrite_history.last() {
        Some(result) => result.1.clone(),
        None => word.syllables.clone()
    }
}
pub fn get_word_graphemes(word : &Word) -> String {
    match word.grapheme_rewrite_history.last() {
        Some(result) => result.1.clone(),
        None => word.syllables.clone()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

//! Socket module

use std::os::unix::io::RawFd;

use super::rand;
use super::simple_stream::nbetstream::{
    NbetStream,
    ReadResult,
    WriteResult
};

/// Represents an epoll controlled Async socket
#[derive(Clone)]
pub struct Socket {
    /// Unique identifier
    id: u32,
    /// I/O stream
    stream: NbetStream
}

impl Socket {

    /// Returns a new Socket
    pub fn new(stream: NbetStream) -> Socket {
        Socket {
            id: rand::random::<u32>(),
            stream: stream
        }
    }

    /// Returns this socket's id
    pub fn id(&self) -> u32 {
        self.id
    }

    /// Attempts to read from socket
    pub fn read(&mut self) -> ReadResult {
        self.stream.read()
    }

    /// Attempts to write to this socket
    pub fn write(&mut self, buf: &Vec<u8>) -> WriteResult {
        self.stream.write(buf)
    }

    /// Returns the underlying file descriptor
    pub fn raw_fd(&self) -> RawFd {
        self.stream.raw_fd()
    }

    /// Returns a Vec<Vec<u8>> representing the payloads that were read during the last
    /// call to read().
    /// This calls drains the internal buffer
    pub fn buffer(&mut self) -> Vec<Vec<u8>> {
        let internal_buffer = self.stream.buffer_as_mut();
        let queue = internal_buffer.drain_queue();

        println!("queue.len: {}", queue.len());
        for msg in queue.iter() {
            println!("queue.msg.len: {}", msg.len());
        }

        queue
    }
}
<commit_msg>Removing log messages<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

//! Socket module

use std::os::unix::io::RawFd;

use super::rand;
use super::simple_stream::nbetstream::{
    NbetStream,
    ReadResult,
    WriteResult
};

/// Represents an epoll controlled Async socket
#[derive(Clone)]
pub struct Socket {
    /// Unique identifier
    id: u32,
    /// I/O stream
    stream: NbetStream
}

impl Socket {

    /// Returns a new Socket
    pub fn new(stream: NbetStream) -> Socket {
        Socket {
            id: rand::random::<u32>(),
            stream: stream
        }
    }

    /// Returns this socket's id
    pub fn id(&self) -> u32 {
        self.id
    }

    /// Attempts to read from socket
    pub fn read(&mut self) -> ReadResult {
        self.stream.read()
    }

    /// Attempts to write to this socket
    pub fn write(&mut self, buf: &Vec<u8>) -> WriteResult {
        self.stream.write(buf)
    }

    /// Returns the underlying file descriptor
    pub fn raw_fd(&self) -> RawFd {
        self.stream.raw_fd()
    }

    /// Returns a Vec<Vec<u8>> representing the payloads that were read during the last
    /// call to read().
    /// This calls drains the internal buffer
    pub fn buffer(&mut self) -> Vec<Vec<u8>> {
        let internal_buffer = self.stream.buffer_as_mut();
        let queue = internal_buffer.drain_queue();
        queue
    }
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use v2::json::{buffer, Extras, Index};

/// Image data used to create a texture.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct Image {
    /// The index of the buffer view that contains the image. Use this instead of the image's uri property.
    #[serde(rename = "bufferView")]
    pub buffer_view: Option<Index<buffer::View>>,

    /// The image's MIME type.
    #[serde(rename = "mimeType")]
    pub mime_type: Option<String>,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// The uri of the image.  Relative paths are relative to the .gltf file.  Instead of referencing an external file, the uri can also be a data-uri.  The image format must be jpg or png.
    pub uri: Option<String>,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: ImageExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,
}

/// Extension specific data for `Image`.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct ImageExtensions {
    #[serde(default)]
    _allow_unknown_fields: (),
}
<commit_msg>Added validation for image MIME types<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use v2::json::{buffer, Extras, Index, Root};
use v2::validation::{Error, JsonPath, Validate};

/// All valid MIME types.
pub const VALID_MIME_TYPES: &'static [&'static str] = &[
    "image/jpeg",
    "image/png",
];

/// Image data used to create a texture.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct Image {
    /// The index of the buffer view that contains the image. Use this instead of the image's uri property.
    #[serde(rename = "bufferView")]
    pub buffer_view: Option<Index<buffer::View>>,

    /// The image's MIME type.
    #[serde(rename = "mimeType")]
    pub mime_type: Option<MimeType>,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// The uri of the image.  Relative paths are relative to the .gltf file.  Instead of referencing an external file, the uri can also be a data-uri.  The image format must be jpg or png.
    pub uri: Option<String>,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: ImageExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,
}

/// Extension specific data for `Image`.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct ImageExtensions {
    #[serde(default)]
    _allow_unknown_fields: (),
}

/// An image MIME type.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MimeType(String);

impl Validate for MimeType {
    fn validate<F>(&self, _: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        if !VALID_MIME_TYPES.contains(&self.0.as_str()) {
            report(Error::invalid_enum(path, self.0.clone()));
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsString;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

pub fn append_path(name: &str, value: Vec<PathBuf>, cmd: &mut Command) {
    let old_value = env::var_os(name);
    let mut parts: Vec<PathBuf>;
    if let Some(ref v) = old_value {
        parts = env::split_paths(v).collect();
        parts.extend(value);
    } else {
        parts = value;
    }
    if let Ok(new_value) = env::join_paths(parts) {
        cmd.env(name, new_value);
    }
}

pub fn prepend_path(name: &str, value: &Path, cmd: &mut Command) {
    let old_value = env::var_os(name);
    let mut parts = vec![value.to_owned()];
    if let Some(ref v) = old_value {
        parts.extend(env::split_paths(v));
    }
    let new_value = env::join_paths(parts).unwrap_or_else(|_| OsString::from(value));

    cmd.env(name, new_value);
}

pub fn inc(name: &str, cmd: &mut Command) {
    let old_value = env::var(name)
                        .ok()
                        .and_then(|v| v.parse().ok())
                        .unwrap_or(0);

    cmd.env(name, (old_value + 1).to_string());
}
<commit_msg>Allow append_path to be unused<commit_after>use std::ffi::OsString;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

#[allow(unused)]
pub fn append_path(name: &str, value: Vec<PathBuf>, cmd: &mut Command) {
    let old_value = env::var_os(name);
    let mut parts: Vec<PathBuf>;
    if let Some(ref v) = old_value {
        parts = env::split_paths(v).collect();
        parts.extend(value);
    } else {
        parts = value;
    }
    if let Ok(new_value) = env::join_paths(parts) {
        cmd.env(name, new_value);
    }
}

pub fn prepend_path(name: &str, value: &Path, cmd: &mut Command) {
    let old_value = env::var_os(name);
    let mut parts = vec![value.to_owned()];
    if let Some(ref v) = old_value {
        parts.extend(env::split_paths(v));
    }
    let new_value = env::join_paths(parts).unwrap_or_else(|_| OsString::from(value));

    cmd.env(name, new_value);
}

pub fn inc(name: &str, cmd: &mut Command) {
    let old_value = env::var(name)
                        .ok()
                        .and_then(|v| v.parse().ok())
                        .unwrap_or(0);

    cmd.env(name, (old_value + 1).to_string());
}
<|endoftext|>


<commit_before>use chrono::*;
use std::io::prelude::*;
use render::Renderer;
use result;
use hyper::client;
use hyper::net::Fresh;
use hyper::method;
use hyper::Url;

pub struct InfluxDbRenderer {
    write_url: String,
}

impl InfluxDbRenderer {
    pub fn new(write_url: String)
               -> InfluxDbRenderer {
        InfluxDbRenderer {
            write_url: write_url,
        }
    }
}

impl Renderer for InfluxDbRenderer {
    fn render(&mut self, result: result::RequestLogAnalyzerResult) -> () {
		let client = client::Client::new();
		let res = client.post(&self.write_url)
					.body(&post_body(result))
					.send()
					.unwrap();
    }
}

fn post_body(result: result::RequestLogAnalyzerResult) -> String {
	let mut timing_values = String::from("");
	let mut error_rate_values = String::from("");

	match result.timing {
		Some(timing) => {
			timing_values = format!("\
				time_max={} \
				time_min={} \
				time_avg={} \
				time_median={} \
				time_90percent={}",
				timing.max,
				timing.min,
				timing.avg,
				timing.median,
				timing.percentile90);
		}
		None => warn!("No matching log lines in file."),
	}

	match result.error {
		Some(error) => {
			error_rate_values = format!("\
				client_error_4xx_rate={} \
				server_error_5xx_rate={}",
				error.client_error_4xx,
				error.server_error_5xx);
		}
		None => warn!("No matching log lines in file."),
	}

	format!("request_log count={} {} {}", result.count, timing_values, error_rate_values)
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::prelude::*;
    use std::str;
    use chrono::*;
    use analyzer;
    use super::*;

    struct MockTcpStream {
        write_calls: Vec<String>,
    }

    impl Write for MockTcpStream {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
            Ok(1)
        }

        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    fn get_result_fixture() -> result::RequestLogAnalyzerResult {
        result::RequestLogAnalyzerResult {
            count: 3,
            timing: Some(analyzer::TimingResult {
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
                count: 3,
            }),
            error: Some(analyzer::aggregated_error_rates::ErrorRatesResult {
                client_error_4xx: 0.1,
                server_error_5xx: 0.2,
            }),
        }
    }

	#[test]
	fn test_instantiate() {
		InfluxDbRenderer::new(String::from("http://example.com/write?db=testdb"));
	}

	#[test]
	fn test_post_body() {
		let result = post_body(get_result_fixture());

		assert!(result.starts_with("request_log "));

		assert!(result.contains("count=3"));
		assert!(result.contains("time_max=100"));
		assert!(result.contains("time_min=1"));
		assert!(result.contains("time_avg=37"));
		assert!(result.contains("time_median=10"));
		assert!(result.contains("time_90percent=100"));
		assert!(result.contains("client_error_4xx_rate=0.1"));
		assert!(result.contains("server_error_5xx_rate=0.2"));

	}

	#[test]
	fn test_post_body_empty() {
		let result = post_body(result::RequestLogAnalyzerResult {
            count: 0,
            timing: None,
            error: None,
        });

		assert!(result.starts_with("request_log "));

		assert!(result.contains("count=0"));

		// Don't include empty fields
		assert!(!result.contains("time_max="));
		assert!(!result.contains("time_min="));
		assert!(!result.contains("time_avg="));
		assert!(!result.contains("time_median="));
		assert!(!result.contains("time_90percent="));
		assert!(!result.contains("client_error_4xx_rate="));
		assert!(!result.contains("server_error_5xx_rate="));
	}
}
<commit_msg>Clean up unused imports and structs<commit_after>use render::Renderer;
use result;
use hyper::client;

pub struct InfluxDbRenderer {
    write_url: String,
}

impl InfluxDbRenderer {
    pub fn new(write_url: String)
               -> InfluxDbRenderer {
        InfluxDbRenderer {
            write_url: write_url,
        }
    }
}

impl Renderer for InfluxDbRenderer {
    fn render(&mut self, result: result::RequestLogAnalyzerResult) -> () {
		let client = client::Client::new();
		let res = client.post(&self.write_url)
					.body(&post_body(result))
					.send()
					.unwrap();
    }
}

fn post_body(result: result::RequestLogAnalyzerResult) -> String {
	let mut timing_values = String::from("");
	let mut error_rate_values = String::from("");

	match result.timing {
		Some(timing) => {
			timing_values = format!("\
				time_max={} \
				time_min={} \
				time_avg={} \
				time_median={} \
				time_90percent={}",
				timing.max,
				timing.min,
				timing.avg,
				timing.median,
				timing.percentile90);
		}
		None => warn!("No matching log lines in file."),
	}

	match result.error {
		Some(error) => {
			error_rate_values = format!("\
				client_error_4xx_rate={} \
				server_error_5xx_rate={}",
				error.client_error_4xx,
				error.server_error_5xx);
		}
		None => warn!("No matching log lines in file."),
	}

	format!("request_log count={} {} {}", result.count, timing_values, error_rate_values)
}

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

    fn get_result_fixture() -> result::RequestLogAnalyzerResult {
        result::RequestLogAnalyzerResult {
            count: 3,
            timing: Some(analyzer::TimingResult {
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
                count: 3,
            }),
            error: Some(analyzer::aggregated_error_rates::ErrorRatesResult {
                client_error_4xx: 0.1,
                server_error_5xx: 0.2,
            }),
        }
    }

	#[test]
	fn test_instantiate() {
		InfluxDbRenderer::new(String::from("http://example.com/write?db=testdb"));
	}

	#[test]
	fn test_post_body() {
		let result = post_body(get_result_fixture());

		assert!(result.starts_with("request_log "));

		assert!(result.contains("count=3"));
		assert!(result.contains("time_max=100"));
		assert!(result.contains("time_min=1"));
		assert!(result.contains("time_avg=37"));
		assert!(result.contains("time_median=10"));
		assert!(result.contains("time_90percent=100"));
		assert!(result.contains("client_error_4xx_rate=0.1"));
		assert!(result.contains("server_error_5xx_rate=0.2"));

	}

	#[test]
	fn test_post_body_empty() {
		let result = post_body(result::RequestLogAnalyzerResult {
            count: 0,
            timing: None,
            error: None,
        });

		assert!(result.starts_with("request_log "));

		assert!(result.contains("count=0"));

		// Don't include empty fields
		assert!(!result.contains("time_max="));
		assert!(!result.contains("time_min="));
		assert!(!result.contains("time_avg="));
		assert!(!result.contains("time_median="));
		assert!(!result.contains("time_90percent="));
		assert!(!result.contains("client_error_4xx_rate="));
		assert!(!result.contains("server_error_5xx_rate="));
	}
}
<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate libc;
extern crate winapi;
extern crate "kernel32-sys" as kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

extern "system" {
    fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE) -> HANDLE;
    fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
    fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
}

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    conin: HANDLE,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            // Unlike in Linux, we *could* use the default stdin/stdout file handles to talk
            // directly to the console. However, we need the default stdin handle for the list of
            // choices, and we need to write just the final selection to stdout. Therefore we have
            // to explicitly create new handles to talk to the console. The gory details are
            // available at:
            //
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075%28v=vs.85%29.aspx
            // http://stackoverflow.com/questions/377152/what-does-createfileconin-do
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            conin: conin,
            conout: conout,
        }
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in range(0, self.height) {
            self.write(blank_line.as_slice());
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteFile(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
        let mut chars_read: DWORD = 0;
        win32!(ReadFile(self.conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));

        let mut ret = Vec::new();
        for i in range(0, chars_read) {
            ret.push(Screen::translate_byte(buf[i as usize]));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conin: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conin, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    let conout = unsafe { kernel32::GetStdHandle(-11) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<commit_msg>Update comment<commit_after>#![cfg(windows)]

extern crate libc;
extern crate winapi;
extern crate "kernel32-sys" as kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

extern "system" {
    fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE) -> HANDLE;
    fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
    fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
}

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    conin: HANDLE,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            // Unlike in Linux, we *could* use the default stdin/stdout file handles to talk
            // directly to the console. However, we need the default stdin handle for the list of
            // choices, and we need to write just the final selection to stdout. Therefore we have
            // to explicitly create new handles to talk to the console. The gory details are
            // available at:
            //
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075%28v=vs.85%29.aspx
            // http://stackoverflow.com/questions/377152/what-does-createfileconin-do
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            conin: conin,
            conout: conout,
        }
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in range(0, self.height) {
            self.write(blank_line.as_slice());
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteFile(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    // Currently the Windows implementation does not buffer, so this function just performs a
    // blocking read of a single key.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
        let mut chars_read: DWORD = 0;
        win32!(ReadFile(self.conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));

        let mut ret = Vec::new();
        for i in range(0, chars_read) {
            ret.push(Screen::translate_byte(buf[i as usize]));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conin: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conin, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    let conout = unsafe { kernel32::GetStdHandle(-11) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<|endoftext|>


<commit_before>use parse;
use serde::json;
use std::collections::btree_map::BTreeMap;
use std::fs::File;
use std::io::{self, Read};

impl parse::Value {
    fn to_json(&self) -> json::Value {
        let maybe_s = match *self {
            parse::Value::DataFile(ref path)    => slurp(path).ok(),
            parse::Value::DataString(ref s)     => Some(s.to_string()),
            parse::Value::FormFile(ref path)    => slurp(path).ok(),
            parse::Value::HttpHeader(ref s)     => Some(s.to_string()),
            parse::Value::RawJsonString(ref s)  => Some(s.to_string()),
            parse::Value::RawJsonFile(ref path) => slurp(path).ok().and_then(|s| json::from_str(&s).ok()),
            parse::Value::UrlParam(ref s)       => Some(s.to_string()),
        };
        match maybe_s {
            Some(s) => json::Value::String(s),
            None    => json::Value::Null,
        }
    }
}

pub fn to_json(pairs: &[parse::Pair]) -> String {
    let mut map = BTreeMap::new();
    for pair in pairs.iter() {
        let k = pair.0.clone();
        let v = pair.1.clone().map(|v| v.to_json()).unwrap_or(json::Value::Null);
        map.insert(k, v);
    }
    let root = json::Value::Object(map);
    json::ser::to_string(&root).unwrap_or("".to_string())
}

fn slurp(path: &str) -> io::Result<String> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}
<commit_msg>Raw JSON value is now correctly raw<commit_after>use parse;
use serde::json;
use std::collections::btree_map::BTreeMap;
use std::fs::File;
use std::io::{self, Read};

impl parse::Value {
    fn to_json(&self) -> Option<json::Value> {
        match *self {
            parse::Value::DataFile(ref path) => {
                slurp(path)
                    .ok()
                    .and_then(|s| Some(json::Value::String(s)))
            }
            parse::Value::DataString(ref s) => {
                Some(json::Value::String(s.to_string()))
            }
            parse::Value::FormFile(ref path) => {
                slurp(path)
                    .ok()
                    .and_then(|s| Some(json::Value::String(s)))
            }
            parse::Value::HttpHeader(ref s) => {
                Some(json::Value::String(s.to_string()))
            }
            parse::Value::RawJsonString(ref s) => {
                json::from_str(s).unwrap_or(None)
            }
            parse::Value::RawJsonFile(ref path) => {
                slurp(path)
                    .ok()
                    .and_then(|s| json::from_str(&s).ok())
            }
            parse::Value::UrlParam(ref s) => {
                Some(json::Value::String(s.to_string()))
            }
        }
    }
}

pub fn to_json(pairs: &[parse::Pair]) -> String {
    let mut map = BTreeMap::new();
    for pair in pairs.iter() {
        let maybe_v = pair.1.clone().and_then(|v| v.to_json());
        if let Some(v) = maybe_v {
            let k = pair.0.clone();
            map.insert(k, v);
        }
    }
    let root = json::Value::Object(map);
    json::ser::to_string(&root).unwrap_or("".to_string())
}

fn slurp(path: &str) -> io::Result<String> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}
<|endoftext|>


<commit_before>use structure;

pub mod integer;
pub mod sequence;
pub mod octetstring;
pub mod boolean;
pub mod null;
pub mod explicit;

// Reexport everything
pub use self::integer::Integer;
pub use self::sequence::{Sequence, SequenceOf, SetOf};
pub use self::octetstring::OctetString;
pub use self::boolean::Boolean;
pub use self::null::Null;

pub trait ASNTag {
    /// Encode yourself into a generic Tag format.
    ///
    /// The only thing that changes between types is how to encode the value they wrap into bytes,
    /// however the encoding of the class and id does not change. By first converting the tag into
    /// a more generic tag (with already encoded payload), we don't have to reimplement the
    /// encoding step for class & id every time.
    fn into_structure(self) -> structure::StructureTag;
}

#[derive(Clone, Debug)]
/// This enum does not cover all ASN.1 Types but only the types needed for LDAPv3.
pub enum Tag {
    Integer(integer::Integer),
    Sequence(sequence::Sequence),
    OctetString(octetstring::OctetString),
    Boolean(boolean::Boolean),
    Null(null::Null),
    ExplicitTag(explicit::ExplicitTag),
    StructureTag(structure::StructureTag),
}

impl ASNTag for Tag {
    fn into_structure(self) -> structure::StructureTag {
        match self {
            Tag::Integer(i)      => i.into_structure(),
            Tag::Sequence(i)     => i.into_structure(),
            Tag::OctetString(i)  => i.into_structure(),
            Tag::Boolean(i)      => i.into_structure(),
            Tag::Null(i)         => i.into_structure(),
            Tag::ExplicitTag(i)  => i.into_structure(),
            Tag::StructureTag(s) => s
        }
    }
}
<commit_msg>Reexports ExplicitTag<commit_after>use structure;

pub mod integer;
pub mod sequence;
pub mod octetstring;
pub mod boolean;
pub mod null;
pub mod explicit;

// Reexport everything
pub use self::integer::Integer;
pub use self::sequence::{Sequence, SequenceOf, SetOf};
pub use self::octetstring::OctetString;
pub use self::boolean::Boolean;
pub use self::null::Null;
pub use self::explicit::ExplicitTag;

pub trait ASNTag {
    /// Encode yourself into a generic Tag format.
    ///
    /// The only thing that changes between types is how to encode the value they wrap into bytes,
    /// however the encoding of the class and id does not change. By first converting the tag into
    /// a more generic tag (with already encoded payload), we don't have to reimplement the
    /// encoding step for class & id every time.
    fn into_structure(self) -> structure::StructureTag;
}

#[derive(Clone, Debug)]
/// This enum does not cover all ASN.1 Types but only the types needed for LDAPv3.
pub enum Tag {
    Integer(integer::Integer),
    Sequence(sequence::Sequence),
    OctetString(octetstring::OctetString),
    Boolean(boolean::Boolean),
    Null(null::Null),
    ExplicitTag(explicit::ExplicitTag),
    StructureTag(structure::StructureTag),
}

impl ASNTag for Tag {
    fn into_structure(self) -> structure::StructureTag {
        match self {
            Tag::Integer(i)      => i.into_structure(),
            Tag::Sequence(i)     => i.into_structure(),
            Tag::OctetString(i)  => i.into_structure(),
            Tag::Boolean(i)      => i.into_structure(),
            Tag::Null(i)         => i.into_structure(),
            Tag::ExplicitTag(i)  => i.into_structure(),
            Tag::StructureTag(s) => s
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Fabian Schuiki

//! Name resolution.
//!
//! This module implements the infrastructure to describe scopes and resolve
//! names in them.

use crate::{ast_map::AstNode, crate_prelude::*, hir::HirNode, ParamEnv};
use std::collections::HashMap;

/// One local scope.
///
/// A rib represents a any kind of scope. Ribs form a tree structure along their
/// parents that may be traversed from the bottom to the top to perform name
/// resolution, or top to bottom to lookup hierarchical names.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Rib {
    /// The node this rib is associated with.
    ///
    /// When querying the compiler for a node's rib, what you get in return is
    /// not necessarily the rib of that node. If the node does not generate a
    /// new rib, you get back the rib of a parent node.
    pub node: NodeId,
    /// The parent rib.
    ///
    /// Note that this does not necessarily correspond to the parent node, but
    /// may skip nodes that do not contain a rib.
    pub parent: Option<NodeId>,
    /// The data associated with the rib.
    pub kind: RibKind,
}

/// A local scope kind.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RibKind {
    /// A normal declaration.
    Normal(Spanned<Name>, NodeId),
    /// A module.
    Module(HashMap<Name, NodeId>),
}

impl Rib {
    /// Look up a name.
    pub fn get(&self, name: Name) -> Option<NodeId> {
        self.kind.get(name)
    }
}

impl RibKind {
    /// Look up a name.
    pub fn get(&self, name: Name) -> Option<NodeId> {
        match *self {
            RibKind::Normal(n, id) if n.value == name => Some(id),
            RibKind::Module(ref defs) => defs.get(&name).cloned(),
            _ => None,
        }
    }
}

/// Determine the local rib that applies to a node.
///
/// This will return either the rib the node itself generates, or the next rib
/// up the hierarchy.
pub(crate) fn local_rib<'gcx>(cx: &impl Context<'gcx>, node_id: NodeId) -> Result<&'gcx Rib> {
    let ast = cx.ast_of(node_id)?;
    let kind = match ast {
        AstNode::TypeParam(_, decl) => {
            RibKind::Normal(Spanned::new(decl.name.name, decl.name.span), node_id)
        }
        AstNode::ValueParam(_, decl) => {
            RibKind::Normal(Spanned::new(decl.name.name, decl.name.span), node_id)
        }
        AstNode::Module(_) => RibKind::Module(HashMap::new()),
        AstNode::VarDecl(decl, _, _) => {
            RibKind::Normal(Spanned::new(decl.name, decl.name_span), node_id)
        }
        AstNode::GenvarDecl(decl) => {
            RibKind::Normal(Spanned::new(decl.name, decl.name_span), node_id)
        }
        AstNode::Typedef(def) => {
            RibKind::Normal(Spanned::new(def.name.name, def.name.span), node_id)
        }
        _ => {
            return cx.local_rib(
                cx.parent_node_id(node_id)
                    .expect("root node must produce a rib"),
            );
        }
    };
    let rib = Rib {
        node: node_id,
        parent: match cx.parent_node_id(node_id) {
            Some(parent_id) => Some(cx.local_rib(parent_id)?.node),
            None => None,
        },
        kind: kind,
    };
    Ok(cx.arena().alloc_rib(rib))
}

/// Resolve a name upwards through the ribs.
///
/// This is equivalent to performing regular scoped namespace lookup.
pub(crate) fn resolve_upwards<'gcx>(
    cx: &impl Context<'gcx>,
    name: Name,
    start_at: NodeId,
) -> Result<Option<NodeId>> {
    let mut next_id = Some(start_at);
    while let Some(rib_id) = next_id {
        let rib = cx.local_rib(rib_id)?;
        if let id @ Some(_) = rib.get(name) {
            return Ok(id);
        }
        next_id = rib.parent;
    }
    Ok(None)
}

/// Resolve a node to its target.
pub(crate) fn resolve_node<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    _env: ParamEnv,
) -> Result<NodeId> {
    let hir = cx.hir_of(node_id)?;
    match hir {
        HirNode::Expr(expr) => match expr.kind {
            hir::ExprKind::Ident(ident) => return cx.resolve_upwards_or_error(ident, node_id),
            _ => (),
        },
        _ => (),
    }
    panic!("cannot resolve {:?}", hir)
}
<commit_msg>svlog: declare port names<commit_after>// Copyright (c) 2016-2019 Fabian Schuiki

//! Name resolution.
//!
//! This module implements the infrastructure to describe scopes and resolve
//! names in them.

use crate::{ast_map::AstNode, crate_prelude::*, hir::HirNode, ParamEnv};
use std::collections::HashMap;

/// One local scope.
///
/// A rib represents a any kind of scope. Ribs form a tree structure along their
/// parents that may be traversed from the bottom to the top to perform name
/// resolution, or top to bottom to lookup hierarchical names.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Rib {
    /// The node this rib is associated with.
    ///
    /// When querying the compiler for a node's rib, what you get in return is
    /// not necessarily the rib of that node. If the node does not generate a
    /// new rib, you get back the rib of a parent node.
    pub node: NodeId,
    /// The parent rib.
    ///
    /// Note that this does not necessarily correspond to the parent node, but
    /// may skip nodes that do not contain a rib.
    pub parent: Option<NodeId>,
    /// The data associated with the rib.
    pub kind: RibKind,
}

/// A local scope kind.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RibKind {
    /// A normal declaration.
    Normal(Spanned<Name>, NodeId),
    /// A module.
    Module(HashMap<Name, NodeId>),
}

impl Rib {
    /// Look up a name.
    pub fn get(&self, name: Name) -> Option<NodeId> {
        self.kind.get(name)
    }
}

impl RibKind {
    /// Look up a name.
    pub fn get(&self, name: Name) -> Option<NodeId> {
        match *self {
            RibKind::Normal(n, id) if n.value == name => Some(id),
            RibKind::Module(ref defs) => defs.get(&name).cloned(),
            _ => None,
        }
    }
}

/// Determine the local rib that applies to a node.
///
/// This will return either the rib the node itself generates, or the next rib
/// up the hierarchy.
pub(crate) fn local_rib<'gcx>(cx: &impl Context<'gcx>, node_id: NodeId) -> Result<&'gcx Rib> {
    let ast = cx.ast_of(node_id)?;
    let kind = match ast {
        AstNode::TypeParam(_, decl) => {
            RibKind::Normal(Spanned::new(decl.name.name, decl.name.span), node_id)
        }
        AstNode::ValueParam(_, decl) => {
            RibKind::Normal(Spanned::new(decl.name.name, decl.name.span), node_id)
        }
        AstNode::Module(_) => RibKind::Module(HashMap::new()),
        AstNode::VarDecl(decl, _, _) => {
            RibKind::Normal(Spanned::new(decl.name, decl.name_span), node_id)
        }
        AstNode::GenvarDecl(decl) => {
            RibKind::Normal(Spanned::new(decl.name, decl.name_span), node_id)
        }
        AstNode::Typedef(def) => {
            RibKind::Normal(Spanned::new(def.name.name, def.name.span), node_id)
        }
        AstNode::Port(&ast::Port::Named { name, .. }) => {
            RibKind::Normal(Spanned::new(name.name, name.span), node_id)
        }
        _ => {
            return cx.local_rib(
                cx.parent_node_id(node_id)
                    .expect("root node must produce a rib"),
            );
        }
    };
    let rib = Rib {
        node: node_id,
        parent: match cx.parent_node_id(node_id) {
            Some(parent_id) => Some(cx.local_rib(parent_id)?.node),
            None => None,
        },
        kind: kind,
    };
    Ok(cx.arena().alloc_rib(rib))
}

/// Resolve a name upwards through the ribs.
///
/// This is equivalent to performing regular scoped namespace lookup.
pub(crate) fn resolve_upwards<'gcx>(
    cx: &impl Context<'gcx>,
    name: Name,
    start_at: NodeId,
) -> Result<Option<NodeId>> {
    let mut next_id = Some(start_at);
    while let Some(rib_id) = next_id {
        let rib = cx.local_rib(rib_id)?;
        if let id @ Some(_) = rib.get(name) {
            return Ok(id);
        }
        next_id = rib.parent;
    }
    Ok(None)
}

/// Resolve a node to its target.
pub(crate) fn resolve_node<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    _env: ParamEnv,
) -> Result<NodeId> {
    let hir = cx.hir_of(node_id)?;
    match hir {
        HirNode::Expr(expr) => match expr.kind {
            hir::ExprKind::Ident(ident) => return cx.resolve_upwards_or_error(ident, node_id),
            _ => (),
        },
        _ => (),
    }
    panic!("cannot resolve {:?}", hir)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     int,                    // Program counter (index within ante.code)
    line:   int,                    // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new() -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        Ante {
            pc:     0,
            line:   0,
            code:   vec![],
            vars:   vars,
            labels: HashMap::new(),
            buffer: vec![]
        }
    }

    fn run(&mut self, filename: &str) {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);
        self.parse(program.as_slice())
    }

    // Turn source file into array of cards.
    fn parse(&mut self, program: &str) {
        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            self.code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                self.code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, self.code.len()) {
            println!("{:2}) code: /{}:{}/", i, self.code[i].rank, self.code[i].suit);
        }

    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new().run("factorial.ante".as_slice());
}
<commit_msg>Extra pass to set up jump labels<commit_after>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new() -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        Ante {
            pc:     0,
            line:   0,
            code:   vec![],
            vars:   vars,
            labels: HashMap::new(),
            buffer: vec![]
        }
    }

    fn run(&mut self, filename: &str) {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);
        self.parse(program.as_slice())
    }

    // Turn source file into array of cards.
    fn parse(&mut self, program: &str) {
        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            self.code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                self.code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, self.code.len()) {
            println!("{:2}) code: /{}:{}/", i, self.code[i].rank, self.code[i].suit);
        }

        // Extra pass to set up jump labels.
        let mut pc = 0u;
        while pc < self.code.len() - 1 {
            let card = self.code[pc];
            pc += 1;
            if card.rank == 81 { // 'Q'
                let mut queen = card.suit as uint;
                while pc < self.code.len() - 1 && self.code[pc].rank == 81 && self.code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                self.labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in self.labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new().run("factorial.ante".as_slice());
}
<|endoftext|>