<commit_before>extern crate getopts;
extern crate izzet;
extern crate toml;

use getopts::{Matches, Options};
use izzet::error::{Error, Result};
use izzet::post;
use izzet::gen;
use izzet::get_opener;
use izzet::config::Config;
use std::env;
use std::fs::DirBuilder;
use std::path::PathBuf;
use std::process;
use std::io::Write;

const PROG_NAME: &str = env!("CARGO_PKG_NAME");

fn create_site(m: &Matches) -> Result<()> {
    let dir = m.free.get(1)
        .map(|s| PathBuf::from(s))
        .unwrap_or(env::current_dir()?);

    let opener = get_opener(m.opt_present("force"));

    for filename in izzet::SITE_FILES {
        opener.open(dir.join(filename))
              .map_err(|e| format!("fail to create {}: {}", filename, e))?;
    }

    for dirname in izzet::SITE_DIRS {
        DirBuilder::new()
            .recursive(m.opt_present("force"))
            .create(dir.join(dirname))
            .map_err(|e| format!("fail to create {}: {}", dirname, e))?;
    }

    for &(filename, html) in izzet::SITE_TEMPLATES {
        let mut file = opener.open(dir.join(izzet::TEMPLATES_DIR)
                                      .join(filename))
                             .map_err(|e| format!("fail to create {}: {}", filename, e))?;
        file.write(html)?;
    }

    Ok(())
}

fn usage(opts: &Options) {
    println!("{}", opts.usage(&format!("usage: {} <options> <args>", PROG_NAME)));
}

fn run(m: Matches) -> Result<()> {
    // Note that now we have no configuration file yet
    if m.opt_present("new") {
        create_site(&m)?;
        return Ok(());
    }

    // Load config file as a basis which may be overwritten
    // later by the command-line options.
    let mut config = Config::from_file(m.opt_str("config")
                                        .map(|p| PathBuf::from(p))
                                        .unwrap_or(env::current_dir()?)
                                        .join(izzet::CONFIG_FILE))?;

    config.force = Some(m.opt_present("force"));

    if m.opt_present("article") || m.opt_present("page") {
        let link = m.free.get(1)
            .ok_or(Error::new("fail to get the link of article".to_string()))?;
        post::create_post(link.clone(), config, m.opt_present("article"))?;
    }
    else if m.opt_present("gen") {
        config.in_dir = m.opt_str("input");
        config.out_dir = m.opt_str("output");
        gen::generate(config)?;
    }

    Ok(())
}

fn main() {
    let mut opts = Options::new();

    // One of these flags should be specified
    opts.optflag("n", "new", "Initialize an empty site at the given location.");
    opts.optflag("a", "article", "Create an article with the given permalink.");
    opts.optflag("p", "page", "Create a page with the given permalink.");
    opts.optflag("g", "gen", "Generate site, can be used along with -i and -o \
                              to specify the input and output location.");
    opts.optflag("f", "force", "Overwrite existing files when creating articles, \
                                generating site output files, etc.");

    opts.optopt("c", "config", "Run with the given configuration file. By default \
                                configuration file will be looked for under the \
                                current directory.", "CONFIG");
    opts.optopt("i", "input", "Input site directory. Read input files from current \
                              directory by default.", "INPUT");
    opts.optopt("o", "output", "Output site directory. Write to current directory \
                               by default.", "OUTPUT");

    opts.optflag("h", "help", "Show this help message.");
    opts.optflag("V", "version", "Display version information.");

    let matches = match opts.parse(env::args()) {
        Ok(m) => m,
        Err(e) => {
            eprintln!("{}\ntry `{1} -h` or `{1} --help` to see the help.", e, PROG_NAME);
            process::exit(1);
        },
    };

    if matches.opt_present("help") {
        usage(&opts);
        return;
    }

    if matches.opt_present("version") {
        println!("{} {}", PROG_NAME, env!("CARGO_PKG_VERSION"));
        return;
    }

    if !matches.opt_present("new")
        && !matches.opt_present("article")
        && !matches.opt_present("page")
        && !matches.opt_present("gen") {
        println!("nothing to do.");
        process::exit(1);
    }

    let mutex_opts = ["new", "article", "gen", "page"];
    if mutex_opts.iter()
        .map(|o| matches.opt_present(o) as u32)
        .sum::<u32>() != 1 {
        eprintln!("only one of `-n', `-a' and `-g' could be specified");
        process::exit(1);
    }

    if let Err(e) = run(matches) {
        eprintln!("{}", e);
        process::exit(1);
    }
}
<commit_msg>Check mutex options with pattern matching<commit_after>extern crate getopts;
extern crate izzet;
extern crate toml;

use getopts::{Matches, Options};
use izzet::error::{Error, Result};
use izzet::post;
use izzet::gen;
use izzet::get_opener;
use izzet::config::Config;
use std::env;
use std::fs::DirBuilder;
use std::path::PathBuf;
use std::process;
use std::io::Write;

const PROG_NAME: &str = env!("CARGO_PKG_NAME");

fn create_site(m: &Matches) -> Result<()> {
    let dir = m.free.get(1)
        .map(|s| PathBuf::from(s))
        .unwrap_or(env::current_dir()?);

    let opener = get_opener(m.opt_present("force"));

    for filename in izzet::SITE_FILES {
        opener.open(dir.join(filename))
              .map_err(|e| format!("fail to create {}: {}", filename, e))?;
    }

    for dirname in izzet::SITE_DIRS {
        DirBuilder::new()
            .recursive(m.opt_present("force"))
            .create(dir.join(dirname))
            .map_err(|e| format!("fail to create {}: {}", dirname, e))?;
    }

    for &(filename, html) in izzet::SITE_TEMPLATES {
        let mut file = opener.open(dir.join(izzet::TEMPLATES_DIR)
                                      .join(filename))
                             .map_err(|e| format!("fail to create {}: {}", filename, e))?;
        file.write(html)?;
    }

    Ok(())
}

fn usage(opts: &Options) {
    println!("{}", opts.usage(&format!("usage: {} <options> <args>", PROG_NAME)));
}

fn run(m: Matches) -> Result<()> {
    // Note that now we have no configuration file yet
    if m.opt_present("new") {
        create_site(&m)?;
        return Ok(());
    }

    // Load config file as a basis which may be overwritten
    // later by the command-line options.
    let mut config = Config::from_file(m.opt_str("config")
                                        .map(|p| PathBuf::from(p))
                                        .unwrap_or(env::current_dir()?)
                                        .join(izzet::CONFIG_FILE))?;

    config.force = Some(m.opt_present("force"));

    if m.opt_present("article") || m.opt_present("page") {
        let link = m.free.get(1)
            .ok_or(Error::new("fail to get the link of article".to_string()))?;
        post::create_post(link.clone(), config, m.opt_present("article"))?;
    }
    else if m.opt_present("gen") {
        config.in_dir = m.opt_str("input");
        config.out_dir = m.opt_str("output");
        gen::generate(config)?;
    }

    Ok(())
}

