<commit_before>extern crate regex;
extern crate readline;

use regex::Regex;
use std::collections::HashMap;
use std::io::prelude::*;
use std::iter::Iterator;
use std::string::String;

#[derive(Debug, PartialEq, Clone)]
enum Atom {
    Integer(i64),
    Float(f64),
    Symbol(String),
    Boolean(bool),
    Nil
}

type Function = Fn(&Vec<Atom>) -> AtomResult;
type FunctionMap = HashMap<String, Box<Function>>;

#[derive(Debug)]
enum Error {
    UnexpectedType,
    Parser,
    InvalidArguments,
    NotAFunction,
    NotImplemented
}

type AtomResult = Result<Atom, Error>;
type ParseResult = Result<Node, Error>;

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

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

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

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

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

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

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

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

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

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

    for i in args.iter().skip(1) {
        if v != i {
            return Ok(Atom::Boolean(false));
        }
    }
    Ok(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 tokenize(line: &str) -> ParseResult {
    let r = Regex::new(r"\s+").unwrap();
    let l = line.replace("(", " ( ").replace(")", " ) ").trim().to_string();
    let iter = r.split(&l);
    return read_tokens(&mut iter.peekable());
}

fn atom(token: &str) -> Atom {
    match token {
        "true" => return Atom::Boolean(true),
        "false" => return Atom::Boolean(false),
        _ => ()
    }

    let i = token.parse::<i64>();
     match i {
         Ok(v) => Atom::Integer(v),
         _ => {
             let f = token.parse::<f64>();
             match f {
                 Ok(x) => Atom::Float(x),
                 _ => Atom::Symbol(token.to_string())
             }
         },
     }
}

#[derive(Debug,PartialEq)]
struct Node {
    atom: Atom,
    children: Vec<Node>
}

fn read_tokens(iter: &mut std::iter::Peekable<regex::RegexSplits>) -> ParseResult {
    let mut node = Node{ atom: Atom::Nil, children: vec![] };

    match iter.next() {
        Some("(") => {
            loop {
                match iter.peek() {
                    Some(&")") => {
                        iter.next();
                        break
                    },
                    Some(_) => (),
                    None => return Err(Error::Parser)
                }
                let token = try!(read_tokens(iter));
                node.children.push(token);
            }
        },
        Some(")") => return Err(Error::Parser),
        Some(x) => {
            node.atom = atom(x);
        },
        None => return Err(Error::Parser)
    }
    return Ok(node);
}

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

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

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

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

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

    for i in node.children.iter().skip(1) {
        let atom = try!(eval(i, env));
        args.push(atom);
    }
    return Ok(args);
}

fn eval(node: &Node, env: &mut Env) -> AtomResult {
    if let Atom::Nil = node.atom {
        if let Atom::Symbol(ref s) = node.children[0].atom {
            match s.as_ref() {
                "define" => {
                    let args = try!(eval_args(node, env));
                    return define(args, env);
                },
                "get" => {
                    return get( try!(eval_args(node, env)), env);
                 },
                "if" => {
                    let predicate = try!(eval(&node.children[1], env));
                    if let Atom::Boolean(b) = predicate {
                        if b {
                            return eval(&node.children[2], env);
                        } else if node.children.len() > 2 {
                            return eval(&node.children[3], env);
                        }
                    }
                    return Err(Error::InvalidArguments)
                },
                _ => ()
            };

            let args = try!(eval_args(node, env));

            if let Some(f) = env.func_map.get(s) {
                f(&args)
            } else {
                Ok(Atom::Nil)
            }
        } else {
            Err(Error::NotAFunction)
        }
    } else {
        Ok(node.atom.clone())
    }
}

