<commit_before>extern crate regex;
extern crate readline;

mod errors;
mod atom;
mod parser;

use parser::*;
use atom::*;
use errors::Error;
use errors::Error::*;

use std::collections::HashMap;
use std::string::String;
type EvalResult = Result<Eval, Error>;
type Function = Fn(&Vec<Eval>) -> EvalResult;
type FunctionMap = HashMap<String, Box<Function>>;

fn nil_func(_: &Vec<Eval>) -> EvalResult {
    return Ok(Eval::Atom(Atom::Nil));
}

struct Env {
    func_map: FunctionMap,
    def_map: HashMap<String, Eval>
}

fn add(v: &Vec<Eval>) -> EvalResult {
    let mut result = 0;

    for i in v {
        if let Eval::Atom(Atom::Integer(d)) = *i {
                result += d
        } else {
            return Err(Error::UnexpectedType);
        }
    }

    return Ok(Eval::Atom(Atom::Integer(result)));
}

fn sub(v: &Vec<Eval>) -> EvalResult {
    if v.len() < 1 {
        return Err(Error::InvalidArguments)
    }

    let mut result = match v[0] {
        Eval::Atom(Atom::Integer(d)) => d,
        _ => return Err(Error::UnexpectedType)
    };

    for i in v.iter().skip(1) {
        match *i {
            Eval::Atom(Atom::Integer(d)) => result -= d,
            _ => return Err(Error::UnexpectedType)
        }
    }

    return Ok(Eval::Atom(Atom::Integer(result)));
}

fn equals(args: &Vec<Eval>) -> EvalResult {
    let v = &args[0];

    for i in args.iter().skip(1) {
        if v != i {
            return Ok(Eval::Atom(Atom::Boolean(false)));
        }
    }
    Ok(Eval::Atom(Atom::Boolean(true)))
}

fn default_env() -> Env {
    let mut env = Env{func_map: HashMap::new(), def_map: HashMap::new()};

    env.func_map.insert("nil".to_string(), Box::new(nil_func) as Box<Function>);
    env.func_map.insert("+".to_string(), Box::new(add) as Box<Function>);
    env.func_map.insert("-".to_string(), Box::new(sub) as Box<Function>);
    env.func_map.insert("=".to_string(), Box::new(equals) as Box<Function>);

    return env;
}