fn main() {
    let mut opts = Options::new();

    // One of these flags should be specified
    opts.optflag("n", "new", "Initialize an empty site at the given location.");
    opts.optflag("a", "article", "Create an article with the given permalink.");
    opts.optflag("p", "page", "Create a page with the given permalink.");
    opts.optflag("g", "gen", "Generate site, can be used along with -i and -o \
                              to specify the input and output location.");
    opts.optflag("f", "force", "Overwrite existing files when creating articles, \
                                generating site output files, etc.");

    opts.optopt("c", "config", "Run with the given configuration file. By default \
                                configuration file will be looked for under the \
                                current directory.", "CONFIG");
    opts.optopt("i", "input", "Input site directory. Read input files from current \
                              directory by default.", "INPUT");
    opts.optopt("o", "output", "Output site directory. Write to current directory \
                               by default.", "OUTPUT");

    opts.optflag("h", "help", "Show this help message.");
    opts.optflag("V", "version", "Display version information.");

    let matches = match opts.parse(env::args()) {
        Ok(m) => m,
        Err(e) => {
            eprintln!("{}\ntry `{1} -h` or `{1} --help` to see the help.", e, PROG_NAME);
            process::exit(1);
        },
    };

    if matches.opt_present("help") {
        usage(&opts);
        return;
    }

    if matches.opt_present("version") {
        println!("{} {}", PROG_NAME, env!("CARGO_PKG_VERSION"));
        return;
    }

    if !matches.opt_present("new")
        && !matches.opt_present("article")
        && !matches.opt_present("page")
        && !matches.opt_present("gen") {
        println!("nothing to do.");
        process::exit(1);
    }

    let mutex_opts = ["new", "article", "gen", "page"];

    match mutex_opts.iter()
                    .map(|o| matches.opt_present(o) as u32)
                    .sum::<u32>() {
        0 => {
            println!("nothing to do.");
            process::exit(1);
        },
        1 => (),
        _ => {
            eprintln!("only one of `-n', `-a', `-p' and `-g' could be specified");
            process::exit(1);
        }
    };

    if let Err(e) = run(matches) {
        eprintln!("{}", e);
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate time;

use std::os::{homedir, args};
use std::io::{File, SeekStyle, FileMode, FileAccess, USER_RWX};
use std::io::fs::{unlink, PathExtensions, mkdir};
use time::{now_utc, Tm};

fn main() {
    let args = args();
    match args.get(1) {
        None => panic!("No command given"),
        Some(command) => {
            let mut time_clock = TimeClock::new();
            match &command[] {
                "in" => time_clock.punch_in(),
                "out" => time_clock.punch_out(),
                _ => panic!("unknown command")
            }
        }
    }
}

struct TimeClock {
    now: Tm,
    timesheet: File,
    state_path: Path // TODO: maybe we can make this a bool that we
                           // initalise with the TimeClock
                           // and write back when we destroy the timeclock
                            // object
}

impl TimeClock {
    fn new() -> TimeClock {
        let now = now_utc();
        let home = homedir().unwrap();
        let base_dir = home.join(Path::new(".punch"));
        let timesheet_path = base_dir.join("timesheet");
        let working_state_path = base_dir.join("state");
        if !base_dir.exists() {
            mkdir(&base_dir, USER_RWX).unwrap();
        }
        let timesheet = File::open_mode(&timesheet_path,
                                            FileMode::Append,
                                            FileAccess::Write).unwrap();
        TimeClock {
            timesheet: timesheet,
            state_path: working_state_path,
            now: now
        }
    }

    fn punch_in(&mut self) {
        if self.currently_working() {
            panic!("You're already working");
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "in: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(true);
    }

    fn punch_out(&mut self) {
        if !self.currently_working() {
            panic!("Can't punch out if you're not working!");
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "out: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(false);
    }

    fn set_current_working_state(&self, currently_working: bool) {
        if currently_working {
            File::create(&self.state_path).unwrap();
        } else {
            unlink(&self.state_path).unwrap();
        }
    }

    fn currently_working(&self) -> bool {
        self.state_path.exists()
    }
}
<commit_msg>Add report and status commands<commit_after>#![allow(unstable)]

extern crate time;

use std::os::{homedir, args};
use std::io::{File, SeekStyle, FileMode, FileAccess, USER_RWX, BufferedReader};
use std::io::fs::{unlink, PathExtensions, mkdir};
use time::{now_utc, Tm, empty_tm, strptime};
use std::time::Duration;
use std::io::BufferPrelude;

fn main() {
    let args = args();
    match args.get(1) {
        None => panic!("No command given"),
        Some(command) => {
            let mut time_clock = TimeClock::new();
            match &command[] {
                "in" => time_clock.punch_in(),
                "out" => time_clock.punch_out(),
                "status" => time_clock.status(),
                "report" => time_clock.print_by_days(),
                _ => panic!("unknown command")
            }
        }
    }
}

struct TimeClock {
    now: Tm,
    timesheet: File,
    currently_working: bool,
    state_path: Path
}

impl TimeClock {
    fn new() -> TimeClock {
        let now = now_utc();
        let home = homedir().unwrap();
        let base_dir = home.join(Path::new(".punch"));
        let timesheet_path = base_dir.join("timesheet");
        let working_state_path = base_dir.join("state");
        if !base_dir.exists() {
            mkdir(&base_dir, USER_RWX).unwrap();
        }
        let timesheet = File::open_mode(&timesheet_path,
                                            FileMode::Append,
                                            FileAccess::Write).unwrap();
        TimeClock {
            timesheet: timesheet,
            currently_working: working_state_path.exists(),
            state_path: working_state_path,
            now: now
        }
    }

    fn punch_in(&mut self) {
        if self.currently_working {
            panic!("You're already working");
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "in: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(true);
    }

    fn punch_out(&mut self) {
        if !self.currently_working {
            panic!("Can't punch out if you're not working!");
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "out: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(false);
    }

    fn set_current_working_state(&mut self, currently_working: bool) {
        self.currently_working = currently_working;
        if currently_working {
            File::create(&self.state_path).unwrap();
        } else {
            unlink(&self.state_path).unwrap();
        }
    }

    fn print_by_days(&mut self) {
        self.timesheet.seek(0, SeekStyle::SeekSet).unwrap();
        let mut buf = BufferedReader::new(File::open(self.timesheet.path()));
        let mut starting_time: Option<Tm> = None;
        let mut current_day = empty_tm();
        let mut time_worked_today = Duration::zero();
        for l in buf.lines() {
            // lines should alternate between starting with "in: " and "out: "
            let line = l.unwrap();
            if let Some(start) = starting_time {
                if !line.starts_with("out: ") {
                    panic!("Bad data in timesheet!");
                }
                let time_str = &line[5..];
                let end_time = parse_time(time_str);
                let time_passed = end_time.to_timespec() - start.to_timespec();
                time_worked_today = time_worked_today + time_passed;
                if !same_day(&current_day, &start) {
                    if time_worked_today > Duration::days(1) {
                        panic!("Worked more than 24 hours in a day!");
                    }
                    if !time_worked_today.is_zero() {
                        println!("{}: {}:{}",
                            start.strftime("%a, %d %b %Y").unwrap(),
                            time_worked_today.num_hours() ,
                            time_worked_today.num_minutes() % 60
                        );
                    }
                    current_day = start;
                }
                starting_time = None;
            } else {
                if !line.starts_with("in: ") {
                    panic!("Bad data in timesheet!");
                }
                let time_str = &line[4..];
                let t = parse_time(time_str);
                starting_time = Some(t);
            }
        }
    }

    fn status(&self) {
        if self.currently_working {
            println!("You're punched in")
        } else {
            println!("You're punched out")
        }
    }
}

fn parse_time(s: &str) -> Tm {
    strptime(s.slice_to(s.len() - 1), "%a, %d %b %Y %T %Z").unwrap()
}

fn same_day(t1: &Tm, t2: &Tm) -> bool {
    t1.tm_year == t2.tm_year && t1.tm_yday == t2.tm_yday
}
<|endoftext|>


<commit_before>extern crate gmp;
extern crate time;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use asm::util::*;
use std::io;
use std::io::Write;
use std::str::FromStr;
use asm::assembler::Assembler;
use asm::environment::Environment;
use std::env;
use std::collections::HashMap;

mod asm;

fn add_external_calls(asm:&mut Assembler) {
	asm.add_external_call("printnum", |v,e,_| {
		print!("{}", boolvec_to_bignum(v.get_boolvec(e).as_slice()));
		io::stdout().flush().ok().expect("Could not flush stdout");
	});
	asm.add_external_call("print", |v,e,_| {
		let mut chars:Vec<u8> = vec![];
		let boolvec = v.get_boolvec(e);
		let val = boolvec.as_slice();
		for i in 0..(val.len()/8) {
			let nums = &val[i*8..(i+1)*8];
			let c = boolvec_to_u8(nums);
			if c == 0 {
				break;
			}
			chars.push(c);
		}
		let s = String::from_utf8_lossy(chars.as_slice()).to_string();
		print!("{}", s);
		io::stdout().flush().ok().expect("Could not flush stdout");
	});
	asm.add_external_call("valid", |v,e,_a| {
		let pos = v.get_ptr_position(e);
		let num = match e.validity {
			true => gmp::mpz::Mpz::one(),
			false => gmp::mpz::Mpz::zero()
		};
		let size = v.get_size(e);
		e.set_bits_bignum(&num, pos, size);
	});
	asm.add_external_call("prompt", |_v,e,_a|{
		let mut input = String::new();
		io::stdin().read_line(&mut input).expect("Invalid Input!");
		e.input_string = "".to_string();

		for line in input.lines() {
			e.input_string.push_str(line.as_ref());
		}
	});
	asm.add_external_call("inputnumlen", |v,e,_|{
		e.validity = true;
		let num = match gmp::mpz::Mpz::from_str(e.input_string.as_ref()) {
			Ok(val) => val,
			Err(_) => {
				e.validity = false;
				gmp::mpz::Mpz::zero()
			}
		};
		let num_size = num.bit_length();
		let pos = v.get_ptr_position(e);
		let size = v.get_ptr_size(e);
		e.set_bits_usize(num_size, pos, size);
	});
	asm.add_external_call("inputlen", |v,e,_|{
		let len_bits = e.input_string.len() * 8;
		let pos = v.get_ptr_position(e);
		let size = v.get_size(e);
		e.set_bits_usize(len_bits, pos, size);
	});
	asm.add_external_call("input", |v,e,_|{
		let boolvec = str_to_boolvec(e.input_string.as_ref());
		let pos = v.get_ptr_position(e);
		let size = v.get_size(e);
		e.set_bits_boolvec(boolvec.as_slice(), pos, size);
	});
	asm.add_external_call("inputnum", |v,e,_|{
		e.validity = true;
		let num = match gmp::mpz::Mpz::from_str(e.input_string.as_ref()) {
			Ok(val) => val,
			Err(_) => {
				e.validity = false;
				gmp::mpz::Mpz::zero()
			}
		};
		let pos = v.get_ptr_position(e);
		let size = v.get_size(e);
		e.set_bits_bignum(&num, pos, size);
	});

	asm.add_external_call("random", move |v,e,_|{
		let val = v.get_bignum(e);
		let result = e.randstate.urandom(&val);
		let pos = v.get_ptr_position(e);
		let size = v.get_ptr_size(e);
		e.set_bits_bignum(&result, pos, size);
	});
}

fn load_text(asm: &mut Assembler, code: &str) {
	let mut linenum = 0;
	for line in code.lines() {
		for s in line.split(';') {
			linenum += 1;
			asm.parse_line(&s.to_string(), linenum, None);
		}
	}
}

fn load_file(asm: &mut Assembler, file_name:&str) {
	let file = File::open(file_name).unwrap();
	let buffer = BufReader::new(&file);
	let mut linenum = 0;
	for line in buffer.lines() {
		let l:String = line.unwrap();
		linenum += 1;
		asm.parse_line(&l, linenum, Some(file_name.to_string()));
	}
}

enum Req {
	Yes,
	Maybe,
	No
}

struct ArgType {
	name:String,
	short:Option<String>,
	arg:Req
}

fn main() {
	let valid_args = vec![
		ArgType{name:"help".to_string(), short:Some("h".to_string()), arg:Req::No},
		ArgType{name:"file".to_string(), short:Some("h".to_string()), arg:Req::Yes},
		ArgType{name:"text".to_string(), short:Some("h".to_string()), arg:Req::Yes},
		ArgType{name:"print-stack".to_string(),  short:Some("s".to_string()), arg:Req::Maybe},
		ArgType{name:"print-parsed".to_string(), short:Some("p".to_string()), arg:Req::No},
	];

	let mut args:HashMap<String, String> = HashMap::new();

	let mut current_arg_name:String = "file".to_string();

	let mut is_first = true;
	for element in env::args().collect::<Vec<String>>() {
		if is_first {
			is_first = false;
			continue;
		}
		//argument
		if element.len() >= 2 && &element[0..2] == "--" {
			let element = &element[2..];
			let does_contain = valid_args.iter().filter(
				|a| a.name == element
			).count() != 0;

			if !does_contain {
				panic!("No such argument of name '{}'!", element);
			}

			current_arg_name = element.to_string();

			args.insert(current_arg_name.clone(), "".to_string());

		//shortened argument
		} else if element.len() >= 1 && &element[0..1] == "-" {
			let element = &element[1..];
			let mut arg_name = "".to_string();
			for arg in &valid_args {
				if arg.short == Some(element.to_string()) {
					arg_name = arg.name.clone();
					break;
				}
			}

			if arg_name == "" {
				panic!("No such argument of name '{}'!", element);
			} else {
				current_arg_name = arg_name;
			}

			args.insert(current_arg_name.clone(), "".to_string());

		//not an argument
		} else {
			println!("{}", element);
			let arg = args.get_mut(&current_arg_name).expect("No argument");
			arg.push_str(element.as_ref());
		}
	}

	let do_print_parsed = args.contains_key("print-parsed");
	let do_stack_print = args.contains_key("print-stack");

	let mut env = Environment::new();
	let mut asm = Assembler::new(do_print_parsed);
	add_external_calls(&mut asm);
	let mut do_run = false;

	if args.contains_key("help") {
		println!("{}",
"Welcome to Bit Assembly!
For help on how to write Bit Assembly, refer to the 'doc.md' file.

Usage:
    bit-asm --file {file name}.asm
    bit-asm --text {assembly}");

	} else if args.contains_key("file") {
		load_file(&mut asm, args.get("file").expect("This shouldnt happen"));
		do_run = true;

	} else if args.contains_key("text") {
		load_text(&mut asm, args.get("text").expect("This shouldnt happen"));
		do_run = true;

	} else {
		println!("type 'bit-asm --help' for help on how to use bit assembly");
	}
	if do_run {
		asm.run(&mut env);
		if do_stack_print {
			let bits = usize::from_str(
				match args.get("print-stack").unwrap_or(&"64".to_string()).as_ref() {
					"" => "64",
					other => other
				}
			)
				.expect("print-stack argument is not valid!");
			env.print_bytes(bits);
		}
	}
}
<commit_msg>Added more information to bit-asm help<commit_after>extern crate gmp;
extern crate time;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use asm::util::*;
use std::io;
use std::io::Write;
use std::str::FromStr;
use asm::assembler::Assembler;
use asm::environment::Environment;
use std::env;
use std::collections::HashMap;

mod asm;

fn add_external_calls(asm:&mut Assembler) {
	asm.add_external_call("printnum", |v,e,_| {
		print!("{}", boolvec_to_bignum(v.get_boolvec(e).as_slice()));
		io::stdout().flush().ok().expect("Could not flush stdout");
	});
	asm.add_external_call("print", |v,e,_| {
		let mut chars:Vec<u8> = vec![];
		let boolvec = v.get_boolvec(e);
		let val = boolvec.as_slice();
		for i in 0..(val.len()/8) {
			let nums = &val[i*8..(i+1)*8];
			let c = boolvec_to_u8(nums);
			if c == 0 {
				break;
			}
			chars.push(c);
		}
		let s = String::from_utf8_lossy(chars.as_slice()).to_string();
		print!("{}", s);
		io::stdout().flush().ok().expect("Could not flush stdout");
	});
	asm.add_external_call("valid", |v,e,_a| {
		let pos = v.get_ptr_position(e);
		let num = match e.validity {
			true => gmp::mpz::Mpz::one(),
			false => gmp::mpz::Mpz::zero()
		};
		let size = v.get_size(e);
		e.set_bits_bignum(&num, pos, size);
	});
	asm.add_external_call("prompt", |_v,e,_a|{
		let mut input = String::new();
		io::stdin().read_line(&mut input).expect("Invalid Input!");
		e.input_string = "".to_string();

		for line in input.lines() {
			e.input_string.push_str(line.as_ref());
		}
	});
	asm.add_external_call("inputnumlen", |v,e,_|{
		e.validity = true;
		let num = match gmp::mpz::Mpz::from_str(e.input_string.as_ref()) {
			Ok(val) => val,
			Err(_) => {
				e.validity = false;
				gmp::mpz::Mpz::zero()
			}
		};
		let num_size = num.bit_length();
		let pos = v.get_ptr_position(e);
		let size = v.get_ptr_size(e);
		e.set_bits_usize(num_size, pos, size);
	});
	asm.add_external_call("inputlen", |v,e,_|{
		let len_bits = e.input_string.len() * 8;
		let pos = v.get_ptr_position(e);
		let size = v.get_size(e);
		e.set_bits_usize(len_bits, pos, size);
	});
	asm.add_external_call("input", |v,e,_|{
		let boolvec = str_to_boolvec(e.input_string.as_ref());
		let pos = v.get_ptr_position(e);
		let size = v.get_size(e);
		e.set_bits_boolvec(boolvec.as_slice(), pos, size);
	});
	asm.add_external_call("inputnum", |v,e,_|{
		e.validity = true;
		let num = match gmp::mpz::Mpz::from_str(e.input_string.as_ref()) {
			Ok(val) => val,
			Err(_) => {
				e.validity = false;
				gmp::mpz::Mpz::zero()
			}
		};
		let pos = v.get_ptr_position(e);
		let size = v.get_size(e);
		e.set_bits_bignum(&num, pos, size);
	});

	asm.add_external_call("random", move |v,e,_|{
		let val = v.get_bignum(e);
		let result = e.randstate.urandom(&val);
		let pos = v.get_ptr_position(e);
		let size = v.get_ptr_size(e);
		e.set_bits_bignum(&result, pos, size);
	});
}

fn load_text(asm: &mut Assembler, code: &str) {
	let mut linenum = 0;
	for line in code.lines() {
		for s in line.split(';') {
			linenum += 1;
			asm.parse_line(&s.to_string(), linenum, None);
		}
	}
}

fn load_file(asm: &mut Assembler, file_name:&str) {
	let file = File::open(file_name).unwrap();
	let buffer = BufReader::new(&file);
	let mut linenum = 0;
	for line in buffer.lines() {
		let l:String = line.unwrap();
		linenum += 1;
		asm.parse_line(&l, linenum, Some(file_name.to_string()));
	}
}

enum Req {
	Yes,
	Maybe,
	No
}

struct ArgType {
	name:String,
	short:Option<String>,
	arg:Req
}

fn main() {
	let valid_args = vec![
		ArgType{name:"help".to_string(), short:Some("h".to_string()), arg:Req::No},
		ArgType{name:"file".to_string(), short:Some("h".to_string()), arg:Req::Yes},
		ArgType{name:"text".to_string(), short:Some("h".to_string()), arg:Req::Yes},
		ArgType{name:"print-stack".to_string(),  short:Some("s".to_string()), arg:Req::Maybe},
		ArgType{name:"print-parsed".to_string(), short:Some("p".to_string()), arg:Req::No},
	];

	let mut args:HashMap<String, String> = HashMap::new();

	let mut current_arg_name:String = "file".to_string();

	let mut is_first = true;
	for element in env::args().collect::<Vec<String>>() {
		if is_first {
			is_first = false;
			continue;
		}
		//argument
		if element.len() >= 2 && &element[0..2] == "--" {
			let element = &element[2..];
			let does_contain = valid_args.iter().filter(
				|a| a.name == element
			).count() != 0;

			if !does_contain {
				panic!("No such argument of name '{}'!", element);
			}

			current_arg_name = element.to_string();

			args.insert(current_arg_name.clone(), "".to_string());

		//shortened argument
		} else if element.len() >= 1 && &element[0..1] == "-" {
			let element = &element[1..];
			let mut arg_name = "".to_string();
			for arg in &valid_args {
				if arg.short == Some(element.to_string()) {
					arg_name = arg.name.clone();
					break;
				}
			}

			if arg_name == "" {
				panic!("No such argument of name '{}'!", element);
			} else {
				current_arg_name = arg_name;
			}

			args.insert(current_arg_name.clone(), "".to_string());

		//not an argument
		} else {
			println!("{}", element);
			let arg = args.get_mut(&current_arg_name).expect("No argument");
			arg.push_str(element.as_ref());
		}
	}

	let do_print_parsed = args.contains_key("print-parsed");
	let do_stack_print = args.contains_key("print-stack");

	let mut env = Environment::new();
	let mut asm = Assembler::new(do_print_parsed);
	add_external_calls(&mut asm);
	let mut do_run = false;

	if args.contains_key("help") {
		println!("{}",
"Welcome to Bit Assembly!
For help on how to write Bit Assembly, refer to the 'doc.md' file.

Usage:
    bit-asm --file {file name}.asm
    bit-asm --text {assembly}

Options:
    --print-stack {bits}    prints stack as a sequence of bytes
    --print-parsed          prints each line as they are parsed");

	} else if args.contains_key("file") {
		load_file(&mut asm, args.get("file").expect("This shouldnt happen"));
		do_run = true;

	} else if args.contains_key("text") {
		load_text(&mut asm, args.get("text").expect("This shouldnt happen"));
		do_run = true;

	} else {
		println!("type 'bit-asm --help' for help on how to use bit assembly");
	}
	if do_run {
		asm.run(&mut env);
		if do_stack_print {
			let bits = usize::from_str(
				match args.get("print-stack").unwrap_or(&"64".to_string()).as_ref() {
					"" => "64",
					other => other
				}
			)
				.expect("print-stack argument is not valid!");
			env.print_bytes(bits);
		}
	}
}
<|endoftext|>


<commit_before>#[derive(Debug)]
#[derive(Clone)]
enum PBWireType {
    VarInt,
    Fixed64,
    LengthDelim,
    Fixed32,
    Reserved,
}

struct TagValue<'a> {
    tag: u8,
    value: &'a [u8],
}

#[derive(Clone)]
struct ParserPosition {
    position: usize,
    tag: u8,
    wire_type: PBWireType,
    cur_idx: u8,
    max_idx: u8,
}

fn PBParseNext<'a>(s: &'a [u8], pos: ParserPosition) -> (TagValue<'a>, ParserPosition) {
    let idx2wireType = vec![PBWireType::VarInt,
                            PBWireType::Fixed64,
                            PBWireType::LengthDelim,
                            PBWireType::Reserved,
                            PBWireType::Reserved,
                            PBWireType::Fixed32];

    let mut p = pos.clone();

    if p.cur_idx == p.max_idx {
        p.tag = s[p.position] >> 3;
        p.wire_type = idx2wireType[(s[p.position] & 7) as usize].clone();
        p.position += 1;
        p.cur_idx = 0;
        p.max_idx = 0;
    }
    else {
      p.cur_idx += 1;
    }
    let mut value = match p.wire_type {
        PBWireType::LengthDelim => {
            let offset = s[p.position] as usize;
            let start = p.position + 1;
            let end = p.position + offset;
            p.position = end + 1;
            &s[start..end + 1]
        }
        _ => &[],
    };
    (TagValue {
         value: value,
         tag: p.tag,
     },
     p.clone())
}

use std::str;

fn main() {
    /*
     * Sample ProtocolBuffer message for schema:
     *
     *     message Test2 {
     *       required string b = 2;
     *     }
     *
     * with b = testing
     *
     * @see https://developers.google.com/protocol-buffers/docs/encoding
     */
    let msg = vec![0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67];

    let (x, pp) = PBParseNext(msg.as_slice(),
                              ParserPosition {
                                  position: 0,
                                  tag: 0,
                                  wire_type: PBWireType::Reserved,
                                  cur_idx: 0,
                                  max_idx: 0,
                              });

    print!("Tag   = {}\n", x.tag);
    print!("Value = {}\n", str::from_utf8(x.value).unwrap());
}
<commit_msg>Example of multiple fields<commit_after>#[derive(Clone, Copy, Debug)]
enum PBWireType {
    VarInt,
    Fixed64,
    LengthDelim,
    Fixed32,
    Reserved,
}

struct TagValue<'a> {
    tag: u8,
    value: &'a [u8],
}

#[derive(Clone)]
struct ParserPosition {
    position: usize,
    tag: u8,
    wire_type: PBWireType,
    cur_idx: u8,
    max_idx: u8,
}

fn PBParseNext<'a>(s: &'a [u8], pos: ParserPosition) -> (TagValue<'a>, ParserPosition) {
    let idx2wireType = vec![PBWireType::VarInt,
                            PBWireType::Fixed64,
                            PBWireType::LengthDelim,
                            PBWireType::Reserved,
                            PBWireType::Reserved,
                            PBWireType::Fixed32];

    let mut p = pos.clone();

    if p.cur_idx == p.max_idx {
        p.tag = s[p.position] >> 3;
        p.wire_type = idx2wireType[(s[p.position] & 7) as usize];
        p.position += 1;
        p.cur_idx = 0;
        p.max_idx = 0;
    }
    else {
      p.cur_idx += 1;
    }
    let mut value = match p.wire_type {
        PBWireType::LengthDelim => {
            let offset = s[p.position] as usize;
            let start = p.position + 1;
            let end = p.position + offset;
            p.position = end + 1;
            &s[start..end + 1]
        }
        _ => &[],
    };
    (TagValue {
         value: value,
         tag: p.tag,
     },
     p.clone())
}

use std::str;

fn main() {
    /*
     * Sample ProtocolBuffer message for schema:
     *
     *     message Test2 {
     *       required string a = 1;
     *       required string b = 2;
     *     }
     *
     * with a = test, b = testing
     *
     * @see https://developers.google.com/protocol-buffers/docs/encoding
     */
    let msg = vec![0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67,
                   0x0a, 0x04, 0x74, 0x65, 0x73, 0x74];

    let (mut x, mut pp) = PBParseNext(msg.as_slice(),
                              ParserPosition {
                                  position: 0,
                                  tag: 0,
                                  wire_type: PBWireType::Reserved,
                                  cur_idx: 0,
                                  max_idx: 0,
                              });

    print!("Tag   = {}\n", x.tag);
    print!("Value = {}\n", str::from_utf8(x.value).unwrap());

    let (x, pp) = PBParseNext(msg.as_slice(), pp);

    print!("Tag   = {}\n", x.tag);
    print!("Value = {}\n", str::from_utf8(x.value).unwrap());
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;

use diffus::{
    edit::{self, string},
    Diffable,
};
use regex::Regex;
use std::io::{self, BufRead};

const ADD: &str = "\x1b[32m"; // Green
const REMOVE: &str = "\x1b[31m"; // Red
const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

const INVERSE_VIDEO: &str = "\x1b[7m";
const NOT_INVERSE_VIDEO: &str = "\x1b[27m";

const BOLD: &str = "\x1b[1m";

const NORMAL: &str = "\x1b[0m";

lazy_static! {
    static ref STATIC_HEADERS: Vec<(Regex, &'static str)> = vec![
        (Regex::new("^diff ").unwrap(), BOLD),
        (Regex::new("^index ").unwrap(), BOLD),
        (Regex::new("^--- ").unwrap(), BOLD),
        (Regex::new("^\\+\\+\\+ ").unwrap(), BOLD),
        (Regex::new("^@@ ").unwrap(), HUNK_HEADER),
    ];
}

fn simple_print_adds_and_removes(adds: &[String], removes: &[String]) {
    for remove_line in removes {
        println!("{}{}", REMOVE, remove_line)
    }

    for add_line in adds {
        println!("{}{}", ADD, add_line)
    }

    print!("{}", NORMAL);
}

/// Joins multiple lines into a single string.
///
/// The first character of each line is skipped, because it is assumed to be
/// either a `+` or a `-` in a diff.
///
/// Between each joined line a `\n` linefeed character is inserted.
fn join_skip_first(lines: &[String]) -> String {
    let mut joined = String::new();
    for line in lines {
        if !line.is_empty() {
            joined.push_str("\n")
        }
        joined.push_str(&line[1..]);
    }

    return joined;
}

fn print_adds_and_removes(adds: &[String], removes: &[String]) {
    if adds.is_empty() {
        simple_print_adds_and_removes(adds, removes);
        return;
    }

    if removes.is_empty() {
        simple_print_adds_and_removes(adds, removes);
        return;
    }

    // Join inputs by linefeeds into strings
    let adds = join_skip_first(adds);
    let removes = join_skip_first(removes);

    // Find diffs between adds and removals
    let mut highlighted_adds = String::new();
    let mut highlighted_removes = String::new();
    let mut adds_is_inverse = false;
    let mut removes_is_inverse = false;
    let diff = removes.diff(&adds);
    match diff {
        edit::Edit::Copy(unchanged) => {
            highlighted_adds.push_str(unchanged);
            highlighted_removes.push_str(unchanged);
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        string::Edit::Copy(elem) => {
                            if adds_is_inverse {
                                highlighted_adds.push_str(NOT_INVERSE_VIDEO);
                            }
                            adds_is_inverse = false;

                            if removes_is_inverse {
                                highlighted_removes.push_str(NOT_INVERSE_VIDEO);
                            }
                            removes_is_inverse = false;

                            highlighted_adds.push(elem);
                            highlighted_removes.push(elem);
                        }
                        string::Edit::Insert(elem) => {
                            if !adds_is_inverse {
                                highlighted_adds.push_str(INVERSE_VIDEO);
                            }
                            adds_is_inverse = true;

                            highlighted_adds.push(elem);
                        }
                        string::Edit::Remove(elem) => {
                            if !removes_is_inverse {
                                highlighted_removes.push_str(INVERSE_VIDEO);
                            }
                            removes_is_inverse = true;

                            highlighted_removes.push(elem);
                        }
                    };
                })
                .for_each(drop);
        }
    }

    for highlighted_remove in highlighted_removes.lines() {
        println!("{}-{}", REMOVE, highlighted_remove);
    }
    for highlighted_add in highlighted_adds.lines() {
        println!("{}+{}", ADD, highlighted_add);
    }
}

fn get_fixed_highlight(line: &str) -> &str {
    for static_header in STATIC_HEADERS.iter() {
        let re = &static_header.0;
        if re.is_match(line) {
            return static_header.1;
        }
    }

    return "";
}

fn main() {
    let stdin = io::stdin();
    let mut adds: Vec<String> = Vec::new();
    let mut removes: Vec<String> = Vec::new();
    for line in stdin.lock().lines() {
        let line = line.unwrap();

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            // Drain outstanding adds / removes
            print_adds_and_removes(&adds, &removes);
            adds.clear();
            removes.clear();

            println!("{}{}{}", fixed_highlight, line, NORMAL);
            continue;
        }

        // Collect adds / removes
        if !line.is_empty() && line.chars().next().unwrap() == '+' {
            adds.push(line);
            continue;
        } else if !line.is_empty() && line.chars().next().unwrap() == '-' {
            removes.push(line);
            continue;
        }

        // Drain outstanding adds / removes
        print_adds_and_removes(&adds, &removes);
        adds.clear();
        removes.clear();

        // Print current line
        println!("{}", line);
    }
    print_adds_and_removes(&adds, &removes);

    print!("{}", NORMAL);
}
<commit_msg>Make simple formatting function testable<commit_after>#[macro_use]
extern crate lazy_static;

use diffus::{
    edit::{self, string},
    Diffable,
};
use regex::Regex;
use std::io::{self, BufRead};

const ADD: &str = "\x1b[32m"; // Green
const REMOVE: &str = "\x1b[31m"; // Red
const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

const INVERSE_VIDEO: &str = "\x1b[7m";
const NOT_INVERSE_VIDEO: &str = "\x1b[27m";

const BOLD: &str = "\x1b[1m";

const NORMAL: &str = "\x1b[0m";

lazy_static! {
    static ref STATIC_HEADERS: Vec<(Regex, &'static str)> = vec![
        (Regex::new("^diff ").unwrap(), BOLD),
        (Regex::new("^index ").unwrap(), BOLD),
        (Regex::new("^--- ").unwrap(), BOLD),
        (Regex::new("^\\+\\+\\+ ").unwrap(), BOLD),
        (Regex::new("^@@ ").unwrap(), HUNK_HEADER),
    ];
}

/// Format add and remove lines in ADD and REMOVE colors.
///
/// No intra-line refinement.
#[must_use]
fn simple_format_adds_and_removes(adds: &[String], removes: &[String]) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();

    for remove_line in removes {
        lines.push(format!("{}{}", REMOVE, remove_line));
    }

    for add_line in adds {
        // The NORMAL at the end is required for the following lines not to be printed
        // with ADD coloring.
        lines.push(format!("{}{}{}", ADD, add_line, NORMAL))
    }

    return lines;
}