fn parse(line: &str) -> ParseResult {
    tokenize(line)
}

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

    loop {
        match readline::readline(">") {
            Some(s) => {
                if let Ok(p) = parse(&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 super::Node;
    use super::Atom;
    use super::atom;
    use super::parse;

    fn make_atom_node(s: &str) -> Node {
        return Node{ atom: atom(s), children: vec![]};
    }

    #[test]
    fn atom_test() {
        assert_eq!(Atom::Integer(32), atom("32"));
        assert_eq!(Atom::Symbol("symbol".to_string()), atom("symbol"));
    }

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

        assert_eq!(Atom::Nil, x.atom);
        assert_eq!(3, x.children.len());

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

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

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

        assert_eq!( atom("+"), x.children[0].atom);
        assert_eq!( atom("1"), x.children[1].atom);
        assert_eq!( Atom::Nil, x.children[2].atom);

        assert_eq!( 3, x.children[2].children.len());
        assert_eq!( atom("*"), x.children[2].children[0].atom);
        assert_eq!( atom("2"), x.children[2].children[1].atom);
        assert_eq!( atom("2"), x.children[2].children[2].atom);
    }

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

        assert_eq!( atom("+"), x.children[0].atom);
        assert_eq!( atom("1"), x.children[1].atom);
        assert_eq!( Atom::Nil, x.children[2].atom);

        assert_eq!( 3, x.children[2].children.len());
        assert_eq!( atom("+"), x.children[2].children[0].atom);
        assert_eq!( atom("2"), x.children[2].children[1].atom);
        assert_eq!( atom("3"), x.children[2].children[2].atom);

        assert_eq!(atom("4"), x.children[3].atom);
    }

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

    #[test]
    #[should_panic]
    fn eof() {
         parse("").unwrap();
    }
}
<commit_msg>random cleanup<commit_after>extern crate regex;
extern crate readline;

use regex::Regex;
use std::collections::HashMap;
use std::io::prelude::*;
use std::iter::Iterator;
use std::string::String;

#[derive(Debug, PartialEq, Clone)]
enum Atom {
    Integer(i64),
    Float(f64),
    Symbol(String),
    Boolean(bool),
    Nil
}

type Function = Fn(&Vec<Atom>) -> AtomResult;
type FunctionMap = HashMap<String, Box<Function>>;

#[derive(Debug)]
enum Error {
    UnexpectedType,
    Parser,
    InvalidArguments,
    NotAFunction,
    NotImplemented
}

type AtomResult = Result<Atom, Error>;
type ParseResult = Result<Node, Error>;

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

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

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

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

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

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

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

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

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

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

    for i in args.iter().skip(1) {
        if v != i {
            return Ok(Atom::Boolean(false));
        }
    }
    Ok(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 tokenize(line: &str) -> ParseResult {
    let r = Regex::new(r"\s+").unwrap();
    let l = line.replace("(", " ( ").replace(")", " ) ").trim().to_string();
    let iter = r.split(&l);
    return read_tokens(&mut iter.peekable());
}

fn atom(token: &str) -> Atom {
    match token {
        "true" => return Atom::Boolean(true),
        "false" => return Atom::Boolean(false),
        _ => ()
    }

    let i = token.parse::<i64>();
    match i {
        Ok(v) => Atom::Integer(v),
        _ => {
            let f = token.parse::<f64>();
            match f {
                Ok(x) => Atom::Float(x),
                _ => Atom::Symbol(token.to_string())
            }
        },
    }
}

#[derive(Debug,PartialEq)]
struct Node {
    atom: Atom,
    children: Vec<Node>
}

fn read_tokens(iter: &mut std::iter::Peekable<regex::RegexSplits>) -> ParseResult {
    let mut node = Node{ atom: Atom::Nil, children: vec![] };

    match iter.next() {
        Some("(") => {
            loop {
                match iter.peek() {
                    Some(&")") => {
                        iter.next();
                        break
                    },
                    Some(_) => {
                        let token = try!(read_tokens(iter));
                        node.children.push(token);
                    },
                    None => return Err(Error::Parser)
                }
            }
        },
        Some(")") => return Err(Error::Parser),
        Some(x) => node.atom = atom(x),
        None => return Err(Error::Parser)
    }
    return Ok(node);
}

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

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

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

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

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

    for i in node.children.iter().skip(1) {
        let atom = try!(eval(i, env));
        args.push(atom);
    }
    return Ok(args);
}

fn eval(node: &Node, env: &mut Env) -> AtomResult {
    if let Atom::Nil = node.atom {
        if let Atom::Symbol(ref s) = node.children[0].atom {
            match s.as_ref() {
                "define" => {
                    let args = try!(eval_args(node, env));
                    return define(args, env);
                },
                "get" => {
                    return get( try!(eval_args(node, env)), env);
                 },
                "if" => {
                    let predicate = try!(eval(&node.children[1], env));

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

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

            let args = try!(eval_args(node, env));

            if let Some(f) = env.func_map.get(s) {
                f(&args)
            } else {
                Ok(Atom::Nil)
            }
        } else {
            Err(Error::NotAFunction)
        }
    } else {
        Ok(node.atom.clone())
    }
}

fn parse(line: &str) -> ParseResult {
    tokenize(line)
}

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

    loop {
        match readline::readline(">") {
            Some(s) => {
                if let Ok(p) = parse(&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 super::Node;
    use super::Atom;
    use super::atom;
    use super::parse;
    use super::default_env;
    use super::eval;

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

    fn make_atom_node(s: &str) -> Node {
        return Node{ atom: atom(s), children: vec![]};
    }

    #[test]
    fn atom_test() {
        assert_eq!(Atom::Integer(32), atom("32"));
        assert_eq!(Atom::Symbol("symbol".to_string()), atom("symbol"));
    }

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

        assert_eq!(Atom::Nil, x.atom);
        assert_eq!(3, x.children.len());

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

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

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

        assert_eq!( atom("+"), x.children[0].atom);
        assert_eq!( atom("1"), x.children[1].atom);
        assert_eq!( Atom::Nil, x.children[2].atom);

        assert_eq!( 3, x.children[2].children.len());
        assert_eq!( atom("*"), x.children[2].children[0].atom);
        assert_eq!( atom("2"), x.children[2].children[1].atom);
        assert_eq!( atom("2"), x.children[2].children[2].atom);
    }

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

        assert_eq!( atom("+"), x.children[0].atom);
        assert_eq!( atom("1"), x.children[1].atom);
        assert_eq!( Atom::Nil, x.children[2].atom);

        assert_eq!( 3, x.children[2].children.len());
        assert_eq!( atom("+"), x.children[2].children[0].atom);
        assert_eq!( atom("2"), x.children[2].children[1].atom);
        assert_eq!( atom("3"), x.children[2].children[2].atom);

        assert_eq!(atom("4"), x.children[3].atom);
    }

    #[test]
    fn if_special_form() {
        let x = eval(&parse("(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(&parse("(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() {
        parse("(+ 1").unwrap();
    }

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


<commit_before>/// Rosten
/// Track Bring packages in Rust
/// For testing use "TESTPACKAGE-AT-PICKUPPOINT" as tracking number
/// https://www.mybring.com/tracking/api

extern crate curl;
extern crate clap;
extern crate serde_json;

use std::env;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use curl::easy::Easy;
use std::fmt::Display;
use serde_json::Value;

// response.rs contains structs for API response.
mod response;

pub fn main() {

    // TODO Figure out ~/ path so compiler can find the file easily
    let path = Path::new("/home/stian/projects/rosten/tracking.json");
    let display = path.display();
    let mut file = match File::open(&path) {
        Err(e) => panic!("unable to open {}: {}", display, e.description()),
        Ok(file) => file,
    };

    let mut buffer = String::new();
    file.read_to_string(&mut buffer).unwrap();

    // TODO Better names
    let data: Value = serde_json::from_str(&buffer).unwrap();

    // TODO Iterate over consignmentSet
    let values = data.as_object()
        .and_then(|object| object.get("consignmentSet"))
        .and_then(|values| values.as_object())
        .unwrap_or_else(|| {
            panic!("Failed to get object value from json"); // fails at runtime here
        });

    for (key, value) in values.iter() {
        let results = value.find("consignmentId")
            .and_then(|value| value.as_object())
            .unwrap_or_else(|| {
                panic!("Failed to get value from within values");
            });
        println!("{} -> {:?}", key, results);
    }
}
<commit_msg>reverte to rustc_serialize lib and deserialize to structs<commit_after>/// Rosten
/// Track Bring packages in Rust
/// For testing use "TESTPACKAGE-AT-PICKUPPOINT" as tracking number
/// https://www.mybring.com/tracking/api

extern crate curl;
extern crate clap;
extern crate rustc_serialize;
mod response;

use std::env;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use curl::easy::Easy;
use rustc_serialize::json;
use response::Response;

pub fn main() {

    // TODO Figure out ~/ path so compiler can find the file easily
    let path = Path::new("/home/stian/projects/rosten/tracking.json");
    let display = path.display();

    let mut file = match File::open(&path) {
    Err(e) => panic!("unable to open {}: {}", display, e.description()),
    Ok(file) => file,
    };

    // Do I need to read into a buffer first? Does this affect type?
    let mut buffer = String::new();
    file.read_to_string(&mut buffer).unwrap();

    // TODO Better names
    let deserialize :Response = json::decode(&buffer).unwrap();
    let sets = deserialize.consignmentSet;
    for i in 0..sets.len() {
        let set = &sets[i];
        println!("Sets is {}", set.senderName);
        for x in 0..set.packageSet.len() {
            let package_set = &set.packageSet[x];
            println!("Packageset number is {}", x);
            println!("Packageset is {}", package_set.statusDescription);
        }
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::env;

// OWNERSHIP: we cannot use a binding after we’ve moved it aka taken a reference to it or passed it as an args
//
//

// enum CommandType {
// 	A_COMMAND,
// 	C_COMMAND,
// 	L_COMMAND,
// }
struct Parser<'a> {
	commands: Vec<&'a str>,
}

impl<'a> Parser<'a> {
	// remove all white space and comments
	fn new(asm_filename: &str) -> Parser {
		let asm_file_content = load_asm(asm_filename);
		Parser {
			commands: asm_file_content.trim().split('\n').collect(),
		}
	}
}

fn load_asm(filename: &str) -> String {
	//create a path to the desired file
	let path = Path::new(filename);
	let display = path.display();

	// open the path in read-only mode
	let mut file = match File::open(&path) {
		Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
		Ok(file) => file,
	};

	// Read the file content into a string
	let mut file_content = String::new();
	match file.read_to_string(&mut file_content) {
		Err(why) => panic!("couldn't read {}: {}", display, Error::description(&why)),
		Ok(_) => print!("{} contains:\n{}", display, file_content),
	}
	file_content
}

fn main() {
	let args: Vec<String> = env::args().collect();
	if args.len() != 2 {
		println!("Usage: assembler [PATH_TO_ASM_FILE]");
		return;
	}
	let path_to_asm = &args[1];
	let parser = Parser::new(path_to_asm);
}
<commit_msg>Parser struct unique field is the asm file stream, ready to be parsed.<commit_after>use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::env;

struct Parser {
	input_file: File,
}

impl Parser {
	fn new(filename: &str) -> Parser {
		let path = Path::new(filename);
		let file = match File::open(&path) {
			Err(why) => panic!("couldn't open {}: {}", path.display(), Error::description(&why)),
			Ok(file) => file,
		};

		Parser { input_file: file}
	}
}

fn main() {
	let args: Vec<String> = env::args().collect();
	if args.len() != 2 {
		println!("Usage: assembler [PATH_TO_ASM_FILE]");
		return;
	}
	let path_to_asm = &args[1];
	let parser = Parser::new(path_to_asm);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::str::FromStr;

use std::path::{Path, PathBuf};
use std::env;

/// Coloring of command output.
#[derive(Debug)]
pub enum Coloring {
    Auto,
    Never,
    Always
}

impl FromStr for Coloring {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "auto"   => Ok(Coloring::Auto),
            "never"  => Ok(Coloring::Never),
            "always" => Ok(Coloring::Always),
            _        => Err(())
        }
    }
}

#[derive(Debug)]
pub enum Edges {
    Explicit,
    Implicit,
    Both
}

impl FromStr for Edges {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "explicit" => Ok(Edges::Explicit),
            "implicit" => Ok(Edges::Implicit),
            "both"     => Ok(Edges::Both),
            _          => Err(())
        }
    }
}

/// Returns an absolute path to the rules, starting at the given directory. The
/// canonical name for the JSON rules file is "button.json". This function shall
/// search for the file in the given starting directory and all parent
/// directories. Returns `None` if it cannot be found.
pub fn find_rules_path(start: &Path) -> Option<PathBuf> {
    let path = start.join("button.json");

    if path.is_file() {
        Some(path)
    }
    else {
        // Search in the parent directory.
        match path.parent() {
            Some(parent) => find_rules_path(parent),
            None => None,
        }
    }
}

/// Returns a path to the rules.
pub fn rules_path(path: Option<&Path>) -> PathBuf {
    match path {
        Some(path) => path.to_path_buf(),
        None => {
            let cwd = env::current_dir().unwrap();
            match find_rules_path(&cwd) {
                Some(path) => path,

                // Not found. Just assume it lives in the current directory even
                // though it doesn't (or it would have been found). The error
                // will get reported when trying to load this file later.
                None => PathBuf::from("button.json"),
            }
        }
    }
}
<commit_msg>Fix stack overflow<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::str::FromStr;

use std::path::{Path, PathBuf};
use std::env;

/// Coloring of command output.
#[derive(Debug)]
pub enum Coloring {
    Auto,
    Never,
    Always
}

impl FromStr for Coloring {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "auto"   => Ok(Coloring::Auto),
            "never"  => Ok(Coloring::Never),
            "always" => Ok(Coloring::Always),
            _        => Err(())
        }
    }
}

#[derive(Debug)]
pub enum Edges {
    Explicit,
    Implicit,
    Both
}

impl FromStr for Edges {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "explicit" => Ok(Edges::Explicit),
            "implicit" => Ok(Edges::Implicit),
            "both"     => Ok(Edges::Both),
            _          => Err(())
        }
    }
}

/// Returns an absolute path to the rules, starting at the given directory. The
/// canonical name for the JSON rules file is "button.json". This function shall
/// search for the file in the given starting directory and all parent
/// directories. Returns `None` if it cannot be found.
pub fn find_rules_path(start: &Path) -> Option<PathBuf> {
    let path = start.join("button.json");

    if path.is_file() {
        Some(path)
    }
    else {
        // Search in the parent directory.
        match start.parent() {
            Some(parent) => find_rules_path(parent),
            None => None,
        }
    }
}

/// Returns a path to the rules.
pub fn rules_path(path: Option<&Path>) -> PathBuf {
    match path {
        Some(path) => path.to_path_buf(),
        None => {
            let cwd = env::current_dir().unwrap();
            match find_rules_path(&cwd) {
                Some(path) => path,

                // Not found. Just assume it lives in the current directory even
                // though it doesn't (or it would have been found). The error
                // will get reported when trying to load this file later.
                None => PathBuf::from("button.json"),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(collections)]
#![feature(asm)]
#![feature(stmt_expr_attributes)]
#![feature(type_macros)]
#![feature(associated_consts)]
#![feature(allocator)]
#![feature(alloc)]
#![feature(braced_empty_structs)] // XXX: For now
#![feature(start)]
#![feature(reflect_marker)]
#![feature(const_fn)]
//#![feature(core_str_ext)]
//#![feature(ptr_as_ref)]
#![no_std]
#![allow(dead_code)]              // XXX: For now, because a lot of unused structs
extern crate rlibc;
extern crate mm;
extern crate alloc;
extern crate collections;

#[macro_use]
mod std;
mod xen;

pub use xen::poweroff;
pub use xen::console_io::STDOUT;
pub use xen::mem::sbrk;
pub use xen::emergency_console::EMERGENCY_CONSOLE as DEBUG;
use xen::start_info::start_info_page;
use core::fmt::Write;
use alloc::boxed::Box;

#[lang = "eh_personality"]
extern fn eh_personality() {}

const LEN : usize = 3000;

#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn rust_begin_unwind(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
    writeln!(STDOUT, "In file {} at line {} (XXX LINE COUNT IS CURRENTLY BROKEN)", file, line).unwrap();
    writeln!(STDOUT, "{:?}", args).unwrap();
    xen::crash();
}

fn print_init_info(){
    writeln!(STDOUT, "Magic: {}", core::str::from_utf8(&start_info_page.magic).unwrap_or("ERROR")).unwrap();
    writeln!(STDOUT, "nr_pages: {:#X}", start_info_page.nr_pages).unwrap();
    writeln!(STDOUT, "shared_info: {:#X}", start_info_page.shared_info).unwrap();
}

#[no_mangle]
pub extern fn prologue() {
    unsafe {
        writeln!(DEBUG, "prologue!").unwrap();
        use core::ptr;
        let null: *const u8 = ptr::null();
        let argv: *const *const u8 = &null;
        writeln!(DEBUG, "mm::setup").unwrap();
        writeln!(DEBUG, "xen::console_io::initialize").unwrap();
        xen::console_io::initialize();
        writeln!(DEBUG, "xen::xenstore::initialize").unwrap();
        xen::xenstore::initialize();
        writeln!(DEBUG, "end of prologue!").unwrap();
        let _result = main(0, argv);
    }
}

#[start]
pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
    writeln!(DEBUG, "main!").unwrap();

    let mut s = collections::String::new();
    writeln!(STDOUT, "Growing sequences of numbers to test allocation...");
    for _ in 0 .. 1 {
        for j in 0 .. 10 {
            s.push(('0' as u8 + j) as char);
            writeln!(STDOUT, "{}, {}, {}", &s, s.len(), s.as_ptr() as usize);
        }
    }
    unsafe {
        let vm_name = xen::xenstore::XENSTORE.write().as_mut().unwrap().read("name").unwrap();
        writeln!(STDOUT, "Hello world {}!", vm_name).unwrap();
        let key = "examplekey";
        let value = "examplevalue";
        xen::xenstore::XENSTORE.write().as_mut().unwrap().write(key, value).unwrap();
        writeln!(STDOUT, "Wrote!").unwrap();
//        let read = xen::xenstore::XENSTORE.write().as_mut().unwrap().read(key).unwrap();
//        writeln!(STDOUT, "wrote {}, read {}", value, read).unwrap();
    }

    let x = Box::new(12);

    if *x == 12 {
        writeln!(STDOUT, "Box Worked").unwrap();
    }
    else {
        writeln!(STDOUT, "Box Failed").unwrap();
    }

    let mut a = Box::new([0; LEN]);
    for i in 1..LEN {
        a[i] = i;
    }

    for i in 1..LEN {
        if a[i] != i {
            writeln!(STDOUT, "Error in Memory").unwrap();
        }
    }

    writeln!(DEBUG, "done!").unwrap();
    print_init_info();

    0
}

<commit_msg>fixed build warnings<commit_after>#![feature(lang_items)]
#![feature(collections)]
#![feature(asm)]
#![feature(stmt_expr_attributes)]
#![feature(type_macros)]
#![feature(associated_consts)]
#![feature(allocator)]
#![feature(alloc)]
#![feature(braced_empty_structs)] // XXX: For now
#![feature(start)]
#![feature(reflect_marker)]
#![feature(const_fn)]
//#![feature(core_str_ext)]
//#![feature(ptr_as_ref)]
#![no_std]
#![allow(dead_code)]              // XXX: For now, because a lot of unused structs
extern crate rlibc;
extern crate mm;
extern crate alloc;
extern crate collections;

#[macro_use]
mod std;
mod xen;

pub use xen::poweroff;
pub use xen::console_io::STDOUT;
pub use xen::mem::sbrk;
pub use xen::emergency_console::EMERGENCY_CONSOLE as DEBUG;
use xen::start_info::start_info_page;
use core::fmt::Write;
use alloc::boxed::Box;

#[lang = "eh_personality"]
extern fn eh_personality() {}

const LEN : usize = 3000;

#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn rust_begin_unwind(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
    writeln!(STDOUT, "In file {} at line {} (XXX LINE COUNT IS CURRENTLY BROKEN)", file, line).unwrap();
    writeln!(STDOUT, "{:?}", args).unwrap();
    xen::crash();
}

fn print_init_info(){
    writeln!(STDOUT, "Magic: {}", core::str::from_utf8(&start_info_page.magic).unwrap_or("ERROR")).unwrap();
    writeln!(STDOUT, "nr_pages: {:#X}", start_info_page.nr_pages).unwrap();
    writeln!(STDOUT, "shared_info: {:#X}", start_info_page.shared_info).unwrap();
}

#[no_mangle]
pub extern fn prologue() {
    unsafe {
        writeln!(DEBUG, "prologue!").unwrap();
        use core::ptr;
        let null: *const u8 = ptr::null();
        let argv: *const *const u8 = &null;
        writeln!(DEBUG, "mm::setup").unwrap();
        writeln!(DEBUG, "xen::console_io::initialize").unwrap();
        xen::console_io::initialize();
        writeln!(DEBUG, "xen::xenstore::initialize").unwrap();
        xen::xenstore::initialize();
        writeln!(DEBUG, "end of prologue!").unwrap();
        let _result = main(0, argv);
    }
}

#[start]
pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
    writeln!(DEBUG, "main!").unwrap();

    let mut s = collections::String::new();
    writeln!(STDOUT, "Growing sequences of numbers to test allocation...").unwrap();
    for _ in 0 .. 1 {
        for j in 0 .. 10 {
            s.push(('0' as u8 + j) as char);
            writeln!(STDOUT, "{}, {}, {}", &s, s.len(), s.as_ptr() as usize).unwrap();
        }
    }
    unsafe {
        let vm_name = xen::xenstore::XENSTORE.write().as_mut().unwrap().read("name").unwrap();
        writeln!(STDOUT, "Hello world {}!", vm_name).unwrap();
        let key = "examplekey";
        let value = "examplevalue";
        xen::xenstore::XENSTORE.write().as_mut().unwrap().write(key, value).unwrap();
        writeln!(STDOUT, "Wrote!").unwrap();
//        let read = xen::xenstore::XENSTORE.write().as_mut().unwrap().read(key).unwrap();
//        writeln!(STDOUT, "wrote {}, read {}", value, read).unwrap();
    }

    let x = Box::new(12);

    if *x == 12 {
        writeln!(STDOUT, "Box Worked").unwrap();
    }
    else {
        writeln!(STDOUT, "Box Failed").unwrap();
    }

    let mut a = Box::new([0; LEN]);
    for i in 1..LEN {
        a[i] = i;
    }

    for i in 1..LEN {
        if a[i] != i {
            writeln!(STDOUT, "Error in Memory").unwrap();
        }
    }

    writeln!(DEBUG, "done!").unwrap();
    print_init_info();

    0
}

<|endoftext|>


<commit_before>#![feature(convert)]

#[macro_use] extern crate nickel;
extern crate rustc_serialize;
extern crate hyper;
extern crate nickel_postgres;
extern crate postgres;
extern crate r2d2_postgres;
extern crate r2d2;

use nickel::{Nickel, HttpRouter, QueryString};
use nickel::extensions::Redirect;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;
use std::io::Read;
use std::env;
use r2d2::{NopErrorHandler, PooledConnection};
use r2d2_postgres::{SslMode, PostgresConnectionManager};
use nickel_postgres::{PostgresMiddleware, PostgresRequestExtensions};

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct Data {
    data: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct User {
    id: i32,
    email: String,
    created_at: String,
    updated_at: String,
    first_name: String,
    last_name: String,
    graduation: String,
    major: String,
    shirt_size: String,
    dietary_restrictions: String,
    special_needs: Option<String>,
    date_of_birth: String,
    gender: String,
    phone_number: String,
    school: School,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct School {
    id: i32,
    name: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct TokenResp {
    access_token: String,
    token_type: String,
    scope: String,
    created_at: u64,
}

macro_rules! optry {
    ( $x:expr ) => {
        match $x {
            Some(v) => v,
            None => return None,
        }
    }
}

fn do_request(code: &str) -> Option<Data> {
    let id = env::var("ID").expect("Failed to get ID value");
    let secret = env::var("SECRET").expect("Failed to get SECRET value");
    let redirect = env::var("REDIRECT").expect("Failed to get REDIRECT value");

    let url = format!("https://my.mlh.io/oauth/token?client_id={}&client_secret={}&code={}&redirect_uri={}&grant_type=authorization_code",
                      id, secret, code, redirect);

    let client = Client::new();
    let mut res = optry!(client.post(url.as_str())
        .header(Connection::close())
        .send().ok());

    let mut body = String::new();
    optry!(res.read_to_string(&mut body).ok());

    let token: TokenResp = optry!(json::decode(body.as_str()).ok());
    let url2 = format!("https://my.mlh.io/api/v1/user?access_token={}",
                       token.access_token);

    res = optry!(client.get(url2.as_str())
        .header(Connection::close())
        .send().ok());
    body = String::new();
    optry!(res.read_to_string(&mut body).ok());

    match json::decode(body.as_str()) {
        Ok(b) => Some(b),
        Err(_) => None,
    }
}

fn create_table(conn: PooledConnection<PostgresConnectionManager>) {
    let _r = conn.execute(
            "CREATE TABLE IF NOT EXISTS person (
                id SERIAL PRIMARY KEY,
                email VARCHAR NOT NULL,
                created_at VARCHAR NOT NULL,
                updated_at VARCHAR NOT NULL,
                first_name VARCHAR NOT NULL,
                last_name VARCHAR NOT NULL,
                graduation VARCHAR NOT NULL,
                major VARCHAR NOT NULL,
                shirt_size VARCHAR NOT NULL,
                dietary_restrictions VARCHAR NOT NULL,
                special_needs VARCHAR,
                date_of_birth VARCHAR NOT NULL,
                gender VARCHAR NOT NULL,
                phone_number VARCHAR NOT NULL,
                school_id integer,
                school_name VARCHAR
                )",
            &[]
        );
}

fn main() {
    let mut app = Nickel::new();

    let postgres_url = env::var("DATABASE")
        .expect("Failed to get DATABASE value");
    let dbpool = PostgresMiddleware::new(&*postgres_url, SslMode::None, 5,
                                         Box::new(NopErrorHandler))
        .expect("Failed to start PostgresMiddleware");

    create_table(dbpool.pool.clone().get().unwrap());
    app.utilize(dbpool);

    app.get("/callback", middleware! { |request, response|
        let conn = request.db_conn();
        let user_data = match request.query().get("code") {
            Some(s) => do_request(s),
            None => None
        }.unwrap().data;

        let r = conn.execute(
                "INSERT INTO person (id, email, created_at, updated_at,
                first_name, last_name, graduation, major, shirt_size,
                dietary_restrictions, special_needs, date_of_birth, gender,
                phone_number, school_id, school_name) VALUES ($1, $2, $3, $4,
                $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)",
                &[&user_data.id, &user_data.email, &user_data.created_at,
                  &user_data.updated_at, &user_data.first_name,
                  &user_data.last_name, &user_data.graduation, &user_data.major,
                  &user_data.shirt_size, &user_data.dietary_restrictions,
                  &user_data.special_needs, &user_data.date_of_birth,
                  &user_data.gender, &user_data.phone_number,
                  &user_data.school.id, &user_data.school.name]
            );
        match r {
            Ok(v) => println!("{:?}", v),
            Err(e) => println!("{:?}", e)
        }

        return response.redirect("http://hack.cwru.edu")
    });

    app.get("/start", middleware! { |_req, response|
        let id = env::var("ID").expect("Failed to get ID value");
        let redirect = env::var("REDIRECT")
            .expect("Failed to get REDIRECT value");
        return response.redirect(
            format!(
                    "http://my.mlh.io/oauth/authorize?client_id={}&redirect_uri={}&response_type=code",
                    id, redirect
                )
            );
    });

    let bind = match env::var("BIND") {
        Ok(v) => v,
        Err(_) => "127.0.0.1:8080".to_string(),
    };

    app.listen(bind.as_str());
}
<commit_msg>redirect to /register.html<commit_after>#![feature(convert)]

#[macro_use] extern crate nickel;
extern crate rustc_serialize;
extern crate hyper;
extern crate nickel_postgres;
extern crate postgres;
extern crate r2d2_postgres;
extern crate r2d2;

use nickel::{Nickel, HttpRouter, QueryString};
use nickel::extensions::Redirect;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;
use std::io::Read;
use std::env;
use r2d2::{NopErrorHandler, PooledConnection};
use r2d2_postgres::{SslMode, PostgresConnectionManager};
use nickel_postgres::{PostgresMiddleware, PostgresRequestExtensions};

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct Data {
    data: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct User {
    id: i32,
    email: String,
    created_at: String,
    updated_at: String,
    first_name: String,
    last_name: String,
    graduation: String,
    major: String,
    shirt_size: String,
    dietary_restrictions: String,
    special_needs: Option<String>,
    date_of_birth: String,
    gender: String,
    phone_number: String,
    school: School,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct School {
    id: i32,
    name: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct TokenResp {
    access_token: String,
    token_type: String,
    scope: String,
    created_at: u64,
}

macro_rules! optry {
    ( $x:expr ) => {
        match $x {
            Some(v) => v,
            None => return None,
        }
    }
}

fn do_request(code: &str) -> Option<Data> {
    let id = env::var("ID").expect("Failed to get ID value");
    let secret = env::var("SECRET").expect("Failed to get SECRET value");
    let redirect = env::var("REDIRECT").expect("Failed to get REDIRECT value");

    let url = format!("https://my.mlh.io/oauth/token?client_id={}&client_secret={}&code={}&redirect_uri={}&grant_type=authorization_code",
                      id, secret, code, redirect);

    let client = Client::new();
    let mut res = optry!(client.post(url.as_str())
        .header(Connection::close())
        .send().ok());

    let mut body = String::new();
    optry!(res.read_to_string(&mut body).ok());

    let token: TokenResp = optry!(json::decode(body.as_str()).ok());
    let url2 = format!("https://my.mlh.io/api/v1/user?access_token={}",
                       token.access_token);

    res = optry!(client.get(url2.as_str())
        .header(Connection::close())
        .send().ok());
    body = String::new();
    optry!(res.read_to_string(&mut body).ok());

    match json::decode(body.as_str()) {
        Ok(b) => Some(b),
        Err(_) => None,
    }
}

fn create_table(conn: PooledConnection<PostgresConnectionManager>) {
    let _r = conn.execute(
            "CREATE TABLE IF NOT EXISTS person (
                id SERIAL PRIMARY KEY,
                email VARCHAR NOT NULL,
                created_at VARCHAR NOT NULL,
                updated_at VARCHAR NOT NULL,
                first_name VARCHAR NOT NULL,
                last_name VARCHAR NOT NULL,
                graduation VARCHAR NOT NULL,
                major VARCHAR NOT NULL,
                shirt_size VARCHAR NOT NULL,
                dietary_restrictions VARCHAR NOT NULL,
                special_needs VARCHAR,
                date_of_birth VARCHAR NOT NULL,
                gender VARCHAR NOT NULL,
                phone_number VARCHAR NOT NULL,
                school_id integer,
                school_name VARCHAR
                )",
            &[]
        );
}

fn main() {
    let mut app = Nickel::new();

    let postgres_url = env::var("DATABASE")
        .expect("Failed to get DATABASE value");
    let dbpool = PostgresMiddleware::new(&*postgres_url, SslMode::None, 5,
                                         Box::new(NopErrorHandler))
        .expect("Failed to start PostgresMiddleware");

    create_table(dbpool.pool.clone().get().unwrap());
    app.utilize(dbpool);

    app.get("/callback", middleware! { |request, response|
        let conn = request.db_conn();
        let user_data = match request.query().get("code") {
            Some(s) => do_request(s),
            None => None
        }.unwrap().data;

        let r = conn.execute(
                "INSERT INTO person (id, email, created_at, updated_at,
                first_name, last_name, graduation, major, shirt_size,
                dietary_restrictions, special_needs, date_of_birth, gender,
                phone_number, school_id, school_name) VALUES ($1, $2, $3, $4,
                $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)",
                &[&user_data.id, &user_data.email, &user_data.created_at,
                  &user_data.updated_at, &user_data.first_name,
                  &user_data.last_name, &user_data.graduation, &user_data.major,
                  &user_data.shirt_size, &user_data.dietary_restrictions,
                  &user_data.special_needs, &user_data.date_of_birth,
                  &user_data.gender, &user_data.phone_number,
                  &user_data.school.id, &user_data.school.name]
            );
        match r {
            Ok(v) => println!("{:?}", v),
            Err(e) => println!("{:?}", e)
        }

        return response.redirect("http://hack.cwru.edu/register.html")
    });

    app.get("/start", middleware! { |_req, response|
        let id = env::var("ID").expect("Failed to get ID value");
        let redirect = env::var("REDIRECT")
            .expect("Failed to get REDIRECT value");
        return response.redirect(
            format!(
                    "http://my.mlh.io/oauth/authorize?client_id={}&redirect_uri={}&response_type=code",
                    id, redirect
                )
            );
    });

    let bind = match env::var("BIND") {
        Ok(v) => v,
        Err(_) => "127.0.0.1:8080".to_string(),
    };

    app.listen(bind.as_str());
}
<|endoftext|>


<commit_before>extern crate html5ever;
extern crate html5ever_dom_sink;
extern crate hyper;
extern crate rustc_serialize;
extern crate tempfile;
extern crate tendril;
extern crate url;

mod json;

use std::fs::OpenOptions;
use std::io::Read;
use std::io::Write;
use std::process::Command;
use std::process::Stdio;
use std::str::FromStr;

use html5ever::Attribute;
use html5ever::tree_builder::interface::TreeSink;
use html5ever_dom_sink::common::NodeEnum;
use html5ever_dom_sink::rcdom::Handle;
use html5ever_dom_sink::rcdom::RcDom;
use hyper::Client;
use hyper::header::Connection;
use rustc_serialize::json::Json;
use tempfile::NamedTempFile;
use url::percent_encoding;

use json::JsonPathElement::{Key, Only};

// TODO: there are some places where I've handrolled try!() equivalents. Fix those.
// TODO: make sure I'm returning Results everywhere, and propagating errors correctly.
// TODO: randomize placeholder per-request

// TODO: Can I get rid of the repeated "Zachary_Taylor"s everywhere? Surely the MediaWiki API doesn't actually need that - I can't imagine revision IDs aren't unique across all pages.

fn get_revisions(page: &str, limit: i32, properties: Vec<&str>, start_id: Option<u64>) -> String {
    let client = Client::new();
    let mut res = client.get(
        &format!(
            "https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles={}&rvprop={}&rvlimit={}{}&format=json",
            page, properties.join("|"), limit,
            match start_id { Some(id) => format!("&rvstartid={}", id), None => "".to_string()}))
        .header(Connection::close())
        .send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    body
}

// TODO: this name is terrible.
// Returns pairs of (revid, parentid)
fn get_revert_revision_ids(page: &str) -> Result<Vec<(u64, u64)>, String> {
    let json = Json::from_str(&get_revisions(page, 60, vec!["comment", "ids"], None)).unwrap();
    let revisions = try!(
        json::get_json_array(&json, &[Key("query"), Key("pages"), Only, Key("revisions")]));

    // Filter for revisions that mention vandalism, and that have revid and parentid (which they all
    // should, but merits checking).
    Ok(revisions.into_iter().filter(|revision| {
        match (json::get_json_string(revision, &[Key("comment")]),
               json::get_json_number(revision, &[Key("revid")]),
               json::get_json_number(revision, &[Key("parentid")])) {
            (Ok(ref comment), Ok(_), Ok(_)) => comment.contains("vandal"),
            _ => false,
        }})
       .map(|revision| {
           (json::get_json_number(revision, &[Key("revid")]).unwrap(),
            json::get_json_number(revision, &[Key("parentid")]).unwrap())
       }).collect())
}

fn get_latest_revision_id(page: &str) -> Result<u64, String> {
    let json = Json::from_str(&get_revisions(page, 1, vec!["ids"], None)).unwrap();
    json::get_json_number(
        &json, &[Key("query"), Key("pages"), Only, Key("revisions"), Only, Key("revid")])
}

fn get_revision_content(page: &str, id: u64) -> Result<String, String> {
    let json = Json::from_str(&get_revisions(page, 1, vec!["content"], Some(id))).unwrap();
    match json::get_json_string(
        &json, &[Key("query"), Key("pages"), Only, Key("revisions"), Only, Key("*")]) {
        Ok(content) => Ok(content.to_string()),
        Err(msg) => Err(msg),
    }
}

fn write_to_temp_file(contents: &str) -> NamedTempFile {
    let tempfile = NamedTempFile::new().unwrap();
    let mut file = OpenOptions::new().write(true).open(tempfile.path()).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
    file.flush().unwrap();
    tempfile
}

// TODO: I'm not so sure these parameter names aren't terrible.
fn merge(old: &str, new1: &str, new2: &str) -> Option<String> {
    let old_tempfile = write_to_temp_file(old);
    let new1_tempfile = write_to_temp_file(new1);
    let new2_tempfile = write_to_temp_file(new2);

    let mut process = Command::new("diff3");
    process.arg("-m").args(&[new1_tempfile.path(), old_tempfile.path(), new2_tempfile.path()])
        .stdout(Stdio::piped()).stderr(Stdio::null());
    let output = process.output().unwrap();
    if output.status.success() {
        Some(String::from_utf8(output.stdout).unwrap())
    } else {
        None
    }
}

fn render(wikitext: &str) -> Result<String, String> {
    let post_body = format!(
        "text={}", percent_encoding::percent_encode(
            wikitext.as_bytes(), percent_encoding::QUERY_ENCODE_SET));

    let client = Client::new();
    let mut res = client.post(
        "https://en.wikipedia.org/w/api.php?action=parse&format=json&prop=text&disablepp=&contentmodel=wikitext")
        .body(&post_body)
        .header(Connection::close())
        .send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    // TODO: check return value
    let json = Json::from_str(&body).unwrap();
    match json::get_json_string(&json, &[Key("parse"), Key("text"), Key("*")]) {
        Ok(contents) => Ok(contents.to_string()),
        Err(message) => Err(message),
    }
}

fn has_matching_id(attributes: &Vec<Attribute>, id: &str) -> bool {
    // TODO: could also do this with filter() and is_empty(). Not sure if that would be better.
    for attribute in attributes {
        // TODO: do I seriously have to construct a StrTendril here?
        // There has to be a better way.
        if attribute.name.local.as_slice() == "id" &&
            attribute.value == tendril::StrTendril::from_str(id).unwrap() {
                return true;
            }
    }
    return false;
}

fn find_node_by_id(handle: &Handle, id: &str) -> Result<Handle, String> {
    let node = handle.borrow();
    match node.node {
        NodeEnum::Element(_, ref attributes) if has_matching_id(attributes, id) => Ok(handle.clone()),
        _ => {
            for child in &node.children {
                match find_node_by_id(child, id) {
                    // TODO: this looks weird. Is this an abnormal way to do things?
                    Ok(node) => return Ok(node),
                    _ => continue,
                }
            }
            Err(format!("No node with ID {} found", id))
        },
    }
}

fn replace_node_with_placeholder(original_html: &str, div_id: &str, placeholder: &str) -> Result<String, String> {
    // TODO: check errors
    let html = tendril::StrTendril::from_str(original_html).unwrap();
    let mut dom: RcDom = html5ever::parse(html5ever::one_input(html), Default::default());

    let handle = try!(find_node_by_id(&dom.get_document(), div_id));
    let child_handles =
        (&handle.borrow().children).into_iter().map(|child| child.clone()).collect::<Vec<_>>();
    for child_handle in child_handles {
        dom.remove_from_parent(child_handle);
    }
    dom.append(handle,
               html5ever::tree_builder::interface::NodeOrText::AppendText(
                   tendril::StrTendril::from_str(placeholder).unwrap()));
    let mut serialized: Vec<u8> = vec![];
    html5ever::serialize::serialize(&mut serialized, &dom.document, Default::default());
    // TODO: error handling
    Ok(String::from_utf8(serialized).unwrap())
}

fn get_current_page(page: &str) -> String {
    let client = Client::new();
    let mut res = client.get(
        &format!("https://en.wikipedia.org/wiki/{}", page))
        .header(Connection::close())
        .send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    body
}

fn main() {
    let latest_revid = get_latest_revision_id("Zachary_Taylor").unwrap();
    let mut accumulated_contents = get_revision_content("Zachary_Taylor", latest_revid).unwrap();
    let mut revisions = vec![];
    for (revert_revid, vandalism_revid) in get_revert_revision_ids("Zachary_Taylor").ok().unwrap() {
        let reverted_contents = get_revision_content("Zachary_Taylor", revert_revid).unwrap();
        let vandalized_contents = get_revision_content("Zachary_Taylor", vandalism_revid).unwrap();
        match merge(&reverted_contents, &vandalized_contents, &accumulated_contents) {
            Some(merged_contents) => {
                accumulated_contents = merged_contents;
                revisions.push(revert_revid);
            }
            None => (),
        }
    }

    let rendered_body = render(&accumulated_contents).unwrap();
    let current_page_contents = get_current_page("Zachary_Taylor");
    let page_contents_with_placeholder =
        replace_node_with_placeholder(
            &current_page_contents, "mw-content-text", "WMW_PLACEHOLDER_TEXT").unwrap();
    let final_page_contents = page_contents_with_placeholder.replace("WMW_PLACEHOLDER_TEXT", &rendered_body);

    println!("Restored vandalisms reverted in: {:?}", revisions);
    println!("{}", final_page_contents);
}

#[cfg(test)]
mod tests {
    use super::{merge, replace_node_with_placeholder};

    #[test]
    fn test_merge_clean() {
        let old = "First line.\n\nSecond line.\n";
        let new1 = "First line.\n\nSecond line changed.\n";
        let new2 = "First line changed.\n\nSecond line.\n";
        assert_eq!("First line changed.\n\nSecond line changed.\n", merge(old, new1, new2).unwrap());
    }

    #[test]
    fn test_merge_conflicting() {
        let old = "First line.\n\nSecond line.\n";
        let new1 = "First line.\n\nSecond line changed one way.\n";
        let new2 = "First line changed.\n\nSecond line changed a different way.\n";
        assert_eq!(None, merge(old, new1, new2));
    }

    #[test]
    fn test_merge_special_characters() {
        let old = "First line.\n\nSecond line.\n";
        let new1 = "First line.\n\nSecond line 𐅃.\n";
        let new2 = "First line さようなら.\n\nSecond line.\n";
        assert_eq!("First line さようなら.\n\nSecond line 𐅃.\n", merge(old, new1, new2).unwrap());
    }

    #[test]
    fn test_replace_html_content() {
        let original_html = "

original text

Other text

";
        let expected_html = "

replaced text

Other text

";
        let processed_html = replace_node_with_placeholder(original_html, "mw-content-text", "replaced text").unwrap();
        assert_eq!(expected_html, processed_html);
    }
}
<commit_msg>Extract a parse_wikitext() function from parse().<commit_after>extern crate html5ever;
extern crate html5ever_dom_sink;
extern crate hyper;
extern crate rustc_serialize;
extern crate tempfile;
extern crate tendril;
extern crate url;

mod json;

use std::fs::OpenOptions;
use std::io::Read;
use std::io::Write;
use std::process::Command;
use std::process::Stdio;
use std::str::FromStr;

use html5ever::Attribute;
use html5ever::tree_builder::interface::TreeSink;
use html5ever_dom_sink::common::NodeEnum;
use html5ever_dom_sink::rcdom::Handle;
use html5ever_dom_sink::rcdom::RcDom;
use hyper::Client;
use hyper::header::Connection;
use rustc_serialize::json::Json;
use tempfile::NamedTempFile;
use url::percent_encoding;

use json::JsonPathElement::{Key, Only};

// TODO: there are some places where I've handrolled try!() equivalents. Fix those.
// TODO: make sure I'm returning Results everywhere, and propagating errors correctly.
// TODO: randomize placeholder per-request

// TODO: Can I get rid of the repeated "Zachary_Taylor"s everywhere? Surely the MediaWiki API doesn't actually need that - I can't imagine revision IDs aren't unique across all pages.

fn get_revisions(page: &str, limit: i32, properties: Vec<&str>, start_id: Option<u64>) -> String {
    let client = Client::new();
    let mut res = client.get(
        &format!(
            "https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles={}&rvprop={}&rvlimit={}{}&format=json",
            page, properties.join("|"), limit,
            match start_id { Some(id) => format!("&rvstartid={}", id), None => "".to_string()}))
        .header(Connection::close())
        .send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    body
}

fn parse_wikitext(wikitext: &str) -> String {
    let post_body = format!(
        "text={}", percent_encoding::percent_encode(
            wikitext.as_bytes(), percent_encoding::QUERY_ENCODE_SET));

    let client = Client::new();
    let mut res = client.post(
        "https://en.wikipedia.org/w/api.php?action=parse&format=json&prop=text&disablepp=&contentmodel=wikitext")
        .body(&post_body)
        .header(Connection::close())
        .send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    body
}

// TODO: this name is terrible.
// Returns pairs of (revid, parentid)
fn get_revert_revision_ids(page: &str) -> Result<Vec<(u64, u64)>, String> {
    let json = Json::from_str(&get_revisions(page, 60, vec!["comment", "ids"], None)).unwrap();
    let revisions = try!(
        json::get_json_array(&json, &[Key("query"), Key("pages"), Only, Key("revisions")]));

    // Filter for revisions that mention vandalism, and that have revid and parentid (which they all
    // should, but merits checking).
    Ok(revisions.into_iter().filter(|revision| {
        match (json::get_json_string(revision, &[Key("comment")]),
               json::get_json_number(revision, &[Key("revid")]),
               json::get_json_number(revision, &[Key("parentid")])) {
            (Ok(ref comment), Ok(_), Ok(_)) => comment.contains("vandal"),
            _ => false,
        }})
       .map(|revision| {
           (json::get_json_number(revision, &[Key("revid")]).unwrap(),
            json::get_json_number(revision, &[Key("parentid")]).unwrap())
       }).collect())
}

fn get_latest_revision_id(page: &str) -> Result<u64, String> {
    let json = Json::from_str(&get_revisions(page, 1, vec!["ids"], None)).unwrap();
    json::get_json_number(
        &json, &[Key("query"), Key("pages"), Only, Key("revisions"), Only, Key("revid")])
}

fn get_revision_content(page: &str, id: u64) -> Result<String, String> {
    let json = Json::from_str(&get_revisions(page, 1, vec!["content"], Some(id))).unwrap();
    match json::get_json_string(
        &json, &[Key("query"), Key("pages"), Only, Key("revisions"), Only, Key("*")]) {
        Ok(content) => Ok(content.to_string()),
        Err(msg) => Err(msg),
    }
}

fn write_to_temp_file(contents: &str) -> NamedTempFile {
    let tempfile = NamedTempFile::new().unwrap();
    let mut file = OpenOptions::new().write(true).open(tempfile.path()).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
    file.flush().unwrap();
    tempfile
}

// TODO: I'm not so sure these parameter names aren't terrible.
fn merge(old: &str, new1: &str, new2: &str) -> Option<String> {
    let old_tempfile = write_to_temp_file(old);
    let new1_tempfile = write_to_temp_file(new1);
    let new2_tempfile = write_to_temp_file(new2);

    let mut process = Command::new("diff3");
    process.arg("-m").args(&[new1_tempfile.path(), old_tempfile.path(), new2_tempfile.path()])
        .stdout(Stdio::piped()).stderr(Stdio::null());
    let output = process.output().unwrap();
    if output.status.success() {
        Some(String::from_utf8(output.stdout).unwrap())
    } else {
        None
    }
}

fn render(wikitext: &str) -> Result<String, String> {
    let html = parse_wikitext(wikitext);
    // TODO: check return value
    let json = Json::from_str(&html).unwrap();
    match json::get_json_string(&json, &[Key("parse"), Key("text"), Key("*")]) {
        Ok(contents) => Ok(contents.to_string()),
        Err(message) => Err(message),
    }
}

fn has_matching_id(attributes: &Vec<Attribute>, id: &str) -> bool {
    // TODO: could also do this with filter() and is_empty(). Not sure if that would be better.
    for attribute in attributes {
        // TODO: do I seriously have to construct a StrTendril here?
        // There has to be a better way.
        if attribute.name.local.as_slice() == "id" &&
            attribute.value == tendril::StrTendril::from_str(id).unwrap() {
                return true;
            }
    }
    return false;
}

fn find_node_by_id(handle: &Handle, id: &str) -> Result<Handle, String> {
    let node = handle.borrow();
    match node.node {
        NodeEnum::Element(_, ref attributes) if has_matching_id(attributes, id) => Ok(handle.clone()),
        _ => {
            for child in &node.children {
                match find_node_by_id(child, id) {
                    // TODO: this looks weird. Is this an abnormal way to do things?
                    Ok(node) => return Ok(node),
                    _ => continue,
                }
            }
            Err(format!("No node with ID {} found", id))
        },
    }
}

fn replace_node_with_placeholder(original_html: &str, div_id: &str, placeholder: &str) -> Result<String, String> {
    // TODO: check errors
    let html = tendril::StrTendril::from_str(original_html).unwrap();
    let mut dom: RcDom = html5ever::parse(html5ever::one_input(html), Default::default());

    let handle = try!(find_node_by_id(&dom.get_document(), div_id));
    let child_handles =
        (&handle.borrow().children).into_iter().map(|child| child.clone()).collect::<Vec<_>>();
    for child_handle in child_handles {
        dom.remove_from_parent(child_handle);
    }
    dom.append(handle,
               html5ever::tree_builder::interface::NodeOrText::AppendText(
                   tendril::StrTendril::from_str(placeholder).unwrap()));
    let mut serialized: Vec<u8> = vec![];
    html5ever::serialize::serialize(&mut serialized, &dom.document, Default::default());
    // TODO: error handling
    Ok(String::from_utf8(serialized).unwrap())
}

fn get_current_page(page: &str) -> String {
    let client = Client::new();
    let mut res = client.get(
        &format!("https://en.wikipedia.org/wiki/{}", page))
        .header(Connection::close())
        .send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    body
}

fn main() {
    let latest_revid = get_latest_revision_id("Zachary_Taylor").unwrap();
    let mut accumulated_contents = get_revision_content("Zachary_Taylor", latest_revid).unwrap();
    let mut revisions = vec![];
    for (revert_revid, vandalism_revid) in get_revert_revision_ids("Zachary_Taylor").ok().unwrap() {
        let reverted_contents = get_revision_content("Zachary_Taylor", revert_revid).unwrap();
        let vandalized_contents = get_revision_content("Zachary_Taylor", vandalism_revid).unwrap();
        match merge(&reverted_contents, &vandalized_contents, &accumulated_contents) {
            Some(merged_contents) => {
                accumulated_contents = merged_contents;
                revisions.push(revert_revid);
            }
            None => (),
        }
    }

    let rendered_body = render(&accumulated_contents).unwrap();
    let current_page_contents = get_current_page("Zachary_Taylor");
    let page_contents_with_placeholder =
        replace_node_with_placeholder(
            &current_page_contents, "mw-content-text", "WMW_PLACEHOLDER_TEXT").unwrap();
    let final_page_contents = page_contents_with_placeholder.replace("WMW_PLACEHOLDER_TEXT", &rendered_body);

    println!("Restored vandalisms reverted in: {:?}", revisions);
    println!("{}", final_page_contents);
}

#[cfg(test)]
mod tests {
    use super::{merge, replace_node_with_placeholder};

    #[test]
    fn test_merge_clean() {
        let old = "First line.\n\nSecond line.\n";
        let new1 = "First line.\n\nSecond line changed.\n";
        let new2 = "First line changed.\n\nSecond line.\n";
        assert_eq!("First line changed.\n\nSecond line changed.\n", merge(old, new1, new2).unwrap());
    }

    #[test]
    fn test_merge_conflicting() {
        let old = "First line.\n\nSecond line.\n";
        let new1 = "First line.\n\nSecond line changed one way.\n";
        let new2 = "First line changed.\n\nSecond line changed a different way.\n";
        assert_eq!(None, merge(old, new1, new2));
    }

    #[test]
    fn test_merge_special_characters() {
        let old = "First line.\n\nSecond line.\n";
        let new1 = "First line.\n\nSecond line 𐅃.\n";
        let new2 = "First line さようなら.\n\nSecond line.\n";
        assert_eq!("First line さようなら.\n\nSecond line 𐅃.\n", merge(old, new1, new2).unwrap());
    }

    #[test]
    fn test_replace_html_content() {
        let original_html = "

original text

Other text

";
        let expected_html = "

replaced text

Other text

";
        let processed_html = replace_node_with_placeholder(original_html, "mw-content-text", "replaced text").unwrap();
        assert_eq!(expected_html, processed_html);
    }
}
<|endoftext|>


<commit_before>//TODO(remove)
#![allow(dead_code)]
#![allow(unstable)]

use std::io;
use std::io::{File};
use std::time::duration::Duration;

use vm::Vm;

mod error;
mod ops;
mod vm;

fn main() {
    let mut vm = Vm::new();

    //let mut rom_file = File::open(&Path::new("/Users/jakerr/Downloads/IBM Logo.ch8")).unwrap();
     let mut rom_file = File::open(&Path::new("/Users/jakerr/Downloads/Chip8 Picture.ch8")).unwrap();
    // let mut rom_file = File::open(&Path::new("/Users/jakerr/Downloads/Fishie [Hap, 2005].ch8")).unwrap();
    // let mut rom_file = File::open(&Path::new("/Users/jakerr/Downloads/zerod.ch8.txt")).unwrap();
    // let mut rom_file = File::open(&Path::new("/Users/jakerr/Downloads/sierp.ch8")).unwrap();
    match vm.load_rom(&mut rom_file) {
        Ok(size) => println!("Loaded rom size: {}", size),
        Err(e) => println!("Error loading rom: {}", e)
    }

    let mut dump_file = File::create(&Path::new("/Users/jakerr/tmp/dump.ch8ram")).unwrap();
    vm.dump_ram(&mut dump_file);

    loop {
        if vm.step() { break; }
        // io::timer::sleep(Duration::milliseconds(80));
        // vm.print_screen();
    }
    io::timer::sleep(Duration::milliseconds(300));
    vm.print_screen();
    //vm.print_disassembly();
}
<commit_msg>Temporary easy rom switching with an array of hardcoded roms<commit_after>//TODO(remove)
#![allow(dead_code)]
#![allow(unstable)]

use std::io;
use std::io::{File};
use std::time::duration::Duration;

use vm::Vm;

mod error;
mod ops;
mod vm;

fn main() {
    let mut vm = Vm::new();

    let roms = [
        "IBM Logo.ch8",           // 0
        "Chip8 Picture.ch8",      // 1
        "Fishie [Hap, 2005].ch8", // 2
        "zerod.ch8",              // 3
        "sierp.ch8",              // 4
    ];
    let rom_path = Path::new(format!("/Users/jakerr/Downloads/{}", roms[2]));

    let mut rom_file = File::open(&rom_path).unwrap();

    match vm.load_rom(&mut rom_file) {
        Ok(size) => println!("Loaded rom size: {}", size),
        Err(e) => println!("Error loading rom: {}", e)
    }

    let mut dump_file = File::create(&Path::new("/Users/jakerr/tmp/dump.ch8ram")).unwrap();
    vm.dump_ram(&mut dump_file);

    loop {
        if vm.step() { break; }
        // io::timer::sleep(Duration::milliseconds(80));
        // vm.print_screen();
    }
    io::timer::sleep(Duration::milliseconds(300));
    vm.print_screen();
    //vm.print_disassembly();
}
<|endoftext|>


<commit_before>extern crate rayon;

use rayon::prelude::*;

use std::process::Command;
use std::fs::File;
use std::io::Write;
use std::os::raw;
use std::io::Read;

pub mod descriptions;

use descriptions::*;

#[cfg(target_os="windows")]
const VASM_EXE: &'static str = "bin/win/vasmm68k_mot.exe";

#[cfg(target_os="macos")]
const VASM_EXE: &'static str = "bin/mac/vasmm68k_mot";

#[cfg(any(target_os="linux",
          target_os="freebsd",
          target_os="dragonfly",
          target_os="netbsd",
          target_os="openbsd"))]
const VASM_EXE: &'static str = "vasmm68k_mot";

#[derive(PartialEq, Clone, Copy)]
enum Ea {
    Any,
    Immidate,
    DataRegister,
    AddressRegister,
    Memory,
}

#[derive(PartialEq, Copy, Clone)]
enum Size {
    _Byte,
    Word,
    Long,
}

struct BuildResult {
    src: Option<Op>,
    dst: Op,
    temp_file: String,
    temp_out: String,
    cycle_count: Option<usize>,
}

#[derive(Copy, Clone)]
struct Op {
    name: &'static str,
    print_name: &'static str,
    count: usize,
    ea_type: Ea,
}

impl Op {
    fn new(name: &'static str, print_name: &'static str, count: usize, ea_type: Ea) -> Op {
        Op {
            name: name,
            print_name: print_name,
            count: count,
            ea_type: ea_type,
        }
    }
}
struct Instruction {
    name: &'static str,
    _desc: Option<Description>,
}

fn compile_statement(filename: &str, file_out: &str, statement: &str) -> bool {
    {
        let mut file = File::create(filename).unwrap();
        write!(file, " {}", statement).unwrap();
    }

    let output = Command::new(VASM_EXE)
        .arg(filename)
        .arg("-Fbin")
        .arg("-o")
        .arg(file_out)
        .output()
        .expect("failed to execute process");

    output.status.success()
}

fn print_grid_table(name: &str, cycles: &Vec<BuildResult>, src_table: &[Op], dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    for src in src_table {
        let mut skip_count = 0;

        for i in index..index + 9 {
            if let None = cycles[i].cycle_count {
                skip_count += 1;
            }
        }

        if skip_count != 9 {
            print!("| {name:<width$}", name = src.print_name, width = 9);

            for dest in dest_table {
                if let Some(cycle_count) = cycles[index].cycle_count {
                    print!("|{number:^width$}",
                           number = cycle_count,
                           width = dest.print_name.len() + 2);
                } else {
                    print!("|{number:^width$}",
                           number = "*",
                           width = dest.print_name.len() + 2);
                }
                index += 1;
            }

            println!("|");
        } else {
            index += 9;
        }
    }

    println!("");
}

fn print_table(name: &str, cycles: &Vec<BuildResult>, dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    print!("| {name:<width$}", name = " ", width = 9);

    for dest in dest_table {
        if let Some(cycle_count) = cycles[index].cycle_count {
            print!("|{number:^width$}",
                   number = cycle_count,
                   width = dest.print_name.len() + 2);
        } else {
            print!("|{number:^width$}",
                   number = "*",
                   width = dest.print_name.len() + 2);
        }
        index += 1;
    }

    println!("|");
    println!("");
}

fn print_instruction_header(inst: &Instruction) {
    let name = inst.name.to_uppercase();
    println!("## {}\n", name);
    if let Some(ref desc) = inst._desc {
        println!("**Operation:**      {}\n", desc.operation);

        print!("**Assembler:** ");
        for assem in desc.assembler {
            print!("{}        ", assem);
        }
        println!("\n\n**Attributes:** Size = ({})\n", desc.attributes);

        println!("**Description:** {}\n", desc.description);
    }
    else {
        println!("__No Description__\n");
    }
}

fn compile_cycle_counts(statements: &mut Vec<BuildResult>) {
    let mut instructions = Vec::new();
    let mut inst_count = 0u32;
    let mut cycle_count = Vec::<u32>::new();

    for statement in statements.iter() {
        if statement.cycle_count.is_some() {
            {
                let mut f = File::open(&statement.temp_out).unwrap();
                f.read_to_end(&mut instructions).unwrap();
                cycle_count.push(0);
                inst_count += 1;
            }
        }
    }

    unsafe {
        m68k_run_instructions(instructions.as_ptr() as *const raw::c_void, inst_count, cycle_count.as_mut_ptr());
    }

    inst_count = 0;

    for statement in statements.iter_mut() {
        if statement.cycle_count.is_some() {
            statement.cycle_count = Some(cycle_count[inst_count as usize] as usize);
            inst_count += 1;
        }
    }
}

fn generate_table(inst: &Instruction,
                  name: &str,
                  size: Size,
                  src_table: Option<&[Op]>,
                  dest_table: &[Op]) {
    let mut statements = Vec::with_capacity(20 * 20);
    let mut count = 0;

    if let Some(src_opts) = src_table {
        for src in src_opts {
            for dst in dest_table {
                let file_in = format!("target/temp_{}.s", count);
                let file_out = format!("target/temp_{}.o", count);

                statements.push(BuildResult {
                    src: Some(src.clone()),
                    dst: dst.clone(),
                    temp_file: file_in,
                    temp_out: file_out,
                    cycle_count: None,
                });

                count += 1;
            }
        }

        statements.par_iter_mut().weight_max().for_each(|v| {
            let statement = format!("{} {},{}", name, v.src.unwrap().name, v.dst.name);
            if compile_statement(&v.temp_file, &v.temp_out, &statement) {
                v.cycle_count = Some(0); // indicate that this should be processed
            }
        });

        compile_cycle_counts(&mut statements);

        print_grid_table(name, &statements, &src_opts, dest_table);
    } else {
        for dst in dest_table {
            let file_in = format!("target/temp_{}.s", count);
            let file_out = format!("target/temp_{}.o", count);

            statements.push(BuildResult {
                src: None,
                dst: dst.clone(),
                temp_file: file_in,
                temp_out: file_out,
                cycle_count: None,
            });

            count += 1;
        }

        statements.par_iter_mut().weight_max().for_each(|v| {
            let statement = format!("{} {}", name, v.dst.name);
            if compile_statement(&v.temp_file, &v.temp_out, &statement) {
                v.cycle_count = Some(0);
            }
        });

        compile_cycle_counts(&mut statements);

        print_table(name, &statements, dest_table);
    }
}

fn main() {
    let dest_types = [Op::new("d0", "Dn", 0, Ea::DataRegister),
    Op::new("a0", "An", 0, Ea::AddressRegister),
    Op::new("(a0)", "(An)", 4, Ea::Memory),
    Op::new("(a0)+", "(An)+", 4, Ea::Memory),
    Op::new("-(a0)", "-(An)", 6, Ea::Memory),
    Op::new("2(a0)", "d(An)", 8, Ea::Memory),
    Op::new("2(a0,d0)", "d(An,Dn)", 10, Ea::Memory),
    Op::new("$4.W", "xxx.W", 8, Ea::Memory),
    Op::new("$4.L", "xxx.L", 12, Ea::Memory)];

    let src_types = [Op::new("d0", "Dn", 0, Ea::DataRegister),
    Op::new("a0", "An", 0, Ea::AddressRegister),
    Op::new("(a0)", "(An)", 4, Ea::Memory),
    Op::new("(a0)+", "(An)+", 4, Ea::Memory),
    Op::new("-(a0)", "-(An)", 6, Ea::Memory),
    Op::new("2(a0)", "d(An)", 8, Ea::Memory),
    Op::new("2(a0,d0)", "d(An,Dn)", 10, Ea::Memory),
    Op::new("$4.W", "xxx.W", 8, Ea::Memory),
    Op::new("$4.L", "xxx.L", 12, Ea::Memory),
    Op::new("2(pc)", "d(PC)", 8, Ea::Memory),
    Op::new("2(pc,d0)", "d(PC,Dn)", 10, Ea::Memory),
    Op::new("#2", "#xxx", 4, Ea::Immidate)];

    let dest_types_none = [Op::new("", "", 0, Ea::Immidate)];

    unsafe {
        m68k_wrapper_init();
    }

    let inst_2_ops_000 =
        [
        Instruction {
            name: "abcd",
            _desc: Some(ABCD_DESC),
        },

        Instruction {
            name: "add",
            _desc: Some(ADD_DESC),
        },
        Instruction {
            name: "addq",
            _desc: Some(ADDQ_DESC),
        },
        Instruction {
            name: "addx",
            _desc: Some(ADDX_DESC),
        },
        Instruction {
            name: "and",
            _desc: Some(AND_DESC),
        },
        Instruction {
            name: "bchg",
            _desc: Some(BCHG_DESC),
        },
        Instruction {
            name: "bclr",
            _desc: Some(BCLR_DESC),
        },
        Instruction {
            name: "bset",
            _desc: Some(BSET_DESC),
        },
        Instruction {
            name: "btst",
            _desc: Some(BTST_DESC),
        },
        Instruction {
            name: "cmp",
            _desc: Some(CMP_DESC),
        },
        Instruction {
            name: "divu",
            _desc: Some(DIVS_DIVU_DESC),
        },
        Instruction {
            name: "divs",
            _desc: Some(DIVS_DIVU_DESC),
        },
        Instruction {
            name: "eor",
            _desc: Some(EOR_DESC),
        },
        Instruction {
            name: "exg",
            _desc: Some(EXG_DESC),
        },
        Instruction {
            name: "lea",
            _desc: Some(LEA_DESC),
        },
        Instruction {
            name: "move",
            _desc: Some(MOVE_DESC),
        },
        Instruction {
            name: "muls",
            _desc: Some(MULS_DESC),
        },
        Instruction {
            name: "mulu",
            _desc: Some(MULU_DESC),
        },
        Instruction {
            name: "or",
            _desc: Some(OR_DESC),
        },
        Instruction {
            name: "sub",
            _desc: Some(SUB_DESC),
        },
        Instruction {
            name: "subq",
            _desc: Some(SUBQ_DESC),
        },
        Instruction {
            name: "subx",
            _desc: Some(SUBX_DESC),
        },
        ];

    let inst_1_ops_000 = [
        Instruction {
            name: "clr",
            _desc: Some(CLR_DESC),
        },
        Instruction {
            name: "ext",
            _desc: Some(EXT_DESC),
        },
        Instruction {
            name: "bsr",
            _desc: Some(BSR_DESC),
        },
        Instruction {
            name: "jsr",
            _desc: Some(JSR_DESC),
        },
        Instruction {
            name: "jmp",
            _desc: Some(JMP_DESC),
        },
        Instruction {
            name: "neg",
            _desc: Some(NEG_DESC),
        },
        Instruction {
            name: "not",
            _desc: Some(NOT_DESC),
        },
        Instruction {
            name: "swap",
            _desc: Some(SWAP_DESC),
        },
        ];

    let inst_0_ops_000 = [
        Instruction {
            name: "nop",
            _desc: Some(NOP_DESC),
        },
        Instruction {
            name: "illegal",
            _desc: None,
        },
        Instruction {
            name: "rte",
            _desc: Some(RTS_DESC),
        },
        Instruction {
            name: "rts",
            _desc: Some(RTS_DESC),
        },
    ];

    for inst in &inst_2_ops_000 {
        let name_long = format!("{}.l", inst.name);

        print_instruction_header(inst);
        generate_table(&inst, inst.name, Size::Word, Some(&src_types), &dest_types);
        generate_table(&inst, &name_long, Size::Long, Some(&src_types), &dest_types);
    }

    // Generate instructions with one op

    for inst in &inst_1_ops_000 {
        let name_long = format!("{}.l", inst.name);

        print_instruction_header(inst);
        generate_table(&inst, inst.name, Size::Word, None, &dest_types);
        generate_table(&inst, &name_long, Size::Long, None, &dest_types);
    }

    // Generate instructions with no ops

    for inst in &inst_0_ops_000 {
        let name_long = format!("{}.l", inst.name);

        print_instruction_header(inst);
        generate_table(&inst, inst.name, Size::Word, None, &dest_types_none);
        generate_table(&inst, &name_long, Size::Long, None, &dest_types_none);
    }
}

extern "C" {
    fn m68k_wrapper_init();
    fn m68k_run_instructions(instructions: *const raw::c_void, count: u32, cycle_res: *mut u32);
}

<commit_msg>Cleanup<commit_after>extern crate rayon;

use rayon::prelude::*;

use std::process::Command;
use std::fs::File;
use std::io::Write;
use std::os::raw;
use std::io::Read;

pub mod descriptions;

use descriptions::*;

#[cfg(target_os="windows")]
const VASM_EXE: &'static str = "bin/win/vasmm68k_mot.exe";

#[cfg(target_os="macos")]
const VASM_EXE: &'static str = "bin/mac/vasmm68k_mot";

#[cfg(any(target_os="linux",
          target_os="freebsd",
          target_os="dragonfly",
          target_os="netbsd",
          target_os="openbsd"))]