fn define(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    if args.len() != 2 {
        return Err(Error::InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        env.def_map.insert(key.clone(), args[1].clone());
        Ok(Eval::Atom(Atom::Nil))
    } else {
        Err(Error::InvalidArguments)
    }
}

fn set(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    // FIXME: get rid of the clones
    if args.len() != 2 {
        return Err(InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        if env.def_map.contains_key(key) {
            let entry = env.def_map.entry((*key).clone()).or_insert(Eval::Atom(Atom::Nil));
            *entry = args[1].clone();
            return Ok(args[1].clone())
        }
    }
    Err(InvalidArguments)
}

fn get(args: Vec<Eval>, env: &Env) -> EvalResult {
    if args.len() != 1 {
        return Err(Error::InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref s)) = args[0] {
        if let Some(a) = env.def_map.get(s) {
            Ok(a.clone())
        } else {
            Ok(Eval::Atom(Atom::Nil))
        }
    } else {
        Err(Error::InvalidArguments)
    }
}

fn eval_args(list: &Vec<Node>, env: &mut Env) -> Result<Vec<Eval>, Error> {
    let mut args = vec![];

    for i in list.iter().skip(1) {
        let atom = try!(eval(i, env));
        args.push(atom);
    }
    return Ok(args);
}
#[derive(Debug, Clone, PartialEq)]
enum Eval {
    Atom(Atom),
    Node(Node)
}

fn eval(node: &Node, env: &mut Env) -> Result<Eval, Error> {
    match node {
        &Node::List(ref list) => {
            match list[0] {
                Node::Atom(ref atom) => {
                    if let &Atom::Symbol(ref s) = atom {
                        match s.as_ref() {
                            "def" => {
                                let args = try!(eval_args(&list, env));
                                return define(args, env);
                            },
                            "quote" => {
                                return Ok(Eval::Node(Node::List(list.clone())))
                            },
                            "set!" => {
                                return set( try!(eval_args(&list, env)), env);
                            },
                            "get" => {
                                return get( try!(eval_args(&list, env)), env);
                            },
                            "if" => {
                                let predicate = try!(eval(&list[1], env));

                                let truthy = match predicate {
                                    Eval::Atom(Atom::Boolean(b)) => b,
                                    Eval::Atom(Atom::Nil) => false,
                                    _ => true
                                };

                                if truthy {
                                    return eval(&list[2], env);
                                } else if list.len() > 2 {
                                    return eval(&list[3], env);
                                } else {
                                    return Ok(Eval::Atom(Atom::Boolean(false)))
                                }
                            },
                            _ => ()
                        };

                        let args = try!(eval_args(&list, env));
                        if let Some(f) = env.func_map.get(s) {
                            f(&args)
                        } else {
                            Ok(Eval::Atom(Atom::Nil))
                        }
                    } else {
                        Err(Error::NotAFunction)
                    }
                },
                Node::List(_) => panic!("derp")
            }
        },
        &Node::Atom(ref atom) => Ok(Eval::Atom(atom.clone()))
    }
}

fn repl() {
    println!("Rust Lisp!");
    let mut env = default_env();

    loop {
        match readline::readline(">") {
            Some(s) => {
                if let Ok(p) = parser::tokenize(&s) {
                    match eval(&p, &mut env) {
                        Ok(r) => println!("{:?}", r),
                        Err(e) => println!("Error in evaluation: {:?}", e)
                    }
                } else {
                    println!("Error in parsing");
                }
            },
            None => {
                println!("Exiting...");
                break;
            }
        }
    }
}

pub fn main() {
    repl();
}

#[cfg(test)]
mod test {
    use parser::*;
    use super::default_env;
    use super::eval;
    use atom::Atom;

    fn teval(s: &str) -> Atom {
        eval(&tokenize(s).unwrap(), &mut default_env()).unwrap()
    }

    fn make_atom_node(s: &str) -> Node {
        return Node::Atom(Atom::parse(s));
    }

    fn as_list(n: &Node) -> &Vec<Node> {
        match n {
            &Node::List(ref l) => l,
            _ => panic!("don't get here!")
        }
    }

    fn as_atom(n: &Node) -> &Atom {
        match n {
            &Node::Atom(ref a) => a,
            _ => panic!("not here!")
        }
    }

    fn atom(s: &str) -> Atom {
        Atom::parse(s)
    }

    #[test]
    fn simple_read_tokens() {
        let x = tokenize("(+ 1 2)").unwrap();

        let l = as_list(&x);

        assert_eq!(3, l.len());

        let xx : Vec<Node> = vec![make_atom_node("+"), make_atom_node("1"), make_atom_node("2")];

        for pair in xx.iter().zip(l.iter()) {
            assert_eq!(pair.0, pair.1);
        }
    }

    #[test]
    fn nested_read_tokens() {
        let x = tokenize("(+ 1 (* 2 2))").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l.len());
        assert_eq!( atom("*"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("2"), *as_atom(&l2[2]));
    }

    #[test]
    fn subexp_token_test() {
        let x = tokenize("(+ 1 (+ 2 3) 4)").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l2.len());
        assert_eq!( atom("+"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("3"), *as_atom(&l2[2]));

        assert_eq!(atom("4"), *as_atom(&l[3]));
    }

    #[test]
    fn if_special_form() {
        let x = eval(&tokenize("(if (= 1 1) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Atom::Boolean(true), x);
    }

    #[test]
    fn if_special_form_false() {
        let x = eval(&tokenize("(if (= 1 2) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Atom::Boolean(false), x);
    }

    #[test]
    fn if_no_else() {
        let x = teval("(if (= 1 1) true)");

        assert_eq!(Atom::Boolean(true), x);
    }

    #[test]
    #[should_panic]
    fn unmatched_bracket() {
        tokenize("(+ 1").unwrap();
    }

    #[test]
    #[should_panic]
    fn eof() {
         tokenize("").unwrap();
    }
}
<commit_msg>quote should eat the quote function<commit_after>extern crate regex;
extern crate readline;

mod errors;
mod atom;
mod parser;

use parser::*;
use atom::*;
use errors::Error;
use errors::Error::*;

use std::collections::HashMap;
use std::string::String;
type EvalResult = Result<Eval, Error>;
type Function = Fn(&Vec<Eval>) -> EvalResult;
type FunctionMap = HashMap<String, Box<Function>>;

fn nil_func(_: &Vec<Eval>) -> EvalResult {
    return Ok(Eval::Atom(Atom::Nil));
}

struct Env {
    func_map: FunctionMap,
    def_map: HashMap<String, Eval>
}

fn add(v: &Vec<Eval>) -> EvalResult {
    let mut result = 0;

    for i in v {
        if let Eval::Atom(Atom::Integer(d)) = *i {
                result += d
        } else {
            return Err(Error::UnexpectedType);
        }
    }

    return Ok(Eval::Atom(Atom::Integer(result)));
}

fn sub(v: &Vec<Eval>) -> EvalResult {
    if v.len() < 1 {
        return Err(Error::InvalidArguments)
    }

    let mut result = match v[0] {
        Eval::Atom(Atom::Integer(d)) => d,
        _ => return Err(Error::UnexpectedType)
    };

    for i in v.iter().skip(1) {
        match *i {
            Eval::Atom(Atom::Integer(d)) => result -= d,
            _ => return Err(Error::UnexpectedType)
        }
    }

    return Ok(Eval::Atom(Atom::Integer(result)));
}

fn equals(args: &Vec<Eval>) -> EvalResult {
    let v = &args[0];

    for i in args.iter().skip(1) {
        if v != i {
            return Ok(Eval::Atom(Atom::Boolean(false)));
        }
    }
    Ok(Eval::Atom(Atom::Boolean(true)))
}

fn default_env() -> Env {
    let mut env = Env{func_map: HashMap::new(), def_map: HashMap::new()};

    env.func_map.insert("nil".to_string(), Box::new(nil_func) as Box<Function>);
    env.func_map.insert("+".to_string(), Box::new(add) as Box<Function>);
    env.func_map.insert("-".to_string(), Box::new(sub) as Box<Function>);
    env.func_map.insert("=".to_string(), Box::new(equals) as Box<Function>);

    return env;
}

fn define(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    if args.len() != 2 {
        return Err(Error::InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        env.def_map.insert(key.clone(), args[1].clone());
        Ok(Eval::Atom(Atom::Nil))
    } else {
        Err(Error::InvalidArguments)
    }
}

fn set(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    // FIXME: get rid of the clones
    if args.len() != 2 {
        return Err(InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        if env.def_map.contains_key(key) {
            let entry = env.def_map.entry((*key).clone()).or_insert(Eval::Atom(Atom::Nil));
            *entry = args[1].clone();
            return Ok(args[1].clone())
        }
    }
    Err(InvalidArguments)
}

fn get(args: Vec<Eval>, env: &Env) -> EvalResult {
    if args.len() != 1 {
        return Err(Error::InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref s)) = args[0] {
        if let Some(a) = env.def_map.get(s) {
            Ok(a.clone())
        } else {
            Ok(Eval::Atom(Atom::Nil))
        }
    } else {
        Err(Error::InvalidArguments)
    }
}

fn eval_args(list: &Vec<Node>, env: &mut Env) -> Result<Vec<Eval>, Error> {
    let mut args = vec![];

    for i in list.iter().skip(1) {
        let atom = try!(eval(i, env));
        args.push(atom);
    }
    return Ok(args);
}
#[derive(Debug, Clone, PartialEq)]
enum Eval {
    Atom(Atom),
    Node(Node)
}

fn quote(v: &Vec<Node>) -> Result<Eval, Error> {
    return Ok(Eval::Node(v[1].clone()));
}

fn eval(node: &Node, env: &mut Env) -> Result<Eval, Error> {
    match node {
        &Node::List(ref list) => {
            match list[0] {
                Node::Atom(ref atom) => {
                    if let &Atom::Symbol(ref s) = atom {
                        match s.as_ref() {
                            "def" => {
                                let args = try!(eval_args(&list, env));
                                return define(args, env);
                            },
                            "quote" => {
                                return quote(&list);
                            },
                            "set!" => {
                                return set( try!(eval_args(&list, env)), env);
                            },
                            "get" => {
                                return get( try!(eval_args(&list, env)), env);
                            },
                            "if" => {
                                let predicate = try!(eval(&list[1], env));

                                let truthy = match predicate {
                                    Eval::Atom(Atom::Boolean(b)) => b,
                                    Eval::Atom(Atom::Nil) => false,
                                    _ => true
                                };

                                if truthy {
                                    return eval(&list[2], env);
                                } else if list.len() > 2 {
                                    return eval(&list[3], env);
                                } else {
                                    return Ok(Eval::Atom(Atom::Boolean(false)))
                                }
                            },
                            _ => ()
                        };

                        let args = try!(eval_args(&list, env));
                        if let Some(f) = env.func_map.get(s) {
                            f(&args)
                        } else {
                            Ok(Eval::Atom(Atom::Nil))
                        }
                    } else {
                        Err(Error::NotAFunction)
                    }
                },
                Node::List(_) => panic!("derp")
            }
        },
        &Node::Atom(ref atom) => Ok(Eval::Atom(atom.clone()))
    }
}

fn repl() {
    println!("Rust Lisp!");
    let mut env = default_env();

    loop {
        match readline::readline(">") {
            Some(s) => {
                if let Ok(p) = parser::tokenize(&s) {
                    match eval(&p, &mut env) {
                        Ok(r) => println!("{:?}", r),
                        Err(e) => println!("Error in evaluation: {:?}", e)
                    }
                } else {
                    println!("Error in parsing");
                }
            },
            None => {
                println!("Exiting...");
                break;
            }
        }
    }
}

pub fn main() {
    repl();
}

#[cfg(test)]
mod test {
    use parser::*;
    use super::default_env;
    use super::eval;
    use atom::Atom;

    fn teval(s: &str) -> Atom {
        eval(&tokenize(s).unwrap(), &mut default_env()).unwrap()
    }

    fn make_atom_node(s: &str) -> Node {
        return Node::Atom(Atom::parse(s));
    }

    fn as_list(n: &Node) -> &Vec<Node> {
        match n {
            &Node::List(ref l) => l,
            _ => panic!("don't get here!")
        }
    }

    fn as_atom(n: &Node) -> &Atom {
        match n {
            &Node::Atom(ref a) => a,
            _ => panic!("not here!")
        }
    }

    fn atom(s: &str) -> Atom {
        Atom::parse(s)
    }

    #[test]
    fn simple_read_tokens() {
        let x = tokenize("(+ 1 2)").unwrap();

        let l = as_list(&x);

        assert_eq!(3, l.len());

        let xx : Vec<Node> = vec![make_atom_node("+"), make_atom_node("1"), make_atom_node("2")];

        for pair in xx.iter().zip(l.iter()) {
            assert_eq!(pair.0, pair.1);
        }
    }

    #[test]
    fn nested_read_tokens() {
        let x = tokenize("(+ 1 (* 2 2))").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l.len());
        assert_eq!( atom("*"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("2"), *as_atom(&l2[2]));
    }

    #[test]
    fn subexp_token_test() {
        let x = tokenize("(+ 1 (+ 2 3) 4)").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l2.len());
        assert_eq!( atom("+"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("3"), *as_atom(&l2[2]));

        assert_eq!(atom("4"), *as_atom(&l[3]));
    }

    #[test]
    fn if_special_form() {
        let x = eval(&tokenize("(if (= 1 1) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Atom::Boolean(true), x);
    }

    #[test]
    fn if_special_form_false() {
        let x = eval(&tokenize("(if (= 1 2) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Atom::Boolean(false), x);
    }

    #[test]
    fn if_no_else() {
        let x = teval("(if (= 1 1) true)");

        assert_eq!(Atom::Boolean(true), x);
    }

    #[test]
    #[should_panic]
    fn unmatched_bracket() {
        tokenize("(+ 1").unwrap();
    }

    #[test]
    #[should_panic]
    fn eof() {
         tokenize("").unwrap();
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>first real code commit<commit_after>fn main() {
    for x in 1..31 {
    	if x %3 == 0 && x %5 == 0{
    		println!("fizzbuzz");
    	}
    	else if x %3 == 0{
    		println!("fizz");
    	}
    	else if x %5 == 0{
    		println!("buzz");
    	}
    	else{
    	println!("{}", x);
    	}
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate postgres;

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

extern crate getopts;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::fs;
use std::fs::File;
use std::io::{Write, BufWriter};

mod pombase {
    use std::rc::Rc;
    use std::collections::HashMap;
    use postgres::Connection;

    use pombase::db::*;

    pub struct Raw {
        pub cvs: Vec<Rc<Cv>>,
        pub dbs: Vec<Rc<Db>>,
        pub dbxrefs: Vec<Rc<Dbxref>>,
        pub cvterms: Vec<Rc<Cvterm>>,
        pub cvtermpaths: Vec<Rc<Cvtermpath>>,
        pub cvterm_relationships: Vec<Rc<CvtermRelationship>>,
        pub publications: Vec<Rc<Publication>>,
        pub features: Vec<Rc<Feature>>,
    }

    impl Raw {
        pub fn new(conn: &Connection) -> Raw {
            let mut ret = Raw {
                cvs: vec![], dbs: vec![], dbxrefs: vec![], cvterms: vec![],
                cvtermpaths: vec![], cvterm_relationships: vec![],
                publications: vec![], features: vec![],
            };

            let mut cv_map: HashMap<i32, Rc<Cv>> = HashMap::new();
            let mut db_map: HashMap<i32, Rc<Db>> = HashMap::new();
            let mut dbxref_map: HashMap<i32, Rc<Dbxref>> = HashMap::new();
            let mut cvterm_map: HashMap<i32, Rc<Cvterm>> = HashMap::new();
            let mut feature_map: HashMap<i32, Rc<Feature>> = HashMap::new();
            let mut publication_map: HashMap<i32, Rc<Publication>> = HashMap::new();

            for row in &conn.query("SELECT cv_id, name FROM cv", &[]).unwrap() {
                let cv = Cv {
                    name: row.get(1),
                };
                let rc_cv = Rc::new(cv);
                ret.cvs.push(rc_cv.clone());
                cv_map.insert(row.get(0), rc_cv);
            }

            for row in &conn.query("SELECT db_id, name FROM db", &[]).unwrap() {
                let db_id = row.get(0);
                let db = Db {
                    name: row.get(1),
                };
                let rc_db = Rc::new(db);
                ret.dbs.push(rc_db.clone());
                db_map.insert(db_id, rc_db);
            }

            for row in &conn.query("SELECT dbxref_id, db_id, accession FROM dbxref", &[]).unwrap() {
                let dbxref_id: i32 = row.get(0);
                let db_id: i32 = row.get(1);
                let dbxref = Dbxref {
                    db: db_map.get(&db_id).unwrap().clone(),
                    accession: row.get(2),
                };
                let rc_dbxref = Rc::new(dbxref);
                ret.dbxrefs.push(rc_dbxref.clone());
                dbxref_map.insert(dbxref_id, rc_dbxref);
            }

            for row in &conn.query("SELECT cvterm_id, cv_id, dbxref_id, name FROM cvterm", &[]).unwrap() {
                let cvterm_id: i32 = row.get(0);
                let cv_id: i32 = row.get(1);
                let dbxref_id: i32 = row.get(2);
                let cvterm = Cvterm {
                    cv: cv_map.get(&cv_id).unwrap().clone(),
                    dbxref: dbxref_map.get(&dbxref_id).unwrap().clone(),
                    name: row.get(3),
                };
                let rc_cvterm = Rc::new(cvterm);
                ret.cvterms.push(rc_cvterm.clone());
                cvterm_map.insert(cvterm_id, rc_cvterm);
            }

            for row in &conn.query("SELECT pub_id, uniquename, type_id, title FROM pub", &[]).unwrap() {
                let pub_id: i32 = row.get(0);
                let uniquename: String = row.get(1);
                let type_id: i32 = row.get(2);
                let title: Option<String> = row.get(3);
                let publication = Publication {
                    uniquename: uniquename,
                    pub_type: cvterm_map.get(&type_id).unwrap().clone(),
                    title: title
                };
                let rc_publication = Rc::new(publication);
                ret.publications.push(rc_publication.clone());
                publication_map.insert(pub_id, rc_publication);
            }

            for row in &conn.query("SELECT feature_id, uniquename, name, type_id FROM feature", &[]).unwrap() {
                let feature_id = row.get(0);
                let type_id: i32 = row.get(3);
                let feature = Feature {
                    uniquename: row.get(1),
                    name: row.get(2),
                    feat_type: cvterm_map.get(&type_id).unwrap().clone(),
                };
                let rc_feature = Rc::new(feature);
                ret.features.push(rc_feature.clone());
                feature_map.insert(feature_id, rc_feature);
            }

            ret
        }
    }

    pub mod db {
        use std::rc::Rc;

        pub struct Feature {
            pub uniquename: String,
            pub name: Option<String>,
            pub feat_type: Rc<Cvterm>,
        }
        pub struct Cv {
            pub name: String,
        }
        pub struct Db {
            pub name: String,
        }
        pub struct Dbxref {
            pub accession: String,
            pub db: Rc<Db>,
        }
        pub struct Cvterm {
            pub name: String,
            pub cv: Rc<Cv>,
            pub dbxref: Rc<Dbxref>,
        }
        pub struct Publication {
            pub uniquename: String,
            pub pub_type: Rc<Cvterm>,
            pub title: Option<String>,
        }
        pub struct CvtermRelationship {
            pub subject: Rc<Cvterm>,
            pub object: Rc<Cvterm>,
            pub reltype: Rc<Cvterm>,
        }
        pub struct Cvtermpath {
            pub subject: Rc<Cvterm>,
            pub object: Rc<Cvterm>,
            pub rel_type: Rc<Cvterm>,
            pub pathdistance: Option<i32>,
        }
    }

    pub mod web {
        pub mod data {
            use std::collections::HashMap;

            type GeneUniquename = String;
            type GeneName = String;

            #[derive(Serialize)]
            pub struct GeneShort {
                pub uniquename: GeneUniquename,
                pub name: Option<GeneName>,
            }

            type TermName = String;
            type TermId = String;
            type TermDef = String;

            #[derive(Serialize)]
            pub struct TermShort {
                pub name: TermName,
                pub termid: TermId,
                pub definition: TermDef,
                pub is_obsolete: bool,
            }

            type Evidence = String;

            #[derive(Serialize)]
            pub struct FeatureAnnotation {
                pub term: TermShort,
                pub evidence: Evidence,
            }

            type TypeName = String;
            pub type TypeFeatureAnnotationMap =
                HashMap<TypeName, Vec<FeatureAnnotation>>;

            #[derive(Serialize)]
            pub struct GeneDetails {
                pub uniquename: GeneUniquename,
                pub name: Option<String>,
                pub annotations: TypeFeatureAnnotationMap,
            }

            type UniquenameGeneMap =
                HashMap<GeneUniquename, Vec<GeneDetails>>;

            #[derive(Serialize)]
            pub struct TermAnnotation {
                pub gene: GeneShort,
                pub evidence: Evidence,
            }

            #[derive(Serialize)]
            pub struct TermDetails {
                pub name: TermName,
                pub termid: TermId,
                pub definition: TermDef,
                pub is_obsolete: bool,
                pub annotations: Vec<TermAnnotation>,
            }
        }
    }
}

use pombase::Raw;
use pombase::web::data::*;

fn get_web_data(raw: &Raw) -> (Vec<GeneDetails>, Vec<TermDetails>) {
    let mut genes: Vec<GeneDetails> = vec![];
    let terms: Vec<TermDetails> = vec![];

    for feat in raw.features.iter().filter(|&f| f.feat_type.name == "gene") {
        genes.push(GeneDetails {
            uniquename: feat.uniquename.clone(),
            name: feat.name.clone(),
            annotations: TypeFeatureAnnotationMap::new(),
        });
    }

    (genes, terms)
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.reqopt("c", "connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.reqopt("d", "output-directory",
                "Destination directory for JSON output", "DIR");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let connection_string = matches.opt_str("c").unwrap();
    let output_dir = matches.opt_str("d").unwrap();

    fs::create_dir_all(&output_dir).unwrap_or_else(|why| {
        println!("Creating output directory failed: {:?}", why.kind());
    });

    let conn = Connection::connect(connection_string.as_str(), TlsMode::None).unwrap();

    let raw = Raw::new(&conn);

    let (genes, terms) = get_web_data(&raw);

    println!("{}", genes.len() + terms.len());
    println!("{}", genes.get(0).unwrap().uniquename);

    for gene in &genes {
        let s = serde_json::to_string(&gene).unwrap();
        let file_name = String::new() + &output_dir + "/" + &gene.uniquename + ".json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }

}
<commit_msg>Add organism table reading<commit_after>#![feature(proc_macro)]

extern crate postgres;

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

extern crate getopts;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::fs;
use std::fs::File;
use std::io::{Write, BufWriter};

mod pombase {
    use std::rc::Rc;
    use std::collections::HashMap;
    use postgres::Connection;

    use pombase::db::*;

    pub struct Raw {
        pub organisms: Vec<Rc<Organism>>,
        pub cvs: Vec<Rc<Cv>>,
        pub dbs: Vec<Rc<Db>>,
        pub dbxrefs: Vec<Rc<Dbxref>>,
        pub cvterms: Vec<Rc<Cvterm>>,
        pub cvtermpaths: Vec<Rc<Cvtermpath>>,
        pub cvterm_relationships: Vec<Rc<CvtermRelationship>>,
        pub publications: Vec<Rc<Publication>>,
        pub features: Vec<Rc<Feature>>,
    }

    impl Raw {
        pub fn new(conn: &Connection) -> Raw {
            let mut ret = Raw {
                organisms: vec![],
                cvs: vec![], dbs: vec![], dbxrefs: vec![], cvterms: vec![],
                cvtermpaths: vec![], cvterm_relationships: vec![],
                publications: vec![], features: vec![],
            };

            let mut organism_map: HashMap<i32, Rc<Organism>> = HashMap::new();
            let mut cv_map: HashMap<i32, Rc<Cv>> = HashMap::new();
            let mut db_map: HashMap<i32, Rc<Db>> = HashMap::new();
            let mut dbxref_map: HashMap<i32, Rc<Dbxref>> = HashMap::new();
            let mut cvterm_map: HashMap<i32, Rc<Cvterm>> = HashMap::new();
            let mut feature_map: HashMap<i32, Rc<Feature>> = HashMap::new();
            let mut publication_map: HashMap<i32, Rc<Publication>> = HashMap::new();

            for row in &conn.query("SELECT organism_id, genus, species, abbreviation, common_name FROM organism", &[]).unwrap() {
                let organism = Organism {
                    genus: row.get(1),
                    species: row.get(2),
                    abbreviation: row.get(3),
                    common_name: row.get(4),
                };
                let rc_organism = Rc::new(organism);
                ret.organisms.push(rc_organism.clone());
                organism_map.insert(row.get(0), rc_organism);
            }

            for row in &conn.query("SELECT cv_id, name FROM cv", &[]).unwrap() {
                let cv = Cv {
                    name: row.get(1),
                };
                let rc_cv = Rc::new(cv);
                ret.cvs.push(rc_cv.clone());
                cv_map.insert(row.get(0), rc_cv);
            }

            for row in &conn.query("SELECT db_id, name FROM db", &[]).unwrap() {
                let db_id = row.get(0);
                let db = Db {
                    name: row.get(1),
                };
                let rc_db = Rc::new(db);
                ret.dbs.push(rc_db.clone());
                db_map.insert(db_id, rc_db);
            }

            for row in &conn.query("SELECT dbxref_id, db_id, accession FROM dbxref", &[]).unwrap() {
                let dbxref_id: i32 = row.get(0);
                let db_id: i32 = row.get(1);
                let dbxref = Dbxref {
                    db: db_map.get(&db_id).unwrap().clone(),
                    accession: row.get(2),
                };
                let rc_dbxref = Rc::new(dbxref);
                ret.dbxrefs.push(rc_dbxref.clone());
                dbxref_map.insert(dbxref_id, rc_dbxref);
            }

            for row in &conn.query("SELECT cvterm_id, cv_id, dbxref_id, name FROM cvterm", &[]).unwrap() {
                let cvterm_id: i32 = row.get(0);
                let cv_id: i32 = row.get(1);
                let dbxref_id: i32 = row.get(2);
                let cvterm = Cvterm {
                    cv: cv_map.get(&cv_id).unwrap().clone(),
                    dbxref: dbxref_map.get(&dbxref_id).unwrap().clone(),
                    name: row.get(3),
                };
                let rc_cvterm = Rc::new(cvterm);
                ret.cvterms.push(rc_cvterm.clone());
                cvterm_map.insert(cvterm_id, rc_cvterm);
            }

            for row in &conn.query("SELECT pub_id, uniquename, type_id, title FROM pub", &[]).unwrap() {
                let pub_id: i32 = row.get(0);
                let uniquename: String = row.get(1);
                let type_id: i32 = row.get(2);
                let title: Option<String> = row.get(3);
                let publication = Publication {
                    uniquename: uniquename,
                    pub_type: cvterm_map.get(&type_id).unwrap().clone(),
                    title: title
                };
                let rc_publication = Rc::new(publication);
                ret.publications.push(rc_publication.clone());
                publication_map.insert(pub_id, rc_publication);
            }

            for row in &conn.query("SELECT feature_id, uniquename, name, type_id FROM feature", &[]).unwrap() {
                let feature_id = row.get(0);
                let type_id: i32 = row.get(3);
                let feature = Feature {
                    uniquename: row.get(1),
                    name: row.get(2),
                    feat_type: cvterm_map.get(&type_id).unwrap().clone(),
                };
                let rc_feature = Rc::new(feature);
                ret.features.push(rc_feature.clone());
                feature_map.insert(feature_id, rc_feature);
            }

            ret
        }
    }

    pub mod db {
        use std::rc::Rc;

        pub struct Organism {
            pub genus: String,
            pub species: String,
            pub abbreviation: String,
            pub common_name: String,
        }
        pub struct Cv {
            pub name: String,
        }
        pub struct Db {
            pub name: String,
        }
        pub struct Dbxref {
            pub accession: String,
            pub db: Rc<Db>,
        }
        pub struct Cvterm {
            pub name: String,
            pub cv: Rc<Cv>,
            pub dbxref: Rc<Dbxref>,
        }
        pub struct Publication {
            pub uniquename: String,
            pub pub_type: Rc<Cvterm>,
            pub title: Option<String>,
        }
        pub struct CvtermRelationship {
            pub subject: Rc<Cvterm>,
            pub object: Rc<Cvterm>,
            pub reltype: Rc<Cvterm>,
        }
        pub struct Cvtermpath {
            pub subject: Rc<Cvterm>,
            pub object: Rc<Cvterm>,
            pub rel_type: Rc<Cvterm>,
            pub pathdistance: Option<i32>,
        }
        pub struct Feature {
            pub uniquename: String,
            pub name: Option<String>,
            pub feat_type: Rc<Cvterm>,
        }
    }

    pub mod web {
        pub mod data {
            use std::collections::HashMap;

            type GeneUniquename = String;
            type GeneName = String;

            #[derive(Serialize)]
            pub struct GeneShort {
                pub uniquename: GeneUniquename,
                pub name: Option<GeneName>,
            }

            type TermName = String;
            type TermId = String;
            type TermDef = String;

            #[derive(Serialize)]
            pub struct TermShort {
                pub name: TermName,
                pub termid: TermId,
                pub definition: TermDef,
                pub is_obsolete: bool,
            }

            type Evidence = String;

            #[derive(Serialize)]
            pub struct FeatureAnnotation {
                pub term: TermShort,
                pub evidence: Evidence,
            }

            type TypeName = String;
            pub type TypeFeatureAnnotationMap =
                HashMap<TypeName, Vec<FeatureAnnotation>>;

            #[derive(Serialize)]
            pub struct GeneDetails {
                pub uniquename: GeneUniquename,
                pub name: Option<String>,
                pub annotations: TypeFeatureAnnotationMap,
            }

            type UniquenameGeneMap =
                HashMap<GeneUniquename, Vec<GeneDetails>>;

            #[derive(Serialize)]
            pub struct TermAnnotation {
                pub gene: GeneShort,
                pub evidence: Evidence,
            }

            #[derive(Serialize)]
            pub struct TermDetails {
                pub name: TermName,
                pub termid: TermId,
                pub definition: TermDef,
                pub is_obsolete: bool,
                pub annotations: Vec<TermAnnotation>,
            }
        }
    }
}

use pombase::Raw;
use pombase::web::data::*;

fn get_web_data(raw: &Raw) -> (Vec<GeneDetails>, Vec<TermDetails>) {
    let mut genes: Vec<GeneDetails> = vec![];
    let terms: Vec<TermDetails> = vec![];

    for feat in raw.features.iter().filter(|&f| f.feat_type.name == "gene") {
        genes.push(GeneDetails {
            uniquename: feat.uniquename.clone(),
            name: feat.name.clone(),
            annotations: TypeFeatureAnnotationMap::new(),
        });
    }

    (genes, terms)
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.reqopt("c", "connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.reqopt("d", "output-directory",
                "Destination directory for JSON output", "DIR");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let connection_string = matches.opt_str("c").unwrap();
    let output_dir = matches.opt_str("d").unwrap();

    fs::create_dir_all(&output_dir).unwrap_or_else(|why| {
        println!("Creating output directory failed: {:?}", why.kind());
    });

    let conn = Connection::connect(connection_string.as_str(), TlsMode::None).unwrap();

    let raw = Raw::new(&conn);

    let (genes, terms) = get_web_data(&raw);

    println!("{}", genes.len() + terms.len());
    println!("{}", genes.get(0).unwrap().uniquename);

    for gene in &genes {
        let s = serde_json::to_string(&gene).unwrap();
        let file_name = String::new() + &output_dir + "/" + &gene.uniquename + ".json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }

}
<|endoftext|>


<commit_before>#![feature(slice_bytes,clone_from_slice)]

extern crate libc;
extern crate errno;
extern crate rustc_serialize; //debug hex dump

#[macro_use]
extern crate nom;

use std::io::Write;
use rustc_serialize::hex::ToHex;

const ETH_P_ALL: u16 = 0x0003;
const ETH_P_IP: u16 = 0x0800;
const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;
const RECV_BUF_LEN: usize = 1542;
const SO_ATTACH_FILTER: libc::c_int = 26;

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_filter {	/* Filter block */
	code: u16,   /* Actual filter code */
	jt: u8,	/* Jump true */
	jf: u8,	/* Jump false */
	k: u32      /* Generic multiuse field */
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct sock_fprog {     /* Required for SO_ATTACH_FILTER. */
        len: u16,    /* Number of filter blocks */
        filter: *const sock_filter
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

#[derive(Debug)]
struct EthernetFrame {
    dst: MacAddr,
    src: MacAddr,
    ty: EthernetType,
    payload: EthernetPayload,
}

#[derive(Debug)]
struct MacAddr([u8; 6]);
impl MacAddr {
    fn from_slice(s: &[u8]) -> MacAddr {
        // bit ugly, is there a better way?
        let mut m = MacAddr([0u8; 6]);
        m.0.clone_from_slice(s);
        return m;
    }
}
#[derive(Debug)]
struct IpAddr(u32);

#[derive(Debug)]
#[repr(u16)]
enum EthernetType {
    Arp = ETH_P_ARP,
    Ip = ETH_P_IP
}

#[derive(Debug)]
enum EthernetPayload {
    Arp(ArpPacket),
}

#[derive(Debug)]
struct ArpPacket {
    hwtype: u16,
    proto: u16,
    hwsize: u8,
    protosize: u8,
    opcode: u16,
    sender_mac: MacAddr,
    sender_ip: IpAddr,
    target_mac: MacAddr,
    target_ip: IpAddr
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> libc::c_int {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    if unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) } == -1 {
        let err = errno::errno();
        panic!("Error getting ifindex: {} ({})", err, err.0);
    }
    return ifr.ifr_ifindex;

}

struct SocketError {
    action: &'static str,
    err: errno::Errno
}

macro_rules! sockerr {
    ($action:expr) => {
        return Err(SocketError{ action: $action, err: errno::errno() });
    };
}

fn create_listen_socket(iface: &str) -> Result<libc::c_int, SocketError> {
    // tcpdump -dd arp and incoming
    let bpf_filter_arp_incoming: [sock_filter; 6] = [
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
        sock_filter { code: 0x15, jt: 0, jf: 3, k: 0x00000806 },
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0xfffff004 },
        sock_filter { code: 0x15, jt: 1, jf: 0, k: 0x00000004 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00040000 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00000000 },
    ];
    let bpf_filter_arp_incoming_prog: sock_fprog = sock_fprog {
        len: 6,
        filter: bpf_filter_arp_incoming.as_ptr()
    };

    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32) };
    if listen_socket == -1 {
        println!("try: sudo setcap CAP_NET_RAW+eip arpmasqd");
        sockerr!("opening socket");
    }
    let attach_filter_res = unsafe { libc::setsockopt(listen_socket, libc::SOL_SOCKET, SO_ATTACH_FILTER, std::mem::transmute(&bpf_filter_arp_incoming_prog), std::mem::size_of_val(&bpf_filter_arp_incoming_prog) as u32) };
    if attach_filter_res == -1 {
        sockerr!("attaching filter");
    }
    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ALL.to_be(),
        sll_ifindex: ifindex_from_ifname(&iface, listen_socket),
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe { libc::bind(listen_socket, std::mem::transmute(&listen_sockaddr), std::mem::size_of_val(&listen_sockaddr) as u32) };
    if bind_result == -1 {
        sockerr!("binding socket");
    }
    return Ok(listen_socket);
}

fn u16_to_be_bytes(i: u16) -> [u8;2] {
    [((i>>8) & 0xff) as u8, (i & 0xff) as u8]
}

named!(arp_packet_parser(&[u8]) -> ArpPacket, chain!(
    hwtype: call!(nom::be_u16)
    ~ proto: call!(nom::be_u16)
    ~ hwsize: call!(nom::be_u8)
    ~ protosize: call!(nom::be_u8)
    ~ opcode: call!(nom::be_u16)
    ~ sender_mac: take!(6)
    ~ sender_ip: call!(nom::be_u32)
    ~ target_mac: take!(6)
    ~ target_ip: call!(nom::be_u32),
    || {
        ArpPacket {
            hwtype: hwtype,
            proto: proto,
            hwsize: hwsize,
            protosize: protosize,
            opcode: opcode,
            sender_mac: MacAddr::from_slice(sender_mac),
            sender_ip: IpAddr(sender_ip),
            target_mac: MacAddr::from_slice(target_mac),
            target_ip: IpAddr(target_ip)
        }
    })
);

named!(eth_frame_parser(&[u8]) -> EthernetFrame, chain!(
    dst: take!(6)
    ~ src: take!(6)
    ~ _ty: tag!(u16_to_be_bytes(ETH_P_ARP))
    ~ payload: call!(arp_packet_parser),
    || {
        EthernetFrame {
            dst: MacAddr::from_slice(dst),
            src: MacAddr::from_slice(src),
            ty: EthernetType::Arp,
            payload: EthernetPayload::Arp(payload)
        }
    })
);

fn do_recv(listen_socket: libc::c_int) -> ! {
    let buf = [0u8; RECV_BUF_LEN];
    let mut recv_sockaddr = unsafe { std::mem::zeroed::<libc::sockaddr_ll>() };
    let mut recv_sockaddr_len: u32 = std::mem::size_of_val(&recv_sockaddr) as u32;
    loop {
        let recv_result = unsafe { libc::recvfrom(listen_socket, std::mem::transmute(&buf), RECV_BUF_LEN as u64, 0, std::mem::transmute(&recv_sockaddr), &mut recv_sockaddr_len) };
        if recv_result == -1 {
            let err = errno::errno();
            panic!("Error in recvfrom: {} ({})", err, err.0);
        }
        // rust has no offsetof yet so we hardcode 12 here instead
        println!("From: {}", recv_sockaddr.sll_addr[0..(recv_sockaddr_len as usize -12)].to_hex());
        //TODO minimum arp packet length?
        if recv_result >= 42 {
            if let nom::IResult::Done(_, frame) = eth_frame_parser(&buf[0..(recv_result as usize)]) {
                println!("{:?}", frame);
            } else {
                println!("parser error");
            }
        } else {
            println!("Too short frame ({}): {}", recv_result, buf[0..(recv_result as usize)].to_hex());
        }
    }
}

fn main() {
    let mut args = std::env::args();
    if args.len() != 2 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_IFACE\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    match create_listen_socket(&listen_iface) {
        Ok(sock) => do_recv(sock),
        Err(err) => panic!("Error {}: {} ({})", err.action, err.err, err.err.0)
    }
}
<commit_msg>cleanup; formatting, error handling etc<commit_after>#![feature(slice_bytes,clone_from_slice)]

extern crate libc;
extern crate errno;
extern crate rustc_serialize; //debug hex dump

#[macro_use]
extern crate nom;

use std::io::Write;
use rustc_serialize::hex::ToHex;

const ETH_P_ALL: u16 = 0x0003;
const ETH_P_IP: u16 = 0x0800;
const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;
const RECV_BUF_LEN: usize = 1522;
const SO_ATTACH_FILTER: libc::c_int = 26;

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_filter { /* Filter block */
    code: u16,       /* Actual filter code */
    jt: u8,          /* Jump true */
    jf: u8,          /* Jump false */
    k: u32           /* Generic multiuse field */
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_fprog {     /* Required for SO_ATTACH_FILTER. */
        len: u16,       /* Number of filter blocks */
        filter: *const sock_filter
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

#[derive(Debug)]
struct EthernetFrame {
    dst: MacAddr,
    src: MacAddr,
    tag: Option<VlanTag>,
    tysize: EthernetTypeSize,
    payload: EthernetPayload,
}

#[derive(Debug)]
struct MacAddr([u8; 6]);
impl MacAddr {
    fn from_slice(s: &[u8]) -> MacAddr {
        // bit ugly, is there a better way?
        let mut m = MacAddr([0u8; 6]);
        m.0.clone_from_slice(s);
        return m;
    }
}

#[derive(Debug)]
struct VlanTag(u16);

#[derive(Debug)]
struct IpAddr(u32);

#[derive(Debug)]
#[repr(u16)]
enum EtherType {
    Arp = ETH_P_ARP,
    Ip = ETH_P_IP
}

#[derive(Debug)]
enum EthernetTypeSize {
    Size(u16),
    Type(EtherType),
}

#[derive(Debug)]
enum EthernetPayload {
    Arp(ArpPacket),
}

#[derive(Debug)]
struct ArpPacket {
    hwtype: u16,
    proto: u16,
    hwsize: u8,
    protosize: u8,
    opcode: u16,
    sender_mac: MacAddr,
    sender_ip: IpAddr,
    target_mac: MacAddr,
    target_ip: IpAddr
}

struct SocketError {
    action: &'static str,
    err: errno::Errno
}

macro_rules! sockerr {
    ($action:expr, $res:expr) => {
        if $res == -1 {
            return Err(SocketError{ action: $action, err: errno::errno() });
        }
    };
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> Result<libc::c_int, SocketError> {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    let res = unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) };
    sockerr!("getting ifindex", res);
    return Ok(ifr.ifr_ifindex);
}

fn create_listen_socket(iface: &str) -> Result<libc::c_int, SocketError> {
    // tcpdump -dd arp and incoming
    let bpf_filter_arp_incoming: [sock_filter; 6] = [
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
        sock_filter { code: 0x15, jt: 0, jf: 3, k: 0x00000806 },
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0xfffff004 },
        sock_filter { code: 0x15, jt: 1, jf: 0, k: 0x00000004 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00040000 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00000000 },
    ];
    let bpf_filter_arp_incoming_prog: sock_fprog = sock_fprog {
        len: 6,
        filter: bpf_filter_arp_incoming.as_ptr()
    };

    let listen_socket = unsafe {
        libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32)
    };
    sockerr!("opening socket", listen_socket);
    let attach_filter_res = unsafe {
        libc::setsockopt(
            listen_socket,
            libc::SOL_SOCKET,
            SO_ATTACH_FILTER,
            std::mem::transmute(&bpf_filter_arp_incoming_prog),
            std::mem::size_of_val(&bpf_filter_arp_incoming_prog) as u32
        )
    };
    sockerr!("attaching filter", attach_filter_res);

    let ifindex = try!(ifindex_from_ifname(&iface, listen_socket));

    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ALL.to_be(),
        sll_ifindex: ifindex,
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe {
        libc::bind(
            listen_socket,
            std::mem::transmute(&listen_sockaddr),
            std::mem::size_of_val(&listen_sockaddr) as u32
        )
    };
    sockerr!("binding socket", bind_result);
    return Ok(listen_socket);
}

fn u16_to_be_bytes(i: u16) -> [u8;2] {
    [((i>>8) & 0xff) as u8, (i & 0xff) as u8]
}

named!(arp_packet_parser(&[u8]) -> ArpPacket, chain!(
    hwtype: call!(nom::be_u16)
    ~ proto: call!(nom::be_u16)
    ~ hwsize: call!(nom::be_u8)
    ~ protosize: call!(nom::be_u8)
    ~ opcode: call!(nom::be_u16)
    ~ sender_mac: take!(6)
    ~ sender_ip: call!(nom::be_u32)
    ~ target_mac: take!(6)
    ~ target_ip: call!(nom::be_u32),
    || {
        ArpPacket {
            hwtype: hwtype,
            proto: proto,
            hwsize: hwsize,
            protosize: protosize,
            opcode: opcode,
            sender_mac: MacAddr::from_slice(sender_mac),
            sender_ip: IpAddr(sender_ip),
            target_mac: MacAddr::from_slice(target_mac),
            target_ip: IpAddr(target_ip)
        }
    })
);

named!(eth_frame_parser(&[u8]) -> EthernetFrame, chain!(
    dst: take!(6)
    ~ src: take!(6)
    ~ tag: opt!(
        chain!(
            _tpid: tag!(u16_to_be_bytes(0x8100))
            ~ tci: call!(nom::be_u16),
            || {
                VlanTag(tci)
            }
        )
    )
    ~ tysize: call!(nom::be_u16)
    ~ payload: call!(arp_packet_parser),
    || {
        let tysize = if tysize < 0x0600 {
            EthernetTypeSize::Size(tysize)
        } else {
            //TODO safe way to convert u16->EtherType
            // tysize comes directly from network so this is VERY BAD
            EthernetTypeSize::Type(unsafe { std::mem::transmute(tysize) } )
        };
        EthernetFrame {
            dst: MacAddr::from_slice(dst),
            src: MacAddr::from_slice(src),
            tag: tag,
            tysize: tysize,
            payload: EthernetPayload::Arp(payload)
        }
    })
);

fn do_recv(listen_socket: libc::c_int) -> SocketError {
    let buf = [0u8; RECV_BUF_LEN];
    let mut recv_sockaddr = unsafe { std::mem::zeroed::<libc::sockaddr_ll>() };
    let mut recv_sockaddr_len: u32 = std::mem::size_of_val(&recv_sockaddr) as u32;
    loop {
        let recv_result = unsafe {
            libc::recvfrom(
                listen_socket,
                std::mem::transmute(&buf),
                RECV_BUF_LEN as u64,
                0,
                std::mem::transmute(&recv_sockaddr),
                &mut recv_sockaddr_len
            )
        };
        if recv_result == -1 {
            return SocketError { action: "recvfrom", err: errno::errno() };
        }
        // rust has no offsetof yet so we hardcode 12 here instead
        // println!("From: {}", recv_sockaddr.sll_addr[0..(recv_sockaddr_len as usize -12)].to_hex());
        //TODO minimum arp packet length?
        if recv_result >= 42 {
            match eth_frame_parser(&buf[0..(recv_result as usize)]) {
                nom::IResult::Done(_i, frame) => println!("Parser done: {:?}", frame),
                nom::IResult::Error(err) => println!("Parser error: {:?}", err),
                nom::IResult::Incomplete(needed) => println!("Parser incomplete: {:?}", needed)
            }
        } else {
            println!("Too short frame ({}): {}", recv_result, buf[0..(recv_result as usize)].to_hex());
        }
    }
}

fn main_wrapper() -> i32 {
    let mut args = std::env::args();
    if args.len() != 2 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_IFACE\n".as_ref()).unwrap();
        std::io::stderr().write("Error: Missing LISTEN_IFACE\n".as_ref()).unwrap();
        return 1;
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    let err = match create_listen_socket(&listen_iface) {
        Ok(sock) => do_recv(sock),
        Err(err) => err
    };
    std::io::stderr().write(format!("Error {}: {} ({})\n", err.action, err.err, err.err.0).as_ref()).unwrap();
    return 1;
}

fn main() {
    std::process::exit(main_wrapper());
}
<|endoftext|>


<commit_before>
use crate::parse::*;
use crate::util::*;
use std::collections::HashMap;
use std::mem;
use std::sync::Mutex;

lazy_static! {
    static ref STR_LABEL: Mutex<i32> = Mutex::new(0);
    static ref GLOBALS: Mutex<Vec<Var>> = Mutex::new(Vec::new());
    static ref STACKSIZE: Mutex<i32> = Mutex::new(0);
}

#[derive(Clone, Debug)]
struct Env<'a> {
    vars: HashMap<String, Var>,
    next: Option<Box<&'a Env<'a>>>,
}

fn new_env<'a>(next: Option<&'a Env>) -> Env<'a> {
    Env {
        vars: HashMap::new(),
        next: if let Some(e) = next {
            Some(Box::new(e))
        } else {
            None
        },
    }
}

impl<'a> Env<'a> {
    fn find(&self, name: & String) -> Option<&Var> {
        if let Some(v) = self.vars.get(name) {
            return Some(v);
        } else if let Some(ref next) = self.next {
            return next.find(name);
        } else {
            return None;
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Var {
    pub ty: Type,
    pub is_local: bool,

    // local
    pub offset: i32,

    // global
    pub name: String,
    pub is_extern: bool,
    pub data: String,
    pub len: usize,
}

fn alloc_var(ty: Type) -> Var {
    Var {
        ty: ty,
        is_local: false,
        offset: 0,
        name: String::new(),
        is_extern: false,
        data: String::new(),
        len: 0,
    }
}

fn new_global(ty: Type, name: String, data: String, len: usize) -> Var {
    let mut var = alloc_var(ty);
    var.is_local = false;
    //var.name = format!(".L.str{}", bump_str_label()).to_string();
    var.name = name;
    var.data = data;
    var.len = len;
    return var;
}

fn init_globals() {
    *GLOBALS.lock().unwrap() = Vec::new();
}

fn globals() -> Vec<Var> {
    GLOBALS.lock().unwrap().clone()
}

fn globals_push(var: Var) {
    let mut globals = GLOBALS.lock().unwrap();
    globals.push(var);
}

fn stacksize() -> i32 {
    *STACKSIZE.lock().unwrap()
}

fn init_stacksize() {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize = 0;
}

fn add_stacksize(i: i32) {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize += i;
}

fn bump_str_label() -> i32 {
    let mut str_label = STR_LABEL.lock().unwrap();
    let ret = *str_label;
    *str_label += 1;
    return ret;
}

fn swap(p: &mut Node, q: &mut Node) {
    mem::swap(p, q);
}

fn maybe_decay(base: & mut Node, decay: bool) -> & mut Node {
    if !decay || base.ty.ty != CType::ARY {
        return base;
    }

    let tmp = base.clone();
    *base = alloc_node();
    base.op = NodeType::ADDR;
    base.ty = ptr_of(*tmp.clone().ty.ary_of.unwrap());

    base.expr = Some(Box::new(tmp));
    return base;
}

fn check_lval(node: & Node) {
    match node.op {
        NodeType::LVAR | NodeType::GVAR | NodeType::DEREF => {
            return;
        }
        _ => {
            panic!("not an lvalue: {:?} ({})", node.op, node.name);
        }
    }
}

fn walk<'a>(env: &'a mut Env, node: &'a mut Node, decay: bool) -> &'a Node {
    match node.op {
        NodeType::NUM => {
            return node;
        }
        NodeType::STR => {
            let node_ty = node.ty.clone();
            let node_data = node.data.clone();

            let name = format!(".L.str{}", bump_str_label()).to_string();
            let var = new_global(node_ty.clone(), name, node_data, node.len);
            globals_push(var.clone());

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = node_ty;
            node.name = var.name;
            return maybe_decay(node, decay);
        }
        NodeType::IDENT => {
            let var = match env.find(&node.name) {
                None => panic!("undefined variable: {}", node.name),
                Some(var) => var,
            };

            if var.is_local {
                *node = alloc_node();
                node.op = NodeType::LVAR;
                node.ty = var.ty.clone();
                node.offset = var.offset;
                return maybe_decay(node, decay);
            }

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = var.ty.clone();
            node.name = var.name.clone();
            return maybe_decay(node, decay);
        }
        NodeType::VARDEF => {
            add_stacksize(size_of(& node.ty));
            node.offset = stacksize();

            let mut var = alloc_var(node.ty.clone());
            var.is_local = true;
            var.offset = stacksize();
            env.vars.insert(node.name.clone(), var.clone());

            match node.init {
                Some(_) => {
                    node.init = Some(Box::new(walk(env, &mut *node.init.clone().unwrap(), true).clone()));
                }
                None => { }
            }
            return node;
        }
        NodeType::IF => {
            node.cond = Some(Box::new(walk(env, &mut *node.cond.clone().unwrap(), true).clone()));
            node.then = Some(Box::new(walk(env, &mut *node.then.clone().unwrap(), true).clone()));

            if node.els.is_some() {
                node.els = Some(Box::new(walk(env, &mut *node.els.clone().unwrap(), true).clone()));
            }
            return node;
        }
        NodeType::FOR => {
            node.init = Some(Box::new(walk(env, &mut *node.init.clone().unwrap(), true).clone()));
            node.cond = Some(Box::new(walk(env, &mut *node.cond.clone().unwrap(), true).clone()));
            node.inc = Some(Box::new(walk(env, &mut *node.inc.clone().unwrap(), true).clone()));
            node.body = Some(Box::new(walk(env, &mut *node.body.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::DO_WHILE => {
            node.cond = Some(Box::new(walk(env, &mut *node.cond.clone().unwrap(), true).clone()));
            node.body = Some(Box::new(walk(env, &mut *node.body.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::ADD | NodeType::SUB => {
            node.lhs = Some(Box::new(walk(env, &mut *node.lhs.clone().unwrap(), true).clone()));
            node.rhs = Some(Box::new(walk(env, &mut *node.rhs.clone().unwrap(), true).clone()));

            match (&mut node.lhs, &mut node.rhs) {
                (Some(ref mut lhs), Some(ref mut rhs)) => {
                    if rhs.ty.ty == CType::PTR {
                        swap(lhs, rhs);
                    }
                }
                _ => {}
            }
            match node.rhs {
                Some(ref rhs) => {
                    if rhs.ty.ty == CType::PTR {
                        panic!("'pointer {:?} pointer' is not defined", node.op);
                    }
                }
                None => {
                }
            }

            match node.lhs {
                Some(ref lhs) => {
                    node.ty = lhs.ty.clone();
                }
                None => { }
            }

            return node;
        }
        NodeType::EQL => {
            node.lhs = Some(Box::new(walk(env, &mut *node.lhs.clone().unwrap(), false).clone()));
            check_lval(& *node.lhs.clone().unwrap());

            node.rhs = Some(Box::new(walk(env, &mut *node.rhs.clone().unwrap(), true).clone()));
            node.ty = node.lhs.clone().unwrap().ty;
            return node;
        }
        NodeType::MUL |
            NodeType::DIV |
            NodeType::LT |
            NodeType::EQ |
            NodeType::NE |
            NodeType::LOGAND |
            NodeType::LOGOR => {
                node.lhs = Some(Box::new(walk(env, &mut *node.lhs.clone().unwrap(), true).clone()));
                node.rhs = Some(Box::new(walk(env, &mut *node.rhs.clone().unwrap(), true).clone()));

                match node.lhs {
                    Some(ref lhs) => {
                        node.ty = lhs.ty.clone();
                    }
                    None => { }
                }
                return node;
            }
        NodeType::ADDR => {
            node.expr = Some(Box::new(walk(env, &mut *node.expr.clone().unwrap(), true).clone()));
            check_lval(& *node.expr.clone().unwrap());
            node.ty = ptr_of(node.expr.clone().unwrap().ty);
            return node;
        }
        NodeType::DEREF => {
            node.expr = Some(Box::new(walk(env, &mut *node.expr.clone().unwrap(), true).clone()));
            match &mut node.expr {
                Some(ref expr) => {
                    if expr.ty.ty != CType::PTR {
                        panic!("operand must be a pointer: {:?}", expr);
                    }
                }
                None => {}
            }

            node.ty = *node.expr.clone().unwrap().ty.ptr_of.unwrap();
            return node;
        }
        NodeType::RETURN => {
            node.expr = Some(Box::new(walk(env, &mut *node.expr.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::SIZEOF => {
            let mut nexpr = *node.expr.clone().unwrap();
            let expr = walk(env, &mut nexpr, false);
            let val = size_of(& expr.ty);

            *node = alloc_node();
            node.op = NodeType::NUM;
            node.ty = int_ty();
            node.val = val;
            return node;
        }
        NodeType::CALL => {
            for i in 0..node.args.len() {
                node.args[i] = walk(env, &mut node.args[i], true).clone();
            }
            node.ty = int_ty();
            return node;
        }
        NodeType::FUNC => {
            for i in 0..node.args.len() {
                node.args[i] = walk(env, &mut node.args[i], true).clone();
            }
            node.body = Some(Box::new(walk(env, &mut *node.body.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::COMP_STMT => {
            let mut newenv = new_env(Some(env));
            for i in 0..node.stmts.len() {
                node.stmts[i] = walk(&mut newenv, &mut node.stmts[i], true).clone();
            }
            return node;
        }
        NodeType::EXPR_STMT => {
            node.expr = Some(Box::new(walk(env, &mut *node.expr.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::STMT_EXPR => {
            node.body = Some(Box::new(walk(env, &mut *node.body.clone().unwrap(), true).clone()));
            node.ty = int_ty();
            return node;
        }
        NodeType::NULL => {
            return node;
        }
        _ => {
            panic!("unknown node type");
        }
    }
}

pub fn sema(nodes: &mut Vec<Node>) -> Vec<Var> {
    init_globals();
    let mut topenv = new_env(None);

    for node in nodes.iter_mut() {
        if node.op == NodeType::VARDEF {
            let mut var = new_global(node.ty.clone(), node.name.clone(), node.data.clone(), node.len);
            var.is_extern = node.is_extern;
            globals_push(var.clone());
            topenv.vars.insert(node.name.clone(), var);
            continue;
        }

        assert!(node.op == NodeType::FUNC);

        init_stacksize();
        walk(&mut topenv, node, true);
        node.stacksize = stacksize();
    }
    return globals();
}
<commit_msg>Swap parameters for readability.<commit_after>
use crate::parse::*;
use crate::util::*;
use std::collections::HashMap;
use std::mem;
use std::sync::Mutex;

lazy_static! {
    static ref STR_LABEL: Mutex<i32> = Mutex::new(0);
    static ref GLOBALS: Mutex<Vec<Var>> = Mutex::new(Vec::new());
    static ref STACKSIZE: Mutex<i32> = Mutex::new(0);
}

#[derive(Clone, Debug)]
struct Env<'a> {
    vars: HashMap<String, Var>,
    next: Option<Box<&'a Env<'a>>>,
}

fn new_env<'a>(next: Option<&'a Env>) -> Env<'a> {
    Env {
        vars: HashMap::new(),
        next: if let Some(e) = next {
            Some(Box::new(e))
        } else {
            None
        },
    }
}

impl<'a> Env<'a> {
    fn find(&self, name: & String) -> Option<&Var> {
        if let Some(v) = self.vars.get(name) {
            return Some(v);
        } else if let Some(ref next) = self.next {
            return next.find(name);
        } else {
            return None;
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Var {
    pub ty: Type,
    pub is_local: bool,

    // local
    pub offset: i32,

    // global
    pub name: String,
    pub is_extern: bool,
    pub data: String,
    pub len: usize,
}

fn alloc_var(ty: Type) -> Var {
    Var {
        ty: ty,
        is_local: false,
        offset: 0,
        name: String::new(),
        is_extern: false,
        data: String::new(),
        len: 0,
    }
}

fn new_global(ty: Type, name: String, data: String, len: usize) -> Var {
    let mut var = alloc_var(ty);
    var.is_local = false;
    //var.name = format!(".L.str{}", bump_str_label()).to_string();
    var.name = name;
    var.data = data;
    var.len = len;
    return var;
}

fn init_globals() {
    *GLOBALS.lock().unwrap() = Vec::new();
}

fn globals() -> Vec<Var> {
    GLOBALS.lock().unwrap().clone()
}

fn globals_push(var: Var) {
    let mut globals = GLOBALS.lock().unwrap();
    globals.push(var);
}

fn stacksize() -> i32 {
    *STACKSIZE.lock().unwrap()
}

fn init_stacksize() {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize = 0;
}

fn add_stacksize(i: i32) {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize += i;
}

fn bump_str_label() -> i32 {
    let mut str_label = STR_LABEL.lock().unwrap();
    let ret = *str_label;
    *str_label += 1;
    return ret;
}

fn swap(p: &mut Node, q: &mut Node) {
    mem::swap(p, q);
}

fn maybe_decay(base: & mut Node, decay: bool) -> & mut Node {
    if !decay || base.ty.ty != CType::ARY {
        return base;
    }

    let tmp = base.clone();
    *base = alloc_node();
    base.op = NodeType::ADDR;
    base.ty = ptr_of(*tmp.clone().ty.ary_of.unwrap());

    base.expr = Some(Box::new(tmp));
    return base;
}

fn check_lval(node: & Node) {
    match node.op {
        NodeType::LVAR | NodeType::GVAR | NodeType::DEREF => {
            return;
        }
        _ => {
            panic!("not an lvalue: {:?} ({})", node.op, node.name);
        }
    }
}

fn walk<'a>(node: &'a mut Node, env: &'a mut Env, decay: bool) -> &'a Node {
    match node.op {
        NodeType::NUM => {
            return node;
        }
        NodeType::STR => {
            let node_ty = node.ty.clone();
            let node_data = node.data.clone();

            let name = format!(".L.str{}", bump_str_label()).to_string();
            let var = new_global(node_ty.clone(), name, node_data, node.len);
            globals_push(var.clone());

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = node_ty;
            node.name = var.name;
            return maybe_decay(node, decay);
        }
        NodeType::IDENT => {
            let var = match env.find(&node.name) {
                None => panic!("undefined variable: {}", node.name),
                Some(var) => var,
            };

            if var.is_local {
                *node = alloc_node();
                node.op = NodeType::LVAR;
                node.ty = var.ty.clone();
                node.offset = var.offset;
                return maybe_decay(node, decay);
            }

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = var.ty.clone();
            node.name = var.name.clone();
            return maybe_decay(node, decay);
        }
        NodeType::VARDEF => {
            add_stacksize(size_of(& node.ty));
            node.offset = stacksize();

            let mut var = alloc_var(node.ty.clone());
            var.is_local = true;
            var.offset = stacksize();
            env.vars.insert(node.name.clone(), var.clone());

            match node.init {
                Some(_) => {
                    node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), env, true).clone()));
                }
                None => { }
            }
            return node;
        }
        NodeType::IF => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), env, true).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), env, true).clone()));

            if node.els.is_some() {
                node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), env, true).clone()));
            }
            return node;
        }
        NodeType::FOR => {
            node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), env, true).clone()));
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), env, true).clone()));
            node.inc = Some(Box::new(walk(&mut *node.inc.clone().unwrap(), env, true).clone()));
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::DO_WHILE => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), env, true).clone()));
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::ADD | NodeType::SUB => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), env, true).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), env, true).clone()));

            match (&mut node.lhs, &mut node.rhs) {
                (Some(ref mut lhs), Some(ref mut rhs)) => {
                    if rhs.ty.ty == CType::PTR {
                        swap(lhs, rhs);
                    }
                }
                _ => {}
            }
            match node.rhs {
                Some(ref rhs) => {
                    if rhs.ty.ty == CType::PTR {
                        panic!("'pointer {:?} pointer' is not defined", node.op);
                    }
                }
                None => {
                }
            }

            match node.lhs {
                Some(ref lhs) => {
                    node.ty = lhs.ty.clone();
                }
                None => { }
            }

            return node;
        }
        NodeType::EQL => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), env, false).clone()));
            check_lval(& *node.lhs.clone().unwrap());

            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), env, true).clone()));
            node.ty = node.lhs.clone().unwrap().ty;
            return node;
        }
        NodeType::MUL |
            NodeType::DIV |
            NodeType::LT |
            NodeType::EQ |
            NodeType::NE |
            NodeType::LOGAND |
            NodeType::LOGOR => {
                node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), env, true).clone()));
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), env, true).clone()));

                match node.lhs {
                    Some(ref lhs) => {
                        node.ty = lhs.ty.clone();
                    }
                    None => { }
                }
                return node;
            }
        NodeType::ADDR => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            check_lval(& *node.expr.clone().unwrap());
            node.ty = ptr_of(node.expr.clone().unwrap().ty);
            return node;
        }
        NodeType::DEREF => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            match &mut node.expr {
                Some(ref expr) => {
                    if expr.ty.ty != CType::PTR {
                        panic!("operand must be a pointer: {:?}", expr);
                    }
                }
                None => {}
            }

            node.ty = *node.expr.clone().unwrap().ty.ptr_of.unwrap();
            return node;
        }
        NodeType::RETURN => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::SIZEOF => {
            let mut nexpr = *node.expr.clone().unwrap();
            let expr = walk(&mut nexpr, env, false);
            let val = size_of(& expr.ty);

            *node = alloc_node();
            node.op = NodeType::NUM;
            node.ty = int_ty();
            node.val = val;
            return node;
        }
        NodeType::CALL => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], env, true).clone();
            }
            node.ty = int_ty();
            return node;
        }
        NodeType::FUNC => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], env, true).clone();
            }
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::COMP_STMT => {
            let mut newenv = new_env(Some(env));
            for i in 0..node.stmts.len() {
                node.stmts[i] = walk(&mut node.stmts[i], &mut newenv, true).clone();
            }
            return node;
        }
        NodeType::EXPR_STMT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::STMT_EXPR => {
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), env, true).clone()));
            node.ty = int_ty();
            return node;
        }
        NodeType::NULL => {
            return node;
        }
        _ => {
            panic!("unknown node type");
        }
    }
}