/// Joins multiple lines into a single string.
///
/// The first character of each line is skipped, because it is assumed to be
/// either a `+` or a `-` in a diff.
///
/// Between each joined line a `\n` linefeed character is inserted.
fn join_skip_first(lines: &[String]) -> String {
    let mut joined = String::new();
    for line in lines {
        if !line.is_empty() {
            joined.push_str("\n")
        }
        joined.push_str(&line[1..]);
    }

    return joined;
}

fn print_adds_and_removes(adds: &[String], removes: &[String]) {
    if adds.is_empty() {
        for line in simple_format_adds_and_removes(adds, removes) {
            println!("{}", line);
        }
        return;
    }

    if removes.is_empty() {
        for line in simple_format_adds_and_removes(adds, removes) {
            println!("{}", line);
        }
        return;
    }

    // Join inputs by linefeeds into strings
    let adds = join_skip_first(adds);
    let removes = join_skip_first(removes);

    // Find diffs between adds and removals
    let mut highlighted_adds = String::new();
    let mut highlighted_removes = String::new();
    let mut adds_is_inverse = false;
    let mut removes_is_inverse = false;
    let diff = removes.diff(&adds);
    match diff {
        edit::Edit::Copy(unchanged) => {
            highlighted_adds.push_str(unchanged);
            highlighted_removes.push_str(unchanged);
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        string::Edit::Copy(elem) => {
                            if adds_is_inverse {
                                highlighted_adds.push_str(NOT_INVERSE_VIDEO);
                            }
                            adds_is_inverse = false;

                            if removes_is_inverse {
                                highlighted_removes.push_str(NOT_INVERSE_VIDEO);
                            }
                            removes_is_inverse = false;

                            highlighted_adds.push(elem);
                            highlighted_removes.push(elem);
                        }
                        string::Edit::Insert(elem) => {
                            if !adds_is_inverse {
                                highlighted_adds.push_str(INVERSE_VIDEO);
                            }
                            adds_is_inverse = true;

                            highlighted_adds.push(elem);
                        }
                        string::Edit::Remove(elem) => {
                            if !removes_is_inverse {
                                highlighted_removes.push_str(INVERSE_VIDEO);
                            }
                            removes_is_inverse = true;

                            highlighted_removes.push(elem);
                        }
                    };
                })
                .for_each(drop);
        }
    }

    for highlighted_remove in highlighted_removes.lines() {
        println!("{}-{}", REMOVE, highlighted_remove);
    }
    for highlighted_add in highlighted_adds.lines() {
        println!("{}+{}", ADD, highlighted_add);
    }
}