const VASM_EXE: &'static str = "vasmm68k_mot";

struct BuildResult {
    src: Option<Op>,
    dst: Op,
    temp_file: String,
    temp_out: String,
    cycle_count: Option<usize>,
}

#[derive(Copy, Clone)]
struct Op {
    name: &'static str,
    print_name: &'static str,
}

impl Op {
    fn new(name: &'static str, print_name: &'static str) -> Op {
        Op {
            name: name,
            print_name: print_name,
        }
    }
}
struct Instruction {
    name: &'static str,
    _desc: Option<Description>,
}

fn compile_statement(filename: &str, file_out: &str, statement: &str) -> bool {
    {
        let mut file = File::create(filename).unwrap();
        write!(file, " {}", statement).unwrap();
    }

    let output = Command::new(VASM_EXE)
        .arg(filename)
        .arg("-Fbin")
        .arg("-o")
        .arg(file_out)
        .output()
        .expect("failed to execute process");

    output.status.success()
}

fn print_grid_table(name: &str, cycles: &Vec<BuildResult>, src_table: &[Op], dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    for src in src_table {
        let mut skip_count = 0;

        for i in index..index + 9 {
            if let None = cycles[i].cycle_count {
                skip_count += 1;
            }
        }

        if skip_count != 9 {
            print!("| {name:<width$}", name = src.print_name, width = 9);

            for dest in dest_table {
                if let Some(cycle_count) = cycles[index].cycle_count {
                    print!("|{number:^width$}",
                           number = cycle_count,
                           width = dest.print_name.len() + 2);
                } else {
                    print!("|{number:^width$}",
                           number = "*",
                           width = dest.print_name.len() + 2);
                }
                index += 1;
            }

            println!("|");
        } else {
            index += 9;
        }
    }

    println!("");
}