pub fn sema(nodes: &mut Vec<Node>) -> Vec<Var> {
    init_globals();
    let mut topenv = new_env(None);

    for node in nodes.iter_mut() {
        if node.op == NodeType::VARDEF {
            let mut var = new_global(node.ty.clone(), node.name.clone(), node.data.clone(), node.len);
            var.is_extern = node.is_extern;
            globals_push(var.clone());
            topenv.vars.insert(node.name.clone(), var);
            continue;
        }

        assert!(node.op == NodeType::FUNC);

        init_stacksize();
        walk(node, &mut topenv, true);
        node.stacksize = stacksize();
    }
    return globals();
}
<|endoftext|>


<commit_before>//!
//! Exposes the crypto_sign functionality of NaCl.
//!
//! ## Usage
//!
//! ```rust{.example}
//! use knuckle::sign::Keypair;
//!
//! let key = Keypair::new();
//! let msg = b"some important message";
//!
//! let signed = key.sign(msg);
//!
//! // ...
//!
//! let plain_opt = signed.verify();
//! assert!(plain_opt.is_some());
//! assert!(plain_opt.unwrap().as_slice() == msg);
//! ```

use bindings::*;
use std::slice::bytes::copy_memory;

/// Number of bytes in the sign public key
pub const PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub const SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub const SIGN_BYTES: uint = 64;