fn get_fixed_highlight(line: &str) -> &str {
    for static_header in STATIC_HEADERS.iter() {
        let re = &static_header.0;
        if re.is_match(line) {
            return static_header.1;
        }
    }

    return "";
}

fn main() {
    let stdin = io::stdin();
    let mut adds: Vec<String> = Vec::new();
    let mut removes: Vec<String> = Vec::new();
    for line in stdin.lock().lines() {
        let line = line.unwrap();

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            // Drain outstanding adds / removes
            print_adds_and_removes(&adds, &removes);
            adds.clear();
            removes.clear();

            println!("{}{}{}", fixed_highlight, line, NORMAL);
            continue;
        }

        // Collect adds / removes
        if !line.is_empty() && line.chars().next().unwrap() == '+' {
            adds.push(line);
            continue;
        } else if !line.is_empty() && line.chars().next().unwrap() == '-' {
            removes.push(line);
            continue;
        }

        // Drain outstanding adds / removes
        print_adds_and_removes(&adds, &removes);
        adds.clear();
        removes.clear();

        // Print current line
        println!("{}", line);
    }
    print_adds_and_removes(&adds, &removes);

    print!("{}", NORMAL);
}
<|endoftext|>


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

type FreeVariable = u64;
type VariableName<'a> = &'a str;