fn print_table(name: &str, cycles: &Vec<BuildResult>, dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    print!("| {name:<width$}", name = " ", width = 9);

    for dest in dest_table {
        if let Some(cycle_count) = cycles[index].cycle_count {
            print!("|{number:^width$}",
                   number = cycle_count,
                   width = dest.print_name.len() + 2);
        } else {
            print!("|{number:^width$}",
                   number = "*",
                   width = dest.print_name.len() + 2);
        }
        index += 1;
    }

    println!("|");
    println!("");
}

fn print_instruction_header(inst: &Instruction) {
    let name = inst.name.to_uppercase();
    println!("## {}\n", name);
    if let Some(ref desc) = inst._desc {
        println!("**Operation:**      {}\n", desc.operation);

        print!("**Assembler:** ");
        for assem in desc.assembler {
            print!("{}        ", assem);
        }
        println!("\n\n**Attributes:** Size = ({})\n", desc.attributes);

        println!("**Description:** {}\n", desc.description);
    }
    else {
        println!("__No Description__\n");
    }
}

fn compile_cycle_counts(statements: &mut Vec<BuildResult>) {
    let mut instructions = Vec::new();
    let mut inst_count = 0u32;
    let mut cycle_count = Vec::<u32>::new();

    for statement in statements.iter() {
        if statement.cycle_count.is_some() {
            {
                let mut f = File::open(&statement.temp_out).unwrap();
                f.read_to_end(&mut instructions).unwrap();
                cycle_count.push(0);
                inst_count += 1;
            }
        }
    }

    unsafe {
        m68k_run_instructions(instructions.as_ptr() as *const raw::c_void, inst_count, cycle_count.as_mut_ptr());
    }

    inst_count = 0;

    for statement in statements.iter_mut() {
        if statement.cycle_count.is_some() {
            statement.cycle_count = Some(cycle_count[inst_count as usize] as usize);
            inst_count += 1;
        }
    }
}