/// Key used to verify the validity of signed messages.
pub struct PublicKey ([u8, ..PUBKEY_BYTES]);

/// Secret key used to generate valid message signatures.
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    /// Public key matching the key used to sign this message.
    pub pk: PublicKey,
    /// Cryptographically signed message, containing both signature and message.
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => panic!("Impossible things happened")
            }
        }
    }

    /// Serialize the `SignedMsg` into bytes. Response will contain both the
    /// public key to verify the message as well as the signed message itself.
    ///
    /// **IMPORTANT**: THIS SHOULD NOT BE USED TO TRANSFER THE PUBLIC KEY. It is
    /// only included for convenience. Make sure the client checking the signature
    /// has some secure source for receiving the correct verification key.
    pub fn as_bytes(&self) -> Vec<u8> {
        let PublicKey(pk) = self.pk;
        let mut buf = pk.to_vec();

        buf.push_all(self.signed.as_slice());

        buf
    }

    /// Construct a SignedMsg from the form serialized by `as_bytes`.
    ///
    /// **IMPORTANT**: The same warning in the documentation for `as_bytes`
    /// applies here. Don't blindly trust keys!
    pub fn from_bytes(msg: &[u8]) -> Option<SignedMsg> {
        if msg.len() < PUBKEY_BYTES + SIGN_BYTES {
            return None;
        }

        let mut pk = [0u8, ..PUBKEY_BYTES];
        let signed = msg.slice_from(PUBKEY_BYTES);

        copy_memory(&mut pk, msg.slice(0, PUBKEY_BYTES));

        Some(SignedMsg { pk: PublicKey(pk), signed: signed.to_vec() })
    }
}