/// AST node expression
#[derive(Clone, Debug)]
enum Expression<'a> {
    Number(f64),
    Boolean(bool),

    /// simple variable
    Variable(VariableName<'a>),

    /// fn (x, y, z) -> expr
    Lambda(&'a [VariableName<'a>], &'a Expression<'a>),

    /// let x = expr in expr
    Let(VariableName<'a>, &'a Expression<'a>, &'a Expression<'a>),

    /// some_fn (x, y, z)
    FnCall(&'a Expression<'a>, &'a [ &'a Expression<'a>])
}

#[derive(PartialEq, Clone, Debug)]
enum Type {
    Number,
    Boolean,
    Unbound(FreeVariable),
    // FIXME: can I avoid having this be boxed and vec'd?
    Lambda(Vec<Type>, Box<Type>),
}

type TaggedType<'a> = (Expression<'a>, Type);

type TypeEnv<'a> = HashMap<VariableName<'a>, Type>;

#[derive(Clone, Copy)]
struct VariableGen { current: FreeVariable }
impl VariableGen {
    fn next(&mut self) -> FreeVariable { self.current += 1; self.current }
}

/// Run algorithm W on expr with given type env, yielding the resolved
/// type of the expression, or the type error encountered.
fn w<'a>(expr: &Expression<'a>, env: &mut TypeEnv<'a>, inst: &mut VariableGen) -> Type {
    match *expr {
        // simplest case: literals have immediately defined types.
        Expression::Number(_) => Type::Number,
        Expression::Boolean(_) => Type::Boolean,

        // variables we need to look up inside our type environment
        Expression::Variable(name) => match env.get(name) {
            Some(typ) => typ.clone(),
            None => panic!("undefined variable, {}", name)
        },

        Expression::Lambda(args, body) => {
            // TODO: args -> types. modify the environment
            let body_ty = w(body, env, inst);
            let args_ty = args
                .into_iter()
                .map(|arg| {
                    let ty = inst.next();
                    env.insert(arg, Type::Unbound(ty));
                    Type::Unbound(ty)
                })
                .collect::<Vec<Type>>();

            Type::Lambda(args_ty, Box::new(body_ty))
        },

        Expression::Let(name, expr, body) => {
            let expr_ty = w(expr, env, inst);
            env.insert(name, expr_ty);

            w(body, env, inst)
        },

        // 1. ensure that the callable in this function call is truly callable.
        // 2. ensure that the number and type of args match
        // 3. return type of body of lambda
        Expression::FnCall(callable, args) => {
            // FIXME: this seems broken.
            let mut env_ = env.clone();
            let mut inst_ = inst.clone();

            let type_args = args
                .iter()
                .map(|arg| {
                    w(arg, &mut env_, &mut inst_)
                })
                .collect::<Vec<Type>>();

            match w(callable, env, inst) {
                Type::Lambda(expected, body_type) => {
                    if args.len() != expected.len() {
                        panic!("wrong number of args given, {} for {}", args.len(), expected.len())
                    } else if expected != type_args.as_slice() {
                        panic!("bad types given: {:?} for {:?}", type_args.as_slice(), expected)
                    }

                    *body_type.clone()
                }

                _ => panic!("trying to call non-function")
            }
        }
    }
}