fn generate_table(name: &str,
                  src_table: Option<&[Op]>,
                  dest_table: &[Op]) {
    let mut statements = Vec::with_capacity(20 * 20);
    let mut count = 0;

    if let Some(src_opts) = src_table {
        for src in src_opts {
            for dst in dest_table {
                let file_in = format!("target/temp_{}.s", count);
                let file_out = format!("target/temp_{}.o", count);

                statements.push(BuildResult {
                    src: Some(src.clone()),
                    dst: dst.clone(),
                    temp_file: file_in,
                    temp_out: file_out,
                    cycle_count: None,
                });

                count += 1;
            }
        }

        statements.par_iter_mut().weight_max().for_each(|v| {
            let statement = format!("{} {},{}", name, v.src.unwrap().name, v.dst.name);
            if compile_statement(&v.temp_file, &v.temp_out, &statement) {
                v.cycle_count = Some(0); // indicate that this should be processed
            }
        });

        compile_cycle_counts(&mut statements);

        print_grid_table(name, &statements, &src_opts, dest_table);
    } else {
        for dst in dest_table {
            let file_in = format!("target/temp_{}.s", count);
            let file_out = format!("target/temp_{}.o", count);

            statements.push(BuildResult {
                src: None,
                dst: dst.clone(),
                temp_file: file_in,
                temp_out: file_out,
                cycle_count: None,
            });

            count += 1;
        }

        statements.par_iter_mut().weight_max().for_each(|v| {
            let statement = format!("{} {}", name, v.dst.name);
            if compile_statement(&v.temp_file, &v.temp_out, &statement) {
                v.cycle_count = Some(0);
            }
        });

        compile_cycle_counts(&mut statements);

        print_table(name, &statements, dest_table);
    }
}