/// Struct representing a signing key pair, used to create signed messages.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's signing key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: self.pk, signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}

#[test]
fn test_sign_tamper_resistance() {
    let keypair = Keypair::new();
    let msg = b"something";

    let sig = keypair.sign(msg);
    let mut tampered_msg = sig.signed.clone();

    // Try tampering each of the different bytes of the signed message
    for i in range(0, tampered_msg.len()) {
        tampered_msg[i] = tampered_msg[i] ^ 0xFF;

        let tampered_sig = SignedMsg { pk: keypair.pk, signed: tampered_msg.clone() };
        let design = tampered_sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, design);
        assert!(design.is_none());
    }
}

#[test]
fn test_sign_serialization() {
    let keypair = Keypair::new();
    let msg = b"my message";

    let signed = keypair.sign(msg);
    let serialized = signed.as_bytes();
    let deserialized = SignedMsg::from_bytes(serialized.as_slice());

    assert!(deserialized.is_some());

    let validated_msg = deserialized.unwrap().verify();

    assert!(validated_msg.is_some());
    assert!(validated_msg.unwrap().as_slice() == msg);
}
<commit_msg>Update to latest Rust HEAD<commit_after>//!
//! Exposes the crypto_sign functionality of NaCl.
//!
//! ## Usage
//!
//! ```rust{.example}
//! use knuckle::sign::Keypair;
//!
//! let key = Keypair::new();
//! let msg = b"some important message";
//!
//! let signed = key.sign(msg);
//!
//! // ...
//!
//! let plain_opt = signed.verify();
//! assert!(plain_opt.is_some());
//! assert!(plain_opt.unwrap().as_slice() == msg);
//! ```