fn main() {
    // FIXME: this is so gnarly.
    // let incr = \x -> 123.0 in incr (123.0) :: Number
    let num = Expression::Number(123.0);
    let incr = Expression::Variable("incr");
    let x = Expression::Variable("x");
    let args = ["x"];
    let args_ = [&num];
    let fn_call = Expression::FnCall(&incr, &args_);
    let lambda = Expression::Lambda(&args, &num);

    // let expr = Expression::Let(
    //     "incr", &lambda,
    //     &fn_call);

    let expr = Expression::Let("y", &num, &x);

    let mut inst = VariableGen {current: 0};
    let mut env = HashMap::new();

    println!("this is the thing: {:?}\n", w(&expr, &mut env, &mut inst))
}
<commit_msg>TODO: unify<commit_after>use std::fmt::Display;
use std::collections::HashMap;

type FreeVariable = u64;
type VariableName<'a> = &'a str;

/// AST node expression
#[derive(Clone, Debug)]
enum Expression<'a> {
    Number(f64),
    Boolean(bool),

    /// simple variable
    Variable(VariableName<'a>),

    /// fn (x, y, z) -> expr
    Lambda(&'a [VariableName<'a>], &'a Expression<'a>),

    /// let x = expr in expr
    Let(VariableName<'a>, &'a Expression<'a>, &'a Expression<'a>),

    /// some_fn (x, y, z)
    FnCall(&'a Expression<'a>, &'a [ &'a Expression<'a>])
}

#[derive(PartialEq, Clone, Debug)]
enum Type {
    Number,
    Boolean,
    Unbound(FreeVariable),
    // FIXME: can I avoid having this be boxed and vec'd?
    Lambda(Vec<Type>, Box<Type>),
}

type TaggedType<'a> = (Expression<'a>, Type);

type TypeEnv<'a> = HashMap<VariableName<'a>, Type>;

#[derive(Clone, Copy)]
struct VariableGen { current: FreeVariable }
impl VariableGen {
    fn next(&mut self) -> FreeVariable { self.current += 1; self.current }
}

/// Run algorithm W on expr with given type env, yielding the resolved
/// type of the expression, or the type error encountered.
fn w<'a>(expr: &Expression<'a>, env: &mut TypeEnv<'a>, inst: &mut VariableGen) -> Type {
    match *expr {
        // simplest case: literals have immediately defined types.
        Expression::Number(_) => Type::Number,
        Expression::Boolean(_) => Type::Boolean,

        // variables we need to look up inside our type environment
        Expression::Variable(name) => match env.get(name) {
            Some(typ) => typ.clone(),
            None => panic!("undefined variable, {}", name)
        },

        Expression::Lambda(args, body) => {
            // TODO: args -> types. modify the environment
            let body_ty = w(body, env, inst);
            let args_ty = args
                .into_iter()
                .map(|arg| {
                    let ty = inst.next();
                    env.insert(arg, Type::Unbound(ty));
                    Type::Unbound(ty)
                })
                .collect::<Vec<Type>>();

            Type::Lambda(args_ty, Box::new(body_ty))
        },

        Expression::Let(name, expr, body) => {
            let expr_ty = w(expr, env, inst);
            env.insert(name, expr_ty);

            w(body, env, inst)
        },

        // 1. ensure that the callable in this function call is truly callable.
        // 2. ensure that the number and type of args match
        // 3. return type of body of lambda
        // TODO: Need unification algo here.
        Expression::FnCall(callable, args) => {
            // FIXME: this seems broken.
            let mut env_ = env.clone();
            let mut inst_ = inst.clone();

            let type_args = args
                .iter()
                .map(|arg| {
                    w(arg, &mut env_, &mut inst_)
                })
                .collect::<Vec<Type>>();

            match w(callable, env, inst) {
                Type::Lambda(expected, body_type) => {
                    if args.len() != expected.len() {
                        panic!("wrong number of args given, {} for {}", args.len(), expected.len())
                    } else if expected != type_args.as_slice() {
                        panic!("bad types given: {:?} for {:?}", type_args.as_slice(), expected)
                    }

                    *body_type.clone()
                }

                _ => panic!("trying to call non-function")
            }
        }
    }
}