fn main() {
    let dest_types = [
        Op::new("d0", "Dn"),
        Op::new("a0", "An"),
        Op::new("(a0)", "(An)"),
        Op::new("(a0)+", "(An)+"),
        Op::new("-(a0)", "-(An)"),
        Op::new("2(a0)", "d(An)"),
        Op::new("2(a0,d0)", "d(An,Dn)"),
        Op::new("$4.W", "xxx.W"),
        Op::new("$4.L", "xxx.L")];

    let src_types = [
        Op::new("d0", "Dn"),
        Op::new("a0", "An"),
        Op::new("(a0)", "(An)"),
        Op::new("(a0)+", "(An)+"),
        Op::new("-(a0)", "-(An)"),
        Op::new("2(a0)", "d(An)"),
        Op::new("2(a0,d0)", "d(An,Dn)"),
        Op::new("$4.W", "xxx.W"),
        Op::new("$4.L", "xxx.L"),
        Op::new("2(pc)", "d(PC)"),
        Op::new("2(pc,d0)", "d(PC,Dn)"),
        Op::new("#2", "#xxx")];

    let dest_types_none = [Op::new("", "")];

    unsafe {
        m68k_wrapper_init();
    }

    let inst_2_ops_000 =
        [
        Instruction {
            name: "abcd",
            _desc: Some(ABCD_DESC),
        },

        Instruction {
            name: "add",
            _desc: Some(ADD_DESC),
        },
        Instruction {
            name: "addq",
            _desc: Some(ADDQ_DESC),
        },
        Instruction {
            name: "addx",
            _desc: Some(ADDX_DESC),
        },
        Instruction {
            name: "and",
            _desc: Some(AND_DESC),
        },
        Instruction {
            name: "bchg",
            _desc: Some(BCHG_DESC),
        },
        Instruction {
            name: "bclr",
            _desc: Some(BCLR_DESC),
        },
        Instruction {
            name: "bset",
            _desc: Some(BSET_DESC),
        },
        Instruction {
            name: "btst",
            _desc: Some(BTST_DESC),
        },
        Instruction {
            name: "cmp",
            _desc: Some(CMP_DESC),
        },
        Instruction {
            name: "divu",
            _desc: Some(DIVS_DIVU_DESC),
        },
        Instruction {
            name: "divs",
            _desc: Some(DIVS_DIVU_DESC),
        },
        Instruction {
            name: "eor",
            _desc: Some(EOR_DESC),
        },
        Instruction {
            name: "exg",
            _desc: Some(EXG_DESC),
        },
        Instruction {
            name: "lea",
            _desc: Some(LEA_DESC),
        },
        Instruction {
            name: "move",
            _desc: Some(MOVE_DESC),
        },
        Instruction {
            name: "muls",
            _desc: Some(MULS_DESC),
        },
        Instruction {
            name: "mulu",
            _desc: Some(MULU_DESC),
        },
        Instruction {
            name: "or",
            _desc: Some(OR_DESC),
        },
        Instruction {
            name: "sub",
            _desc: Some(SUB_DESC),
        },
        Instruction {
            name: "subq",
            _desc: Some(SUBQ_DESC),
        },
        Instruction {
            name: "subx",
            _desc: Some(SUBX_DESC),
        },
        ];

    let inst_1_ops_000 = [
        Instruction {
            name: "clr",
            _desc: Some(CLR_DESC),
        },
        Instruction {
            name: "ext",
            _desc: Some(EXT_DESC),
        },
        Instruction {
            name: "bsr",
            _desc: Some(BSR_DESC),
        },
        Instruction {
            name: "jsr",
            _desc: Some(JSR_DESC),
        },
        Instruction {
            name: "jmp",
            _desc: Some(JMP_DESC),
        },
        Instruction {
            name: "neg",
            _desc: Some(NEG_DESC),
        },
        Instruction {
            name: "not",
            _desc: Some(NOT_DESC),
        },
        Instruction {
            name: "swap",
            _desc: Some(SWAP_DESC),
        },
        ];

    let inst_0_ops_000 = [
        Instruction {
            name: "nop",
            _desc: Some(NOP_DESC),
        },
        Instruction {
            name: "illegal",
            _desc: None,
        },
        Instruction {
            name: "rte",
            _desc: Some(RTS_DESC),
        },
        Instruction {
            name: "rts",
            _desc: Some(RTS_DESC),
        },
    ];

    for inst in &inst_2_ops_000 {
        let name_long = format!("{}.l", inst.name);

        print_instruction_header(inst);
        generate_table(inst.name, Some(&src_types), &dest_types);
        generate_table(&name_long, Some(&src_types), &dest_types);
    }

    // Generate instructions with one op

    for inst in &inst_1_ops_000 {
        let name_long = format!("{}.l", inst.name);

        print_instruction_header(inst);
        generate_table(inst.name, None, &dest_types);
        generate_table(&name_long, None, &dest_types);
    }

    //

    // Generate instructions with no ops

    for inst in &inst_0_ops_000 {
        let name_long = format!("{}.l", inst.name);

        print_instruction_header(inst);
        generate_table(inst.name, None, &dest_types_none);
        generate_table(&name_long, None, &dest_types_none);
    }
}

extern "C" {
    fn m68k_wrapper_init();
    fn m68k_run_instructions(instructions: *const raw::c_void, count: u32, cycle_res: *mut u32);
}

<|endoftext|>