use bindings::*;
use std::slice::bytes::copy_memory;

/// Number of bytes in the sign public key
pub const PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub const SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub const SIGN_BYTES: uint = 64;

/// Key used to verify the validity of signed messages.
pub struct PublicKey ([u8, ..PUBKEY_BYTES]);

/// Secret key used to generate valid message signatures.
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    /// Public key matching the key used to sign this message.
    pub pk: PublicKey,
    /// Cryptographically signed message, containing both signature and message.
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => panic!("Impossible things happened")
            }
        }
    }

    /// Serialize the `SignedMsg` into bytes. Response will contain both the
    /// public key to verify the message as well as the signed message itself.
    ///
    /// **IMPORTANT**: THIS SHOULD NOT BE USED TO TRANSFER THE PUBLIC KEY. It is
    /// only included for convenience. Make sure the client checking the signature
    /// has some secure source for receiving the correct verification key.
    pub fn as_bytes(&self) -> Vec<u8> {
        let PublicKey(pk) = self.pk;
        let mut buf = pk.to_vec();

        buf.push_all(self.signed.as_slice());

        buf
    }

    /// Construct a SignedMsg from the form serialized by `as_bytes`.
    ///
    /// **IMPORTANT**: The same warning in the documentation for `as_bytes`
    /// applies here. Don't blindly trust keys!
    pub fn from_bytes(msg: &[u8]) -> Option<SignedMsg> {
        if msg.len() < PUBKEY_BYTES + SIGN_BYTES {
            return None;
        }

        let mut pk = [0u8, ..PUBKEY_BYTES];
        let signed = msg.slice_from(PUBKEY_BYTES);

        copy_memory(&mut pk, msg.slice(0, PUBKEY_BYTES));

        Some(SignedMsg { pk: PublicKey(pk), signed: signed.to_vec() })
    }
}

/// Struct representing a signing key pair, used to create signed messages.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's signing key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: PublicKey(pk), signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}

#[test]
fn test_sign_tamper_resistance() {
    let keypair = Keypair::new();
    let msg = b"something";

    let sig = keypair.sign(msg);
    let mut tampered_msg = sig.signed.clone();

    // Try tampering each of the different bytes of the signed message
    for i in range(0, tampered_msg.len()) {
        tampered_msg[i] = tampered_msg[i] ^ 0xFF;

        let tampered_sig = SignedMsg { pk: keypair.pk, signed: tampered_msg.clone() };
        let design = tampered_sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, design);
        assert!(design.is_none());
    }
}

#[test]
fn test_sign_serialization() {
    let keypair = Keypair::new();
    let msg = b"my message";

    let signed = keypair.sign(msg);
    let serialized = signed.as_bytes();
    let deserialized = SignedMsg::from_bytes(serialized.as_slice());

    assert!(deserialized.is_some());

    let validated_msg = deserialized.unwrap().verify();

    assert!(validated_msg.is_some());
    assert!(validated_msg.unwrap().as_slice() == msg);
}
<|endoftext|>