fn main() {
    // FIXME: this is so gnarly.
    // let incr = \x -> 123.0 in incr (123.0) :: Number
    let num = Expression::Number(123.0);
    let incr = Expression::Variable("incr");
    let x = Expression::Variable("x");
    let args = ["x", "y", "z"];
    let args_ = [&num];
    let fn_call = Expression::FnCall(&incr, &args_);
    let lambda = Expression::Lambda(&args, &num);

    // let expr = Expression::Let(
    //     "incr", &lambda,
    //     &fn_call);

    let expr = Expression::Let("x", &num, &x);

    let mut inst = VariableGen {current: 0};
    let mut env = HashMap::new();

    println!("this is the thing: {:?}\n", w(&lambda, &mut env, &mut inst))
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate walkdir;

use walkdir::WalkDir;
use rand::{Rng, thread_rng};
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
use std::io::Error;
use std::cmp;

fn main() {
    let mut recursive: bool = false;
    let mut file: String = String::from("");
    let mut i: i32 = -1;

    for argument in env::args() {
        i += 1;
        if i == 0 {
            continue;
        }

        if argument.to_lowercase() == "--help" || argument.to_lowercase() == "-help" {
            help();
            return;
        } else if argument.to_lowercase() == "--v" || argument.to_lowercase() == "-v" ||
           argument.to_lowercase() == "-version" ||
           argument.to_lowercase() == "--version" {
            version();
            return;
        } else if argument.to_lowercase() == "-r" {
            recursive = true;
        } else {
            file = argument;
            break;
        }
    }
    if file == "" {
        help();
        return;
    }
    file = get_path(&file);

    if recursive {
        for entry in WalkDir::new(file) {
            let entry = entry.unwrap();
            trumpify(entry.path().display().to_string());
        }
    } else {
        trumpify(file)
    }
}

fn get_path2(file: &str) -> Result<String, Error> {
    let path = try!(fs::canonicalize(file));
    Ok(path.display().to_string())
}

fn get_path(file: &str) -> String {
    get_path2(file).unwrap_or(file.to_owned())
}

fn read_file2(file: &str) -> Result<String, Error> {
    let mut file = try!(File::open(file));
    let mut contents: Vec<u8> = Vec::new();
    try!(file.read_to_end(&mut contents));
    let ret = String::from_utf8(contents).unwrap_or("".to_owned());
    Ok(ret)
}

fn read_file(file: &str) -> String {
    read_file2(file).unwrap_or("".to_owned())
}

fn write_file2(file: &str, content: String) -> Result<bool, Error> {
    let mut f = try!(File::create(file));
    try!(f.write_all(content.as_bytes()));

    try!(f.sync_data());
    Ok(false)
}

fn write_file(file: &str, content: String) {
    write_file2(file, content).unwrap_or(false);
}

fn version() {
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump-0.1.0");
    println!("\x1b[32mWebsite:");
    println!("\x1b[0m    https://github.com/x13machine/trump/");
    println!("\x1b[32mCreator:");
    println!("\x1b[0m    <Googolplexking/x13machine> https://googolplex.ninja/");
}
fn help() {
    println!("\x1b[32mHelp:");
    println!("\x1b[0m    trump --help");
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump -v");
    println!("\x1b[32mFiles:");
    println!("\x1b[0m    trump <File>");
    println!("\x1b[32mDirectories:");
    println!("\x1b[0m    trump -r <Directory>");
}

fn trumpify(file: String) {
    let dirs: Vec<&str> = file.split("/").collect::<Vec<&str>>();
    let mut name: String = String::from(dirs[dirs.len() - 1]);
    name = format!("{}{}",
                   &name[0..1].to_uppercase(),
                   &name[1..name.len()].to_lowercase());
    // Ansi Color Codes!!!
    println!("\x1b[32mMaking Great Again:\x1b[0m {}", file);

    let text = format!("Make {} Great Again!", name);

    let mut content: String = read_file(&file);
    if content == "" {
        return;
    }

    let loops = cmp::max(content.len() / text.len() / 2, 1);
    let mut rng = thread_rng();
    for _ in 0..loops {
        let place: usize = rng.gen_range(0, content.len() as u32) as usize;
        let part1: String = String::from(&content[0..place]);
        let part2: String =
            String::from(&content[cmp::min(place + text.len(), content.len())..content.len()]);
        content = format!("{}{}{}", part1, text, part2);
    }
    write_file(&file, content);
}
<commit_msg>You can use chars in patterns instead of strings<commit_after>extern crate rand;
extern crate walkdir;

use walkdir::WalkDir;
use rand::{Rng, thread_rng};
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
use std::io::Error;
use std::cmp;

fn main() {
    let mut recursive: bool = false;
    let mut file: String = String::from("");
    let mut i: i32 = -1;

    for argument in env::args() {
        i += 1;
        if i == 0 {
            continue;
        }

        if argument.to_lowercase() == "--help" || argument.to_lowercase() == "-help" {
            help();
            return;
        } else if argument.to_lowercase() == "--v" || argument.to_lowercase() == "-v" ||
           argument.to_lowercase() == "-version" ||
           argument.to_lowercase() == "--version" {
            version();
            return;
        } else if argument.to_lowercase() == "-r" {
            recursive = true;
        } else {
            file = argument;
            break;
        }
    }
    if file == "" {
        help();
        return;
    }
    file = get_path(&file);

    if recursive {
        for entry in WalkDir::new(file) {
            let entry = entry.unwrap();
            trumpify(entry.path().display().to_string());
        }
    } else {
        trumpify(file)
    }
}

fn get_path2(file: &str) -> Result<String, Error> {
    let path = try!(fs::canonicalize(file));
    Ok(path.display().to_string())
}

fn get_path(file: &str) -> String {
    get_path2(file).unwrap_or(file.to_owned())
}

fn read_file2(file: &str) -> Result<String, Error> {
    let mut file = try!(File::open(file));
    let mut contents: Vec<u8> = Vec::new();
    try!(file.read_to_end(&mut contents));
    let ret = String::from_utf8(contents).unwrap_or("".to_owned());
    Ok(ret)
}

fn read_file(file: &str) -> String {
    read_file2(file).unwrap_or("".to_owned())
}

fn write_file2(file: &str, content: String) -> Result<bool, Error> {
    let mut f = try!(File::create(file));
    try!(f.write_all(content.as_bytes()));

    try!(f.sync_data());
    Ok(false)
}

fn write_file(file: &str, content: String) {
    write_file2(file, content).unwrap_or(false);
}

fn version() {
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump-0.1.0");
    println!("\x1b[32mWebsite:");
    println!("\x1b[0m    https://github.com/x13machine/trump/");
    println!("\x1b[32mCreator:");
    println!("\x1b[0m    <Googolplexking/x13machine> https://googolplex.ninja/");
}
fn help() {
    println!("\x1b[32mHelp:");
    println!("\x1b[0m    trump --help");
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump -v");
    println!("\x1b[32mFiles:");
    println!("\x1b[0m    trump <File>");
    println!("\x1b[32mDirectories:");
    println!("\x1b[0m    trump -r <Directory>");
}

fn trumpify(file: String) {
    let dirs: Vec<&str> = file.split('/').collect::<Vec<&str>>();
    let mut name: String = String::from(dirs[dirs.len() - 1]);
    name = format!("{}{}",
                   &name[0..1].to_uppercase(),
                   &name[1..name.len()].to_lowercase());
    // Ansi Color Codes!!!
    println!("\x1b[32mMaking Great Again:\x1b[0m {}", file);

    let text = format!("Make {} Great Again!", name);

    let mut content: String = read_file(&file);
    if content == "" {
        return;
    }

    let loops = cmp::max(content.len() / text.len() / 2, 1);
    let mut rng = thread_rng();
    for _ in 0..loops {
        let place: usize = rng.gen_range(0, content.len() as u32) as usize;
        let part1: String = String::from(&content[0..place]);
        let part2: String =
            String::from(&content[cmp::min(place + text.len(), content.len())..content.len()]);
        content = format!("{}{}{}", part1, text, part2);
    }
    write_file(&file, content);
}
<|endoftext|>


<commit_before>//! Galaxy creator for Space Settler
//!
//! This program creates a new galaxy for Space Settler. It has a statistically correct sample of
//! stars, and in those stars it creates complete solar systems (still in development). It creates
//! stars regarding to proportion shown [here](http://adsabs.harvard.edu/abs/2001JRASC..95...32L).
//! Then, the planets are created thinking on habitability, but following as far as possible all the
//! physical laws.

mod planet;
mod star;
mod consts {
	pub const SUN_MASS: f64 = 1.9884E+30; // kg
	pub const SUN_RADIUS: f64 = 6.96E+8; // m
	pub const SUN_LUMINOSITY: f64 = 3.846E+26; // W

    pub const G: f64 = 6.67428e-11_f64; // m³·kg⁻¹·s⁻²
    pub const C: f64 = 299_792_458_f64; // m·s⁻¹
    pub const BOLTZ: f64 = 5.670373E-8_f64; // W·m⁻²·K⁻⁴
}

use std::f64::consts::PI;
use star::Star;
use planet::Planet;

pub fn rad_to_deg(rads: f64) -> f64 {
    rads*180_f64/PI
}

pub fn deg_to_rad(degs: f64) -> f64 {
    degs*PI/180_f64
}

fn main() {
	let sun = Star::new(0, 1);
	println!("Created a new star:");

    println!("\tID: {}", sun.get_id());
    println!("\tGalaxy: {}", sun.get_galaxy_id());
    println!("\tOrbit: {} light years", sun.get_orbit());
    println!("\tClass: {}", sun.get_class_str());
    println!("\tMass: {} suns", sun.get_mass()/consts::SUN_MASS);
    println!("\tRadius: {} suns", sun.get_radius()/consts::SUN_RADIUS);
    println!("\tDensity: {} kg/m³", sun.get_density());
    println!("\tTemperature: {} K", sun.get_temp());
    println!("\tLuminosity: {} suns", sun.get_luminosity()/consts::SUN_LUMINOSITY);

    let earth = Planet::new(&sun, 0.0183, 1.0643, 3);
    println!("\nCreated a new Planet:");

    println!("\tStar ID: {}", earth.get_orbit().get_star().get_id());
    println!("\tAlbedo: {}", earth.get_albedo());
    println!("\tOrbit:");
    println!("\t\tSemimajor axis: {:e} meters", earth.get_orbit().get_sMa());
    println!("\t\tEccentricity: {}", earth.get_orbit().get_ecc());
    println!("\t\tApoapsis: {:e} meters", earth.get_orbit().get_apoapsis());
    println!("\t\tPeriapsis: {:e} meters", earth.get_orbit().get_periapsis());
    println!("\t\tOrbital period: {} days", earth.get_orbit().get_orb_period()/earth.get_orbit().get_day());
    println!("\t\tDay length: {} hours", earth.get_orbit().get_day()/3_600_f64);
    println!("\t\tAxial tilt: {}°", rad_to_deg(earth.get_orbit().get_ax_tilt()));
    println!("\tAtmosphere:");
    println!("\t\tPressure: {} Pa", earth.get_atmosphere().get_pressure());
    println!("\t\tCarbon dioxide (CO₂): {}%", earth.get_atmosphere().get_co2());
    println!("\t\tCarbon monoxide (CO): {}%", earth.get_atmosphere().get_co());
    println!("\t\tNitrogen (N₂): {}%", earth.get_atmosphere().get_n2());
    println!("\t\tOxygen (O₂): {}%", earth.get_atmosphere().get_o2());
    println!("\t\tArgon (Ar): {}%", earth.get_atmosphere().get_ar());
    println!("\t\tSulfur dioxide (SO₂): {}%", earth.get_atmosphere().get_so2());
    println!("\t\tNeon (Ne): {}%", earth.get_atmosphere().get_ne());
    println!("\t\tMethane (CH₄): {}%", earth.get_atmosphere().get_ch4());
    println!("\t\tHelium (He): {}%", earth.get_atmosphere().get_he());
}
<commit_msg>Added more tests<commit_after>//! Galaxy creator for Space Settler
//!
//! This program creates a new galaxy for Space Settler. It has a statistically correct sample of
//! stars, and in those stars it creates complete solar systems (still in development). It creates
//! stars regarding to proportion shown [here](http://adsabs.harvard.edu/abs/2001JRASC..95...32L).
//! Then, the planets are created thinking on habitability, but following as far as possible all the
//! physical laws.

mod planet;
mod star;
mod consts {
	pub const SUN_MASS: f64 = 1.9884E+30; // kg
	pub const SUN_RADIUS: f64 = 6.96E+8; // m
	pub const SUN_LUMINOSITY: f64 = 3.846E+26; // W

    pub const G: f64 = 6.67428e-11; // m³·kg⁻¹·s⁻²
    pub const C: f64 = 299_792_458_f64; // m·s⁻¹
    pub const BOLTZ: f64 = 5.670373E-8; // W·m⁻²·K⁻⁴
}

use std::f64::consts::PI;
use star::Star;
use planet::Planet;

pub fn rad_to_deg(rads: f64) -> f64 {
    rads*180_f64/PI
}

pub fn deg_to_rad(degs: f64) -> f64 {
    degs*PI/180_f64
}

fn main() {
	let sun = Star::new(0, 1);
	println!("Created a new star:");

    println!("\tID: {}", sun.get_id());
    println!("\tGalaxy: {}", sun.get_galaxy_id());
    println!("\tOrbit: {} light years", sun.get_orbit());
    println!("\tClass: {}", sun.get_class_str());
    println!("\tMass: {} suns", sun.get_mass()/consts::SUN_MASS);
    println!("\tRadius: {} suns", sun.get_radius()/consts::SUN_RADIUS);
    println!("\tDensity: {} kg/m³", sun.get_density());
    println!("\tTemperature: {} K", sun.get_temp());
    println!("\tLuminosity: {} suns", sun.get_luminosity()/consts::SUN_LUMINOSITY);

    let earth = Planet::new(&sun, 0.0183, 1.0643, 3);
    println!("\nCreated a new Planet:");

    println!("\tStar ID: {}", earth.get_orbit().get_star().get_id());
    println!("\tAlbedo: {}", earth.get_albedo());
    println!("\tOrbit:");
    println!("\t\tSemimajor axis: {:e} meters", earth.get_orbit().get_sMa());
    println!("\t\tEccentricity: {}", earth.get_orbit().get_ecc());
    println!("\t\tApoapsis: {:e} meters", earth.get_orbit().get_apoapsis());
    println!("\t\tPeriapsis: {:e} meters", earth.get_orbit().get_periapsis());
    println!("\t\tOrbital period: {} days", earth.get_orbit().get_orb_period()/earth.get_orbit().get_day());
    println!("\t\tDay length: {} hours", earth.get_orbit().get_day()/3_600_f64);
    println!("\t\tAxial tilt: {}°", rad_to_deg(earth.get_orbit().get_ax_tilt()));
    println!("\tAtmosphere:");
    println!("\t\tPressure: {} Pa", earth.get_atmosphere().get_pressure());
    println!("\t\tCarbon dioxide (CO₂): {}%", earth.get_atmosphere().get_co2());
    println!("\t\tCarbon monoxide (CO): {}%", earth.get_atmosphere().get_co());
    println!("\t\tNitrogen (N₂): {}%", earth.get_atmosphere().get_n2());
    println!("\t\tOxygen (O₂): {}%", earth.get_atmosphere().get_o2());
    println!("\t\tArgon (Ar): {}%", earth.get_atmosphere().get_ar());
    println!("\t\tSulfur dioxide (SO₂): {}%", earth.get_atmosphere().get_so2());
    println!("\t\tNeon (Ne): {}%", earth.get_atmosphere().get_ne());
    println!("\t\tMethane (CH₄): {}%", earth.get_atmosphere().get_ch4());
    println!("\t\tHelium (He): {}%", earth.get_atmosphere().get_he());
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f64::consts::PI;
    use super::consts::*;

    #[test]
    fn it_rad_to_deg() {
        assert_eq!(360_f64, rad_to_deg(2_f64*PI));
    }

    #[test]
    fn it_deg_to_rad() {
        assert_eq!(2_f64*PI, deg_to_rad(360_f64));
    }

    #[test]
    fn it_constants() {
        assert_eq!(1.9884E+30_f64, SUN_MASS);
        assert_eq!(6.96E+8_f64, SUN_RADIUS);
        assert_eq!(3.846E+26_f64, SUN_LUMINOSITY);

        assert_eq!(6.67428e-11_f64, G);
        assert_eq!(299_792_458_f64, C);
        assert_eq!(5.670373E-8_f64, BOLTZ)
    }
}
<|endoftext|>