<commit_before>use std::fmt::{self, Write, Debug, Formatter};
use std::mem;

use gtk::signal::Inhibit;
use gdk::EventKey;

use logic::Token;

pub struct Line {
	/// The line number of the proof, starting at 1.
	no: usize,
	/// A step of the proof. e.g. (P^Q)->P. This is a vector of tokens that can be invalid.
	step: Vec<Token>,
	/// A string representing the method of the proof. This is guarenteed to be in the format
	/// <methodName> + <space> + <derivedFromLines>
	method: String,
	//
	deps: Vec<usize>,
}
impl Line {
	/// Constructs an empty line
	pub fn new(no: usize) -> Line {
		Line {
			no: no,
			step: Vec::new(),
			method: String::new(),
			deps: Vec::new(),
		}
	}
	/// Gets the line number of the proof
	pub fn no(&self) -> usize {
		self.no
	}
	/// Gets the tokens that represent a step of the proof
	pub fn step(&self) -> &[Token] {
		&self.step
	}
	/// Gets a string that represents a method of the proof
	pub fn method(&self) -> &str {
		&self.method
	}

	pub fn fmt_cursor(&self, f: &mut Formatter, c: &Cursor) -> Result<(), fmt::Error> {
		let mut step_str = String::with_capacity(self.step.len() + 16);
		if !f.alternate() {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{}", t));
			}
		} else {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{:#}", t));
			}
		}
		if c.no == self.no && c.col == Col::Step && c.i == self.step.len() {
			step_str.push('|');
		}
		let mut dep_str = String::with_capacity(self.deps.len() * 2);
		for (i, dep) in self.deps.iter().enumerate() {
			try!(write!(dep_str, "{}", dep));
			if i < self.deps.len() - 1 {
				dep_str.push_str(", ")
			}
		}
		f.pad(&format!("{}.\t{}\t{}\t{{{}}}", self.no, step_str, self.method, dep_str))
	}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Col {
	Step,
	Method,
}
pub struct Cursor {
	/// Line number
	no: usize,
	/// Column
	col: Col,
	/// Index of token/string
	i: usize,
}
impl Cursor {
	pub fn new(no: usize) -> Cursor {
		Cursor {
			no: no,
			col: Col::Step,
			i: 0,
		}
	}
	pub fn right(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { self = Cursor::new(0); return Err(()); },
		};
		self.i += 1;
		match self.col {
			Col::Step => {
				if self.i > l.step().len() {
					self.col = Col::Method;
					self.i = 0;
				}
				Ok(())
			}
			Col::Method => {
				if self.i > l.method().len() {
					if self.no < lines.len() {
						self.no += 1;
						self.col = Col::Step;
						self.i = 0;
						Ok(())
					} else {
						Err(())
					}
				} else {
					Ok(())
				}
			}
		}
	}
	pub fn left(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { self = Cursor::new(0); return Err(()); },
		};

		if self.i == 0 {
			match self.col {
				Col::Step => {
					if self.no > 1 {
						self.no -= 1;
						self.col = Col::Method;
						self.i = match lines.get(self.no) {
							Some(l) => l.method().len(),
							None    => { self = Cursor::new(0); return Err(()); },
						}
					}
				}
				Col::Method => {
					self.col = Col::Step;
					self.i = l.step().len()
				}
			}
		} else {
			self.i -= 1;
		}
	}
}

pub struct Editor {
	lines: Vec<Line>,
	cursor: Cursor,
}

impl<'a> Editor {
	/// Constructs a new editor
	pub fn new() -> Editor {
		Editor {
			lines: vec![Line::new(1)],
			cursor: Cursor::new(1),
		}
	}
	/// Gets a ref to the line numbered `v` in the proof.
	pub fn line(&'a self, v: usize) -> Option<&'a Line> {
		self.lines.get(v - 1)
	}
	/// Gets the number of lines in the proof.
	pub fn lines(&self) -> usize {
		self.lines.len()
	}
	/// Handles the input given to it, and whether to pass the input on or not.
	pub fn handle_input(&mut self, e: &EventKey) -> Inhibit {
		use gdk::enums::key;
		use gdk::{keyval_to_unicode, keyval_name};

		let c = keyval_to_unicode(e.keyval).unwrap_or(' ');
		let name = keyval_name(e.keyval).unwrap_or(" ".to_string());
		println!("keypress: {0:#08x} : {1} : {2}", e.keyval, c, name);

		match unsafe { mem::transmute(e.keyval) } {
			key::Right => {
				let _ = self.cursor.right(&self.lines);
			},
			key::Left => {
				let _ = self.cursor.left(&self.lines);
			},
			_ => {
				return Inhibit(false);
			},
		}
		println!(" *** Editor *** \n{:?}", self);
		Inhibit(true)
	}
}
impl Debug for Editor {
	fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
		for l in self.lines.iter() {
			try!(l.fmt_cursor(f, &self.cursor))
		}
		Ok(())
	}
}
<commit_msg>Fix build issues<commit_after>use std::fmt::{self, Write, Debug, Formatter};
use std::mem;

use gtk::signal::Inhibit;
use gdk::EventKey;

use logic::Token;

pub struct Line {
	/// The line number of the proof, starting at 1.
	no: usize,
	/// A step of the proof. e.g. (P^Q)->P. This is a vector of tokens that can be invalid.
	step: Vec<Token>,
	/// A string representing the method of the proof. This is guarenteed to be in the format
	/// <methodName> + <space> + <derivedFromLines>
	method: String,
	//
	deps: Vec<usize>,
}
impl Line {
	/// Constructs an empty line
	pub fn new(no: usize) -> Line {
		Line {
			no: no,
			step: vec![Token::Not, Token::Var('P')],
			method: String::new(),
			deps: Vec::new(),
		}
	}
	/// Gets the line number of the proof
	pub fn no(&self) -> usize {
		self.no
	}
	/// Gets the tokens that represent a step of the proof
	pub fn step(&self) -> &[Token] {
		&self.step
	}
	/// Gets a string that represents a method of the proof
	pub fn method(&self) -> &str {
		&self.method
	}

	pub fn fmt_cursor(&self, f: &mut Formatter, c: &Cursor) -> Result<(), fmt::Error> {
		let mut step_str = String::with_capacity(self.step.len() + 16);
		if !f.alternate() {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{}", t));
			}
		} else {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{:#}", t));
			}
		}
		if c.no == self.no && c.col == Col::Step && c.i == self.step.len() {
			step_str.push('|');
		}
		let mut dep_str = String::with_capacity(self.deps.len() * 2);
		for (i, dep) in self.deps.iter().enumerate() {
			try!(write!(dep_str, "{}", dep));
			if i < self.deps.len() - 1 {
				dep_str.push_str(", ")
			}
		}
		f.pad(&format!("{}.\t{}\t{}\t{{{}}}", self.no, step_str, self.method, dep_str))
	}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Col {
	Step,
	Method,
}
pub struct Cursor {
	/// Line number
	no: usize,
	/// Column
	col: Col,
	/// Index of token/string
	i: usize,
}
impl Cursor {
	pub fn new(no: usize) -> Cursor {
		Cursor {
			no: no,
			col: Col::Step,
			i: 0,
		}
	}
	pub fn right(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(0); return Err(()); },
		};
		self.i += 1;
		match self.col {
			Col::Step => {
				if self.i > l.step().len() {
					self.col = Col::Method;
					self.i = 0;
				}
				Ok(())
			}
			Col::Method => {
				if self.i > l.method().len() {
					if self.no < lines.len() {
						self.no += 1;
						self.col = Col::Step;
						self.i = 0;
						Ok(())
					} else {
						Err(())
					}
				} else {
					Ok(())
				}
			}
		}
	}
	pub fn left(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(0); return Err(()); },
		};

		if self.i == 0 {
			match self.col {
				Col::Step => {
					if self.no > 1 {
						self.no -= 1;
						self.col = Col::Method;
						self.i = match lines.get(self.no) {
							Some(l) => l.method().len(),
							None    => { *self = Cursor::new(0); return Err(()); },
						};
					}
				}
				Col::Method => {
					self.col = Col::Step;
					self.i = l.step().len();
				}
			}
		} else {
			self.i -= 1;
		}
		Ok(())
	}
}

pub struct Editor {
	lines: Vec<Line>,
	cursor: Cursor,
}

impl<'a> Editor {
	/// Constructs a new editor
	pub fn new() -> Editor {
		Editor {
			lines: vec![Line::new(1)],
			cursor: Cursor::new(1),
		}
	}
	/// Gets a ref to the line numbered `v` in the proof.
	pub fn line(&'a self, v: usize) -> Option<&'a Line> {
		self.lines.get(v - 1)
	}
	/// Gets the number of lines in the proof.
	pub fn lines(&self) -> usize {
		self.lines.len()
	}
	/// Handles the input given to it, and whether to pass the input on or not.
	pub fn handle_input(&mut self, e: &EventKey) -> Inhibit {
		use gdk::enums::key;
		use gdk::{keyval_to_unicode, keyval_name};

		let c = keyval_to_unicode(e.keyval).unwrap_or(' ');
		let name = keyval_name(e.keyval).unwrap_or(" ".to_string());
		println!("keypress: {0:#08x} : {1} : {2}", e.keyval, c, name);

		match unsafe { mem::transmute(e.keyval) } {
			key::Right => {
				let _ = self.cursor.right(&self.lines);
			},
			key::Left => {
				let _ = self.cursor.left(&self.lines);
			},
			_ => {
				return Inhibit(false);
			},
		}
		println!(" *** Editor *** \n{:?}", self);
		Inhibit(true)
	}
}
impl Debug for Editor {
	fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
		for l in self.lines.iter() {
			try!(l.fmt_cursor(f, &self.cursor))
		}
		Ok(())
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate ctrlc;
extern crate env_logger;

use std::env;
use std::io::{Read, stdin};
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use std::sync::Arc;
use std::time::{Duration, Instant};

#[macro_use]
mod utils;

mod cpu;
mod dbgcore;
mod io;
mod mem;
mod hwcore;

fn from_hex(string: String) -> Result<u32, std::num::ParseIntError> {
    let slice = if string.starts_with("0x") {
        &string[2..]
    } else {
        &string[..]
    };
    u32::from_str_radix(slice, 16)
}

static SIGINT_REQUESTED: AtomicBool = ATOMIC_BOOL_INIT;

fn sigint_trap() {
    ctrlc::set_handler(|| SIGINT_REQUESTED.store(true, Ordering::SeqCst));
}

fn sigint_triggered() -> bool {
    SIGINT_REQUESTED.compare_and_swap(true, false, Ordering::SeqCst)
}

fn run_emulator(code: &Vec<u8>, load_offset: u32, entrypoint: u32) {
    let mem = hwcore::map_memory_regions();
    mem.write_buf(load_offset, code.as_slice());

    let mut hwcore = hwcore::HwCore::new(entrypoint, mem);
    let mut debugger = dbgcore::DbgCore::bind(hwcore);
    debugger.hwcore_mut().start();

    sigint_trap();
    let mut is_paused = false;
    loop {
        is_paused = {
            let triggered = sigint_triggered();
            if triggered { debugger.pause(); }
            is_paused | triggered
        };

        if is_paused {
            // Handle pause commands
            let mut input = String::new();
            stdin().read_line(&mut input).unwrap();
            match input.as_str().trim_right() {
                "r" => { debugger.resume(); is_paused = false; },
                _ => {},
            }
        } else {
            std::thread::sleep(Duration::from_millis(100));
        }
    }

    debugger.hwcore_mut().stop();
}

fn main() {
    env_logger::init().unwrap();

    let filename = env::args().nth(1).unwrap();
    let load_offset = from_hex(env::args().nth(2).unwrap()).unwrap();
    let entrypoint = from_hex(env::args().nth(3).unwrap()).unwrap();

    let mut file = std::fs::File::open(filename).unwrap();
    let file_data = file.metadata().unwrap();
    let file_size = file_data.len();

    let mut filebuf = Vec::<u8>::with_capacity(file_size as usize);

    let size = file.read_to_end(&mut filebuf).unwrap();
    info!("Reading {} bytes from input file", size);
    assert!(size == file_size as usize);

    run_emulator(&filebuf, load_offset, entrypoint);
}
<commit_msg>Add "run, regs, quit" pause commands<commit_after>#[macro_use]
extern crate log;
extern crate ctrlc;
extern crate env_logger;

use std::env;
use std::io::{Read, stdin, stdout, Write};
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use std::sync::Arc;
use std::time::{Duration, Instant};

#[macro_use]
mod utils;

mod cpu;
mod dbgcore;
mod io;
mod mem;
mod hwcore;

fn from_hex(string: String) -> Result<u32, std::num::ParseIntError> {
    let slice = if string.starts_with("0x") {
        &string[2..]
    } else {
        &string[..]
    };
    u32::from_str_radix(slice, 16)
}

static SIGINT_REQUESTED: AtomicBool = ATOMIC_BOOL_INIT;

fn sigint_trap() {
    ctrlc::set_handler(|| SIGINT_REQUESTED.store(true, Ordering::SeqCst));
}

fn sigint_triggered() -> bool {
    SIGINT_REQUESTED.compare_and_swap(true, false, Ordering::SeqCst)
}

fn run_emulator(code: &Vec<u8>, load_offset: u32, entrypoint: u32) {
    let mem = hwcore::map_memory_regions();
    mem.write_buf(load_offset, code.as_slice());

    let mut hwcore = hwcore::HwCore::new(entrypoint, mem);
    let mut debugger = dbgcore::DbgCore::bind(hwcore);
    debugger.hwcore_mut().start();

    sigint_trap();
    let mut is_paused = false;
    loop {
        is_paused = {
            let triggered = sigint_triggered();
            if triggered { debugger.pause(); }
            is_paused | triggered
        };

        if is_paused {
            // Print prompt text
            print!(" > ");
            stdout().flush();

            // Read pause command
            let mut input = String::new();
            stdin().read_line(&mut input).unwrap();

            // Handle pause command
            match input.as_str().trim_right() {
                "run" => { debugger.resume(); is_paused = false; },
                "regs" => {
                    let ctx = debugger.get_ctx();
                    for i in 0..16 {
                        println!("R{} = 0x{:08X}", i, ctx.read_reg(i));
                    }
                }
                "quit" => {
                    debugger.hwcore_mut().stop();
                    std::process::exit(0);
                }
                unk_cmd @ _ => println!("Error: Unrecognized command `{}`", unk_cmd),
            }
        } else {
            std::thread::sleep(Duration::from_millis(100));
        }
    }

    debugger.hwcore_mut().stop();
}

fn main() {
    env_logger::init().unwrap();

    let filename = env::args().nth(1).unwrap();
    let load_offset = from_hex(env::args().nth(2).unwrap()).unwrap();
    let entrypoint = from_hex(env::args().nth(3).unwrap()).unwrap();

    let mut file = std::fs::File::open(filename).unwrap();
    let file_data = file.metadata().unwrap();
    let file_size = file_data.len();

    let mut filebuf = Vec::<u8>::with_capacity(file_size as usize);

    let size = file.read_to_end(&mut filebuf).unwrap();
    info!("Reading {} bytes from input file", size);
    assert!(size == file_size as usize);

    run_emulator(&filebuf, load_offset, entrypoint);
}
<|endoftext|>


<commit_before>#![feature(proc_macro, plugin, custom_attribute, custom_derive, plugin, test)]
#![plugin(serde_derive)]

// Imports:

// -- Parsing:
extern crate serde;
extern crate serde_xml;
#[macro_use]
extern crate serde_derive;

// -- Logs:
extern crate env_logger;

// -- Network:
extern crate futures;
extern crate tokio_core;

// TODO: NEXT -> SERIALIZATION ULTIMATUM.
// TODO: mod server -> Client management, send / receive messages to clients
// TODO: mod client -> reads data given by a client, who writes back? (format? -> next)
// TODO: mod xmpp -> formatting -> implement XmlStream struct.
// TODO: mod server, client? -> Implement logging ('log') for the XML stream.

// TCP or UDP?
// TCP.

// Note on the copy(reader, writer) function, it's very simple.
// The function takes data given to reader and copies it over to writer,
// writing back whatever was written. The 'copy' might as well be called 'echo'.

// Also, in this case, when an incoming socket happens, we cannot handle the split
// without a future, since the connection will persist far longer than the
// 'for_each' iteration will, therefore it must be run asynchronously, to avoid
// only being able to handle one client at a time.

#[warn(unused_features, unused_imports)]
use std::net::SocketAddr;
use std::io::{Write, Read};
use std::str::{from_utf8};

use futures::Future;
use futures::stream::Stream;

use tokio_core::io::{copy, Io};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;

//use serde_json::*;

mod server;
mod client;
mod data;
//mod xmpp;

//use server::TctServer;

/// -- Global Constants --
static DELIMITER : u8 = b'\n' as u8;

// We're gonna read some JSON
fn main() {
    let addr = "127.0.0.1:8080".to_string().parse::<SocketAddr>().unwrap();
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let socket = TcpListener::bind(&addr, &handle).unwrap();

    let core_loop = socket.incoming().for_each(|(stream, addr)| {
        let message =
            futures::lazy(move || {
                Ok(stream.split())
            }).and_then(move |(r, w)| {
                //copy(r, Writer{ addr: addr.clone() }) // 'Connect' the streams.
                copy(r, w) // 'Connect' the streams.
            }).map(move |amt| {
                println!("Said hello to client {} at {}!", amt, addr);
            }).map_err(|e| {
                panic!("Error: {}", e);
            });

        handle.spawn(message);

        Ok(())
    });

    core.run(core_loop).unwrap();
}

<commit_msg>Now running the actual server, need to figure out infinite loop bug!<commit_after>#![feature(proc_macro, plugin, custom_attribute, custom_derive, plugin, test)]
#![plugin(serde_derive)]

// Imports:

// -- Parsing:
extern crate serde;
extern crate serde_xml as xml;
extern crate serde_json as json;
#[macro_use]
extern crate serde_derive;

// -- Logs:
extern crate env_logger;

// -- Network:
extern crate futures;
extern crate tokio_core;

// TODO: NEXT -> SERIALIZATION ULTIMATUM.
// TODO: mod server -> Client management, send / receive messages to clients
// TODO: mod client -> reads data given by a client, who writes back? (format? -> next)
// TODO: mod xmpp -> formatting -> implement XmlStream struct.
// TODO: mod server, client? -> Implement logging ('log') for the XML stream.

// TCP or UDP?
// TCP.

// Note on the copy(reader, writer) function, it's very simple.
// The function takes data given to reader and copies it over to writer,
// writing back whatever was written. The 'copy' might as well be called 'echo'.

// Also, in this case, when an incoming socket happens, we cannot handle the split
// without a future, since the connection will persist far longer than the
// 'for_each' iteration will, therefore it must be run asynchronously, to avoid
// only being able to handle one client at a time.

#[warn(unused_features, unused_imports)]
use std::net::SocketAddr;

mod server;
mod client;
mod data;

use server::TctServer;

/// -- Global Constants --
//static DELIMITER : u8 = b'\n' as u8;

// We're gonna read some JSON
fn main() {
    let addr = "127.0.0.1:8080".to_string().parse::<SocketAddr>().unwrap();

    let mut server = TctServer::new(addr);

    server.run();
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate peresil;

mod parser;
mod machine;

use std::fs::File;
use std::io::prelude::*;
use std::collections::BTreeMap;

use parser::Parser;
use machine::{Input, Output, Registers, Tile, Machine};

fn append_string(input: &mut Input, s: &str) {
    input.extend(s.chars().map(Tile::Letter));
}

fn append_zero_terminated_string(input: &mut Input, s: &str) {
    append_string(input, s);
    input.push(Tile::num(0));
}

type Level = (Input, Registers, Output);

// Copy inbox to outbox, losing duplicates
fn level_35() -> Level {
    let mut input = Vec::new();
    append_string(&mut input, "eabedebaeb");

    let mut registers = BTreeMap::new();
    registers.insert(14, Tile::num(0));

    let mut output = Vec::new();
    append_string(&mut output, "eabd");

    (input, registers, output)
}

// Given two zero-terminated words, output the word that is first in
// alphabetical order
fn level_36() -> Level {
    let mut input = Vec::new();
    append_zero_terminated_string(&mut input, "aab");
    append_zero_terminated_string(&mut input, "aaa");

    let mut registers = BTreeMap::new();
    registers.insert(23, Tile::num(0));
    registers.insert(24, Tile::num(10));

    let mut output = Vec::new();
    append_string(&mut output, "aaa");

    (input, registers, output)
}

fn level_37() -> Level {
    let input = [0, 23].iter().cloned().map(Tile::num).collect();

    let mut registers = BTreeMap::new();
    let z = [
        (0, 'e', 13),
        (3, 'c', 23),
        (10, 'p', 20),
        (13, 's', 3),
        (20, 'e', -1),
        (23, 'a', 10),
    ];
    for &(idx, c, v) in &z {
        registers.insert(idx, Tile::Letter(c));
        registers.insert(idx + 1, Tile::num(v));
    }

    let mut output = Vec::new();
    append_string(&mut output, "escapeape");

    (input, registers, output)
}

// Given numbers, output the digits of the numbers
fn level_38() -> Level {
    let input = [33, 505, 7, 979].iter().cloned().map(Tile::num).collect();

    let mut registers = BTreeMap::new();
    registers.insert(9, Tile::num(0));
    registers.insert(10, Tile::num(10));
    registers.insert(11, Tile::num(100));

    let output = [3, 3, 5, 0, 5, 7, 9, 7, 9].iter().cloned().map(Tile::num).collect();

    (input, registers, output)
}

fn report_parsing_error(s: &str, offset: usize, errors: &[parser::Error]) {
    let upto = &s[..offset];
    let leading_nl = upto.rfind("\n").map(|x| x + 1).unwrap_or(0);
    let after = &s[offset..];
    let trailing_nl = after.find("\n").map(|x| x - 1).unwrap_or(after.len()) + offset;

    let line = &s[leading_nl..trailing_nl];
    let inner_offset = offset - leading_nl;

    println!("Error occured while parsing:");
    println!("{}", line);
    for _ in 0..inner_offset { print!(" ") }
    println!("^");
    println!("{:?}", errors);
}

fn main() {
    let level = ::std::env::args().nth(1).expect("level").parse().expect("level number");
    let fname = ::std::env::args().nth(2).expect("filename");
    let mut f = File::open(fname).expect("File?");

    let mut s = String::new();
    f.read_to_string(&mut s).expect("read");

    let t = Parser::new(&s);

    let p = match t.collect() {
        Ok(p) => p,
        Err((offset, errors)) => {
            report_parsing_error(&s, offset, &errors);
            return;
        },
    };

    let (input, registers, output) = match level {
        35 => level_35(),
        36 => level_36(),
        37 => level_37(),
        38 => level_38(),
        _ => panic!("Unknown level {}", level),
    };
    let mut m = Machine::new(p, input, registers);

    match m.run() {
        Ok(..) => {
            let actual_output = m.into_output();
            println!("Program completed");
            if actual_output == output {
                println!("Output matched!");
            } else {
                println!("Output did not match");
                println!("Expected: {:?}", output);
                println!("Got:      {:?}", actual_output);
            }
        },
        Err(e) => {
            println!("Program failed");
            println!("{:?}", e);
        }
    }
}
<commit_msg>Do not lose the character before the trailing newline<commit_after>#[macro_use]
extern crate peresil;

mod parser;
mod machine;

use std::fs::File;
use std::io::prelude::*;
use std::collections::BTreeMap;

use parser::Parser;
use machine::{Input, Output, Registers, Tile, Machine};

fn append_string(input: &mut Input, s: &str) {
    input.extend(s.chars().map(Tile::Letter));
}

fn append_zero_terminated_string(input: &mut Input, s: &str) {
    append_string(input, s);
    input.push(Tile::num(0));
}

type Level = (Input, Registers, Output);

// Copy inbox to outbox, losing duplicates
fn level_35() -> Level {
    let mut input = Vec::new();
    append_string(&mut input, "eabedebaeb");

    let mut registers = BTreeMap::new();
    registers.insert(14, Tile::num(0));

    let mut output = Vec::new();
    append_string(&mut output, "eabd");

    (input, registers, output)
}

// Given two zero-terminated words, output the word that is first in
// alphabetical order
fn level_36() -> Level {
    let mut input = Vec::new();
    append_zero_terminated_string(&mut input, "aab");
    append_zero_terminated_string(&mut input, "aaa");

    let mut registers = BTreeMap::new();
    registers.insert(23, Tile::num(0));
    registers.insert(24, Tile::num(10));

    let mut output = Vec::new();
    append_string(&mut output, "aaa");

    (input, registers, output)
}

fn level_37() -> Level {
    let input = [0, 23].iter().cloned().map(Tile::num).collect();

    let mut registers = BTreeMap::new();
    let z = [
        (0, 'e', 13),
        (3, 'c', 23),
        (10, 'p', 20),
        (13, 's', 3),
        (20, 'e', -1),
        (23, 'a', 10),
    ];
    for &(idx, c, v) in &z {
        registers.insert(idx, Tile::Letter(c));
        registers.insert(idx + 1, Tile::num(v));
    }

    let mut output = Vec::new();
    append_string(&mut output, "escapeape");

    (input, registers, output)
}

// Given numbers, output the digits of the numbers
fn level_38() -> Level {
    let input = [33, 505, 7, 979].iter().cloned().map(Tile::num).collect();

    let mut registers = BTreeMap::new();
    registers.insert(9, Tile::num(0));
    registers.insert(10, Tile::num(10));
    registers.insert(11, Tile::num(100));

    let output = [3, 3, 5, 0, 5, 7, 9, 7, 9].iter().cloned().map(Tile::num).collect();

    (input, registers, output)
}

fn report_parsing_error(s: &str, offset: usize, errors: &[parser::Error]) {
    let upto = &s[..offset];
    let leading_nl = upto.rfind("\n").map(|x| x + 1).unwrap_or(0);
    let after = &s[offset..];
    let trailing_nl = after.find("\n").unwrap_or(after.len()) + offset;

    let line = &s[leading_nl..trailing_nl];
    let inner_offset = offset - leading_nl;

    println!("Error occured while parsing:");
    println!("{}", line);
    for _ in 0..inner_offset { print!(" ") }
    println!("^");
    println!("{:?}", errors);
}

fn main() {
    let level = ::std::env::args().nth(1).expect("level").parse().expect("level number");
    let fname = ::std::env::args().nth(2).expect("filename");
    let mut f = File::open(fname).expect("File?");

    let mut s = String::new();
    f.read_to_string(&mut s).expect("read");

    let t = Parser::new(&s);

    let p = match t.collect() {
        Ok(p) => p,
        Err((offset, errors)) => {
            report_parsing_error(&s, offset, &errors);
            return;
        },
    };

    let (input, registers, output) = match level {
        35 => level_35(),
        36 => level_36(),
        37 => level_37(),
        38 => level_38(),
        _ => panic!("Unknown level {}", level),
    };
    let mut m = Machine::new(p, input, registers);

    match m.run() {
        Ok(..) => {
            let actual_output = m.into_output();
            println!("Program completed");
            if actual_output == output {
                println!("Output matched!");
            } else {
                println!("Output did not match");
                println!("Expected: {:?}", output);
                println!("Got:      {:?}", actual_output);
            }
        },
        Err(e) => {
            println!("Program failed");
            println!("{:?}", e);
        }
    }
}
<|endoftext|>


<commit_before>#![deny(unused_must_use, unused_imports)]
#![deny(unused_parens, unused_variables, unused_mut)]
extern crate term;
extern crate git2;
extern crate libc;

use prompt_buffer::PromptBuffer;

use std::io::{
    Acceptor,
    Command,
    File,
    fs,
    Listener,
    process,
    stdio,
    timer,
    IoError,
    Timer
};
use std::time::Duration;
use std::io::fs::PathExtensions;
use std::io::net::pipe::{
    UnixStream,
    UnixListener,
};
use std::os;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread::Thread;
use std::collections::HashMap;

mod prompt_buffer;
mod git;
mod due_date;

fn get_prompt() -> PromptBuffer {
    let mut buf = PromptBuffer::new();
    buf.add_plugin(Box::new(due_date::DueDatePlugin::new()));
    buf.add_plugin(Box::new(git::GitPlugin::new()));

    buf
}

fn exe_changed() -> u64 {
    match os::self_exe_name() {
        Some(exe_path) => {
            match exe_path.stat() {
                Ok(s) => s.modified,
                _ => 0u64
            }
        },
        None => 0u64
    }
}

fn current_pid(pid_path: &Path) -> Result<i32, IoError> {
    let mut file = try!(File::open(pid_path));
    let contents = try!(file.read_to_string());

    match contents.parse() {
        Some(value) => Ok(value),
        None => Err(IoError::from_errno(libc::consts::os::posix88::ENOMSG as usize, true))
    }
}

macro_rules! sock_try {
    ($x:expr) => {
        match $x {
            Ok(v) => v,
            Err(_) => continue
        }
    };
}

struct PromptThread {
    send: Sender<()>,
    recv: Receiver<String>,
    death: Receiver<()>,
    path: Path,
    cached: String,
    alive: bool
}

impl PromptThread {
    fn new(path: Path) -> PromptThread {
        let (tx_notify, rx_notify) = mpsc::channel();
        let (tx_prompt, rx_prompt) = mpsc::channel();
        let (tx_death, rx_death) = mpsc::channel();

        let p = path.clone();
        Thread::spawn(move || {
            let mut prompt = get_prompt();
            prompt.set_path(p);
            let mut timer = Timer::new().unwrap();

            loop {
                let timeout = timer.oneshot(Duration::minutes(10));

                select! {
                    _ = rx_notify.recv() => {
                        tx_prompt.send(prompt.to_string()).unwrap();
                    },
                    _ = timeout.recv() => {
                        // Assume someone is listening for my death
                        // Otherwise it doesn't matter
                        tx_death.send(()).unwrap();
                        break;
                    }
                }
            }
        });

        PromptThread {
            send: tx_notify,
            recv: rx_prompt,
            death: rx_death,
            path: path,
            cached: get_prompt().to_string_ext(true),
            alive: true
        }
    }

    fn is_alive(&mut self) -> bool {
        if self.death.try_recv().is_ok() {
            self.alive = false;
        }

        self.alive
    }

    fn revive(&mut self) {
        *self = PromptThread::new(self.path.clone());
    }

    fn get(&mut self) -> String {
        if !self.is_alive() {
            self.revive();
        }

        self.send.send(()).unwrap();

        let mut timer = Timer::new().unwrap();
        let timeout = timer.oneshot(Duration::milliseconds(100));

        loop {
            let resp = self.recv.try_recv();

            if resp.is_ok() {
                // We got a good response
                let mut text = resp.unwrap();

                loop {
                    match self.recv.try_recv() {
                        Ok(t) => text = t,
                        Err(_) => break
                    }
                }

                self.cached = text;
                return self.cached.clone();
            }

            // We ran out of time!
            if timeout.try_recv().is_ok() {
                return self.cached.clone();
            }
        }
    }
}

fn main() {
    let stdout_path = Path::new("/var/log/megaprompt/current.out");
    let stderr_path = Path::new("/var/log/megaprompt/current.err");
    let pid_path = Path::new("/var/log/megaprompt/current.pid");
    let socket_path = Path::new("/tmp/megaprompt-socket");

    let args = os::args();
    if args.len() > 1 { // Daemon process
        stdio::set_stdout(Box::new(File::create(&stdout_path)));
        stdio::set_stderr(Box::new(File::create(&stderr_path)));

        let last_modified = exe_changed();
        let mut threads: HashMap<Path, PromptThread> = HashMap::new();

        if socket_path.exists() {
            fs::unlink(&socket_path).unwrap();
        }

        let stream = match UnixListener::bind(&socket_path) {
            Err(_) => panic!("Failed to bind to socket"),
            Ok(stream) => stream
        };

        for mut connection in stream.listen().incoming() {
            let c = &mut connection;

            let output = Path::new(sock_try!(c.read_to_string()));
            println!("Preparing to respond to for {}", output.display());

            let keys: Vec<Path> = threads.keys().map(|x| { x.clone() }).collect();
            for path in keys.iter() {
                if !threads.get_mut(path).unwrap().is_alive() {
                    println!("- Remove thread {}", path.display());
                    threads.remove(path);
                }
            }

            if !threads.contains_key(&output) {
                println!("+ Add thread {}", output.display());
                threads.insert(output.clone(), PromptThread::new(output.clone()));
            }

            for path in threads.keys() {
                println!("* Active thread {}", path.display());
            }

            let mut thr = threads.get_mut(&output).unwrap();

            sock_try!(write!(c, "{}", thr.get()));

            println!("");

            if last_modified != exe_changed() {
                sock_try!(write!(c, "♻  "));
                return;
            }
        }
    } else {
        let current_pid = current_pid(&pid_path).ok().unwrap_or(-1);

        match process::Process::kill(current_pid, 0) {
            Err(_) => {
                // We need to start up the daemon again
                let child = Command::new(args.get(0).as_slice()[0])
                    .arg("daemon")
                    .detached().spawn().unwrap();

                let mut f = match File::create(&pid_path) {
                    Ok(f) => f,
                    Err(_) => panic!("Unable to open pid file")
                };

                write!(&mut f, "{}", child.id()).unwrap();

                println!("Spawned child {}", child.id());

                child.forget();

                timer::sleep(Duration::milliseconds(10));
            }
            _ => {}
        }

        let mut stream = match UnixStream::connect(&socket_path) {
            Err(_) => {
                println!("Can't connect");
                get_prompt().print();
                return;
            },
            Ok(stream) => stream
        };

        write!(&mut stream, "{}", os::make_absolute(&Path::new(".")).unwrap().display()).unwrap();
        stream.close_write().unwrap();
        stream.set_read_timeout(Some(200));
        match stream.read_to_string() {
            Ok(s) => println!("{}", s),
            Err(_) => {
                println!("Response too slow");
                get_prompt().print_fast();
                return;
            }
        }
    }
}
<commit_msg>Add name to thread<commit_after>#![deny(unused_must_use, unused_imports)]
#![deny(unused_parens, unused_variables, unused_mut)]
extern crate term;
extern crate git2;
extern crate libc;

use prompt_buffer::PromptBuffer;

use std::io::{
    Acceptor,
    Command,
    File,
    fs,
    Listener,
    process,
    stdio,
    timer,
    IoError,
    Timer
};
use std::time::Duration;
use std::io::fs::PathExtensions;
use std::io::net::pipe::{
    UnixStream,
    UnixListener,
};
use std::os;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;
use std::collections::HashMap;

mod prompt_buffer;
mod git;
mod due_date;

fn get_prompt() -> PromptBuffer {
    let mut buf = PromptBuffer::new();
    buf.add_plugin(Box::new(due_date::DueDatePlugin::new()));
    buf.add_plugin(Box::new(git::GitPlugin::new()));

    buf
}

fn exe_changed() -> u64 {
    match os::self_exe_name() {
        Some(exe_path) => {
            match exe_path.stat() {
                Ok(s) => s.modified,
                _ => 0u64
            }
        },
        None => 0u64
    }
}

fn current_pid(pid_path: &Path) -> Result<i32, IoError> {
    let mut file = try!(File::open(pid_path));
    let contents = try!(file.read_to_string());

    match contents.parse() {
        Some(value) => Ok(value),
        None => Err(IoError::from_errno(libc::consts::os::posix88::ENOMSG as usize, true))
    }
}

macro_rules! sock_try {
    ($x:expr) => {
        match $x {
            Ok(v) => v,
            Err(_) => continue
        }
    };
}

struct PromptThread {
    send: Sender<()>,
    recv: Receiver<String>,
    death: Receiver<()>,
    path: Path,
    cached: String,
    alive: bool
}

impl PromptThread {
    fn new(path: Path) -> PromptThread {
        let (tx_notify, rx_notify) = mpsc::channel();
        let (tx_prompt, rx_prompt) = mpsc::channel();
        let (tx_death, rx_death) = mpsc::channel();

        let p = path.clone();
        thread::Builder::new().name(format!("{}", path.display())).spawn(move || {
            let mut prompt = get_prompt();
            prompt.set_path(p);
            let mut timer = Timer::new().unwrap();

            loop {
                let timeout = timer.oneshot(Duration::minutes(10));

                select! {
                    _ = rx_notify.recv() => {
                        tx_prompt.send(prompt.to_string()).unwrap();
                    },
                    _ = timeout.recv() => {
                        // Assume someone is listening for my death
                        // Otherwise it doesn't matter
                        tx_death.send(()).unwrap();
                        break;
                    }
                }
            }
        });

        PromptThread {
            send: tx_notify,
            recv: rx_prompt,
            death: rx_death,
            path: path,
            cached: get_prompt().to_string_ext(true),
            alive: true
        }
    }

    fn is_alive(&mut self) -> bool {
        if self.death.try_recv().is_ok() {
            self.alive = false;
        }

        self.alive
    }

    fn revive(&mut self) {
        *self = PromptThread::new(self.path.clone());
    }

    fn get(&mut self) -> String {
        if !self.is_alive() {
            self.revive();
        }

        self.send.send(()).unwrap();

        let mut timer = Timer::new().unwrap();
        let timeout = timer.oneshot(Duration::milliseconds(100));

        loop {
            let resp = self.recv.try_recv();

            if resp.is_ok() {
                // We got a good response
                let mut text = resp.unwrap();

                loop {
                    match self.recv.try_recv() {
                        Ok(t) => text = t,
                        Err(_) => break
                    }
                }

                self.cached = text;
                return self.cached.clone();
            }

            // We ran out of time!
            if timeout.try_recv().is_ok() {
                return self.cached.clone();
            }
        }
    }
}

fn main() {
    let stdout_path = Path::new("/var/log/megaprompt/current.out");
    let stderr_path = Path::new("/var/log/megaprompt/current.err");
    let pid_path = Path::new("/var/log/megaprompt/current.pid");
    let socket_path = Path::new("/tmp/megaprompt-socket");

    let args = os::args();
    if args.len() > 1 { // Daemon process
        stdio::set_stdout(Box::new(File::create(&stdout_path)));
        stdio::set_stderr(Box::new(File::create(&stderr_path)));

        let last_modified = exe_changed();
        let mut threads: HashMap<Path, PromptThread> = HashMap::new();

        if socket_path.exists() {
            fs::unlink(&socket_path).unwrap();
        }

        let stream = match UnixListener::bind(&socket_path) {
            Err(_) => panic!("Failed to bind to socket"),
            Ok(stream) => stream
        };

        for mut connection in stream.listen().incoming() {
            let c = &mut connection;

            let output = Path::new(sock_try!(c.read_to_string()));
            println!("Preparing to respond to for {}", output.display());

            let keys: Vec<Path> = threads.keys().map(|x| { x.clone() }).collect();
            for path in keys.iter() {
                if !threads.get_mut(path).unwrap().is_alive() {
                    println!("- Remove thread {}", path.display());
                    threads.remove(path);
                }
            }

            if !threads.contains_key(&output) {
                println!("+ Add thread {}", output.display());
                threads.insert(output.clone(), PromptThread::new(output.clone()));
            }

            for path in threads.keys() {
                println!("* Active thread {}", path.display());
            }

            let mut thr = threads.get_mut(&output).unwrap();

            sock_try!(write!(c, "{}", thr.get()));

            println!("");

            if last_modified != exe_changed() {
                sock_try!(write!(c, "♻  "));
                return;
            }
        }
    } else {
        let current_pid = current_pid(&pid_path).ok().unwrap_or(-1);

        match process::Process::kill(current_pid, 0) {
            Err(_) => {
                // We need to start up the daemon again
                let child = Command::new(args.get(0).as_slice()[0])
                    .arg("daemon")
                    .detached().spawn().unwrap();

                let mut f = match File::create(&pid_path) {
                    Ok(f) => f,
                    Err(_) => panic!("Unable to open pid file")
                };

                write!(&mut f, "{}", child.id()).unwrap();

                println!("Spawned child {}", child.id());

                child.forget();

                timer::sleep(Duration::milliseconds(10));
            }
            _ => {}
        }

        let mut stream = match UnixStream::connect(&socket_path) {
            Err(_) => {
                println!("Can't connect");
                get_prompt().print();
                return;
            },
            Ok(stream) => stream
        };

        write!(&mut stream, "{}", os::make_absolute(&Path::new(".")).unwrap().display()).unwrap();
        stream.close_write().unwrap();
        stream.set_read_timeout(Some(200));
        match stream.read_to_string() {
            Ok(s) => println!("{}", s),
            Err(_) => {
                println!("Response too slow");
                get_prompt().print_fast();
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate rustbox;
extern crate docopt;
extern crate iota;

#[cfg(not(test))] use std::io::stdio;
#[cfg(not(test))] use docopt::Docopt;
#[cfg(not(test))] use iota::{
    Editor, Input,
    StandardMode, NormalMode,
    RustboxFrontend, Mode
};
#[cfg(not(test))] use rustbox::{InitOption, RustBox};
#[cfg(not(test))] static USAGE: &'static str = "
Usage: iota [<filename>] [options]
       iota --help

Options:
    --vi           Start Iota with vi-like modes
    -h, --help     Show this message.
";

#[derive(RustcDecodable, Show)]
struct Args {
    arg_filename: Option<String>,
    flag_vi: bool,
    flag_help: bool,
}

#[cfg(not(test))]
fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    // editor source - either a filename or stdin
    let source = if stdio::stdin_raw().isatty() {
        Input::Filename(args.arg_filename)
    } else {
        Input::Stdin(stdio::stdin())
    };

    // RustBox options
    let options = [
        if stdio::stderr_raw().isatty() { Some(InitOption::BufferStderr) } else { None },
    ];

    // initialise the frontend
    let rb = RustBox::init(&options).unwrap();
    let frontend = RustboxFrontend::new(&rb);

    // initialise the editor mode
    let mode: Box<Mode> = if args.flag_vi {
        Box::new(NormalMode::new())
    } else {
         Box::new(StandardMode::new())
    };

    // start the editor
    let mut editor = Editor::new(source, mode, frontend);
    editor.start();
}
<commit_msg>Use rustbox InputMode::Alt<commit_after>#![allow(unstable)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate rustbox;
extern crate docopt;
extern crate iota;

#[cfg(not(test))] use std::io::stdio;
#[cfg(not(test))] use docopt::Docopt;
#[cfg(not(test))] use iota::{
    Editor, Input,
    StandardMode, NormalMode,
    RustboxFrontend, Mode
};
#[cfg(not(test))] use rustbox::{InitOption, RustBox, InputMode};
#[cfg(not(test))] static USAGE: &'static str = "
Usage: iota [<filename>] [options]
       iota --help

Options:
    --vi           Start Iota with vi-like modes
    -h, --help     Show this message.
";

#[derive(RustcDecodable, Show)]
struct Args {
    arg_filename: Option<String>,
    flag_vi: bool,
    flag_help: bool,
}

#[cfg(not(test))]
fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    // editor source - either a filename or stdin
    let source = if stdio::stdin_raw().isatty() {
        Input::Filename(args.arg_filename)
    } else {
        Input::Stdin(stdio::stdin())
    };

    // RustBox options
    let options = [
        if stdio::stderr_raw().isatty() { Some(InitOption::BufferStderr) } else { None },
    ];

    // initialise the frontend
    let rb = RustBox::init(&options).unwrap();
    // TODO: perhaps move this to options above - will require rustbox change
    rb.set_input_mode(InputMode::Alt);

    let frontend = RustboxFrontend::new(&rb);

    // initialise the editor mode
    let mode: Box<Mode> = if args.flag_vi {
        Box::new(NormalMode::new())
    } else {
         Box::new(StandardMode::new())
    };

    // start the editor
    let mut editor = Editor::new(source, mode, frontend);
    editor.start();
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

mod game;
mod screen;
mod object;
mod events;

fn main() {
    let mut game = game::Game::new();
    game.run();
}
<commit_msg>Events module has been removed from main<commit_after>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

mod game;
mod screen;
mod object;

fn main() {
    let mut game = game::Game::new();
    game.run();
}
<|endoftext|>


<commit_before>fn main() {
    let x = 5;
    let y = if x == 5 {50} else {60};
    println!("x = {}; y = {};", x, y);
}
<commit_msg>tuples<commit_after>fn main() {
    let (x,y) = (1,2);
    println!("x,y=({},{})", x,y);
}

<|endoftext|>


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

use macroquad::prelude::*;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Colour {
    Red,
    Yellow,
    Green,
    LightBrown,
    Purple,
    Cyan,
    Blue,
    Fuchsia,
}

struct Grid {
    number_of_rows: u8,
    number_of_columns: u8,

    cells: Vec<Colour>,
}

struct Position {
    row: u8,
    column: u8,
}

struct ConnectedComponent {
    colour: Colour,
    cells: Vec<Position>,
}

struct Graph {
    neighours: HashMap<ConnectedComponent, Vec<ConnectedComponent>>,
}

#[macroquad::main("BasicShapes")]
async fn main() {
    loop {
        clear_background(RED);

        draw_line(40.0, 40.0, 100.0, 200.0, 15.0, BLUE);
        draw_rectangle(screen_width() / 2.0 - 60.0, 100.0, 120.0, 60.0, GREEN);
        draw_circle(screen_width() - 30.0, screen_height() - 30.0, 15.0, YELLOW);
        draw_text("HELLO", 20.0, 20.0, 20.0, DARKGRAY);

        next_frame().await
    }
}
<commit_msg>Add function to generate a grid<commit_after>use std::collections::HashMap;

use macroquad::prelude::*;
use macroquad::rand::gen_range;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Colour {
    Red,
    Yellow,
    Green,
    LightBrown,
    Purple,
    Cyan,
    Blue,
    Fuchsia,
}

const AllColours: [Colour; 8] = [
    Colour::Red,
    Colour::Yellow,
    Colour::Green,
    Colour::LightBrown,
    Colour::Purple,
    Colour::Cyan,
    Colour::Blue,
    Colour::Fuchsia,
];

struct Grid {
    number_of_rows: u8,
    number_of_columns: u8,

    cells: Vec<Colour>,
}

impl Grid {
    fn generate(size: usize) -> Self {
        let mut cells = vec![Colour::Red; size*size];
        for i in 0..size {
            for j in 0..size {
                cells[size * i + j] = AllColours[gen_range(0, AllColours.len())];
            }
        }

        Self {
            number_of_columns: size as u8,
            number_of_rows: size as u8,
            cells,
        }
    }
}

struct Position {
    row: u8,
    column: u8,
}

struct ConnectedComponent {
    colour: Colour,
    cells: Vec<Position>,
}

struct Graph {
    neighours: HashMap<ConnectedComponent, Vec<ConnectedComponent>>,
}

#[macroquad::main("BasicShapes")]
async fn main() {
    loop {
        clear_background(RED);

        draw_line(40.0, 40.0, 100.0, 200.0, 15.0, BLUE);
        draw_rectangle(screen_width() / 2.0 - 60.0, 100.0, 120.0, 60.0, GREEN);
        draw_circle(screen_width() - 30.0, screen_height() - 30.0, 15.0, YELLOW);
        draw_text("HELLO", 20.0, 20.0, 20.0, DARKGRAY);

        next_frame().await
    }
}
<|endoftext|>


<commit_before>extern crate bufstream;
extern crate rand;
extern crate time;

use std::cmp::Ordering;
use std::env;
use std::fs::File;
use std::io;
use std::io::{Write, BufRead, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::Arc;
use std::thread;

use bufstream::BufStream;
use rand::Rng;

/// Attempt to write to a `TcpStream` and flush it
///
/// # Failures
///
/// Returns an Err if any errors occur during writing and flushing
fn send_line(stream: &mut BufStream<TcpStream>, message: &str) -> Result<(), io::Error> {
    try!(stream.write(format!("{}\n", message).as_bytes()));
    try!(stream.flush());
    Ok(())
}

/// Handles a single connection
///
/// # Panics
///
/// Any errors writing to or flushing the stream result in a panic.
/// Additionally, a panic also occurs if we can't get the address of our peer.
/// Lots of things can throw panics here, since it only penalises that particular connection.
fn handle_client(stream: TcpStream, words: Arc<Vec<String>>) {

    let remote = stream.peer_addr().unwrap().to_string();
    let mut stream = BufStream::new(stream);

    // We want a trivial way to identify winners
    send_line(&mut stream, "TWITTER HANDLE PLZ").unwrap();

    let mut handle = String::new();
    stream.read_line(&mut handle).unwrap();
    let handle = handle.trim();

    // Get ourselves a random word for this connection
    let idx = rand::thread_rng().gen_range(0, words.len());
    let ref my_word = words[idx];
    println!("[{} | {}] WORD {}", remote, handle, my_word);

    let begin_msg = format!("HELLO {}; BEGIN GUESSING THE WORD", handle);
    send_line(&mut stream, &begin_msg[..]).unwrap();

    let start_time = time::precise_time_s();

    let mut success = false;
    loop {

        let mut input = String::new();
        let len = stream.read_line(&mut input).unwrap();
        // Ghetto EOF detection
        if len == 0 { break; }

        input = input.trim().to_string();

        let output = match input.cmp(&my_word) {
            Ordering::Less    => "<",
            Ordering::Greater => ">",
            Ordering::Equal   => {
                success = true;
                "="
            }
        };
        send_line(&mut stream, output).unwrap();

        if success {
            break;
        } else {
            // 100ms delay between guesses
            thread::sleep_ms(100);
        }

    }

    let end_time = time::precise_time_s();
    let status: &str;
    if success {
        status = "SUCCESS";
    } else {
        status = "FAIL";
    }

    // Milliseconds FTW
    let diff = (end_time - start_time) * 1000f64;
    println!("[{} | {}] {} TIME {:.3}", remote, handle, status, diff);
}

fn main() {

    let port = match env::args().nth(1) {
        Some(port) => port,
        None => "5000".to_owned(),
    };

    let dict_file = match env::args().nth(2) {
        Some(dict_file) => dict_file,
        None => "./dictionary".to_owned(),
    };

    let listen_addr: &str = &format!("0.0.0.0:{}", port);
    let dict_file = Path::new(&dict_file[..]);

    let dict = File::open(&dict_file).unwrap();
    let dict = BufReader::new(dict);
    let mut words : Vec<String> = vec![];
    for word in dict.lines() {
        words.push(word.unwrap());
    }
    println!("[sys] Loaded {} words.", words.len());

    let shared_words = Arc::new(words);

    let listener = TcpListener::bind(listen_addr).unwrap();
    println!("[sys] Listening on {}.", listen_addr);

    for stream in listener.incoming() {

        match stream {
            Err(why) => {
                println!("[ERR] {:?}", why);
                continue;
            },
            Ok(stream) => {

                let remote = match stream.peer_addr() {
                    Err(why) => {
                        println!("[ERR] {:?}", why);
                        continue;
                    },
                    Ok(remote) => remote.to_string(),
                };
                println!("[sys] NEW {}", remote);

                let my_words = shared_words.clone();
                match thread::Builder::new().name(remote).spawn(move || {
                    handle_client(stream, my_words);
                }) {
                    Err(why) => {
                        println!("[ERR] {:?}", why);
                        continue;
                    },
                    Ok(_) => {},
                }

            }
        }

    }

}
<commit_msg>Convert send_line to a macro.<commit_after>extern crate bufstream;
extern crate rand;
extern crate time;

use std::cmp::Ordering;
use std::env;
use std::fs::File;
use std::io::{Write, BufRead, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::Arc;
use std::thread;

use bufstream::BufStream;
use rand::Rng;

/// Attempt to write to a `TcpStream` and flush it
macro_rules! send_line {
    ($stream:ident, $message:expr) => (
        let _ = $stream.write(format!("{}\n", $message).as_bytes()).unwrap();
        $stream.flush().unwrap();
    );
}

/// Handles a single connection
///
/// # Panics
///
/// Any errors writing to or flushing the stream result in a panic.
/// Additionally, a panic also occurs if we can't get the address of our peer.
/// Lots of things can throw panics here, since it only penalises that particular connection.
fn handle_client(stream: TcpStream, words: Arc<Vec<String>>) {

    let remote = stream.peer_addr().unwrap().to_string();
    let mut stream = BufStream::new(stream);

    // We want a trivial way to identify winners
    send_line!(stream, "TWITTER HANDLE PLZ");

    let mut handle = String::new();
    stream.read_line(&mut handle).unwrap();
    let handle = handle.trim();

    // Get ourselves a random word for this connection
    let idx = rand::thread_rng().gen_range(0, words.len());
    let ref my_word = words[idx];
    println!("[{} | {}] WORD {}", remote, handle, my_word);

    let begin_msg = format!("HELLO {}; BEGIN GUESSING THE WORD", handle);
    send_line!(stream, &begin_msg[..]);

    let start_time = time::precise_time_s();

    let mut success = false;
    loop {

        let mut input = String::new();
        let len = stream.read_line(&mut input).unwrap();
        // Ghetto EOF detection
        if len == 0 { break; }

        input = input.trim().to_string();

        let output = match input.cmp(&my_word) {
            Ordering::Less    => "<",
            Ordering::Greater => ">",
            Ordering::Equal   => {
                success = true;
                "="
            }
        };
        send_line!(stream, output);

        if success {
            break;
        } else {
            // 100ms delay between guesses
            thread::sleep_ms(100);
        }

    }

    let end_time = time::precise_time_s();
    let status: &str;
    if success {
        status = "SUCCESS";
    } else {
        status = "FAIL";
    }

    // Milliseconds FTW
    let diff = (end_time - start_time) * 1000f64;
    println!("[{} | {}] {} TIME {:.3}", remote, handle, status, diff);
}

fn main() {

    let port = match env::args().nth(1) {
        Some(port) => port,
        None => "5000".to_owned(),
    };

    let dict_file = match env::args().nth(2) {
        Some(dict_file) => dict_file,
        None => "./dictionary".to_owned(),
    };

    let listen_addr: &str = &format!("0.0.0.0:{}", port);
    let dict_file = Path::new(&dict_file[..]);

    let dict = File::open(&dict_file).unwrap();
    let dict = BufReader::new(dict);
    let mut words : Vec<String> = vec![];
    for word in dict.lines() {
        words.push(word.unwrap());
    }
    println!("[sys] Loaded {} words.", words.len());

    let shared_words = Arc::new(words);

    let listener = TcpListener::bind(listen_addr).unwrap();
    println!("[sys] Listening on {}.", listen_addr);

    for stream in listener.incoming() {

        match stream {
            Err(why) => {
                println!("[ERR] {:?}", why);
                continue;
            },
            Ok(stream) => {

                let remote = match stream.peer_addr() {
                    Err(why) => {
                        println!("[ERR] {:?}", why);
                        continue;
                    },
                    Ok(remote) => remote.to_string(),
                };
                println!("[sys] NEW {}", remote);

                let my_words = shared_words.clone();
                match thread::Builder::new().name(remote).spawn(move || {
                    handle_client(stream, my_words);
                }) {
                    Err(why) => {
                        println!("[ERR] {:?}", why);
                        continue;
                    },
                    Ok(_) => {},
                }

            }
        }

    }

}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate regex;
extern crate getopts;
extern crate ansi_term;

use std::env;
use std::path::Path;
use std::io::Write;
use std::process;
use std::error::Error;

use walkdir::{WalkDir, DirEntry, WalkDirIterator};
use regex::{Regex, RegexBuilder};
use getopts::Options;
use ansi_term::Colour;

struct FdOptions {
    case_sensitive: bool,
    search_full_path: bool,
    follow_links: bool,
    colored: bool
}

/// Print a search result to the console.
fn print_entry(entry: &DirEntry, path_str: &str, config: &FdOptions) {
    if config.colored {
        let style = match entry {
            e if e.path_is_symbolic_link() => Colour::Purple,
            e if e.path().is_dir()         => Colour::Cyan,
            _                              => Colour::White
        };
        println!("{}", style.paint(path_str));
    } else {
        println!("{}", path_str);
    }
}

/// Check if filename of entry starts with a dot.
fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

/// Recursively scan the given root path and search for pathnames matching the
/// pattern.
fn scan(root: &Path, pattern: &Regex, config: &FdOptions) {
    let walker = WalkDir::new(root)
                     .follow_links(config.follow_links)
                     .into_iter();

    for entry in walker.filter_entry(|e| !is_hidden(e))
                       .filter_map(|e| e.ok()) {
        if entry.path() == root {
            continue;
        }

        let path_relative =
            match entry.path().strip_prefix(root) {
                Ok(r) => r,
                Err(_) => continue
            };

        let path_str = match path_relative.to_str() {
            Some(p) => p,
            None => continue
        };

        pattern.find(path_str)
               .map(|_| print_entry(&entry, path_str, &config));
    }
}

/// Print error message to stderr and exit with status `1`.
fn error(message: &str) -> ! {
    writeln!(&mut std::io::stderr(), "{}", message)
        .expect("Failed writing to stderr");
    process::exit(1);
}

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

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help message");
    opts.optflag("s", "sensitive", "case-sensitive search (default: smart case)");
    opts.optflag("f", "full-path", "search full path (default: only filename)");
    opts.optflag("F", "follow", "follow symlinks (default: off)");
    opts.optflag("n", "no-color", "do not colorize output");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => error(e.description())
    };

    if matches.opt_present("h") {
        let brief = "Usage: fd [PATTERN]";
        print!("{}", opts.usage(&brief));
        process::exit(1);
    }

    let empty = String::new();
    let pattern = matches.free.get(0).unwrap_or(&empty);

    let current_dir_buf = match env::current_dir() {
        Ok(cd) => cd,
        Err(_) => error("Could not get current directory!")
    };
    let current_dir = current_dir_buf.as_path();

    let config = FdOptions {
        // The search will be case-sensitive if the command line flag is set or if
        // the pattern has an uppercase character (smart case).
        case_sensitive:    matches.opt_present("s") ||
                           pattern.chars().any(char::is_uppercase),
        search_full_path:  matches.opt_present("f"),
        colored:          !matches.opt_present("n"),
        follow_links:      matches.opt_present("F")
    };

    match RegexBuilder::new(pattern)
              .case_insensitive(!config.case_sensitive)
              .build() {
        Ok(re) => scan(&current_dir, &re, &config),
        Err(err) => error(err.description())
    }
}
<commit_msg>Code-cleanup<commit_after>extern crate walkdir;
extern crate regex;
extern crate getopts;
extern crate ansi_term;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::Write;
use std::path::Path;
use std::process;

use walkdir::{WalkDir, DirEntry, WalkDirIterator};
use regex::{Regex, RegexBuilder};
use getopts::Options;
use ansi_term::Colour;

struct FdOptions {
    case_sensitive: bool,
    search_full_path: bool,
    follow_links: bool,
    colored: bool
}

/// Print a search result to the console.
fn print_entry(entry: &DirEntry, path_str: &str, config: &FdOptions) {
    if config.colored {
        let style = match entry {
            e if e.path_is_symbolic_link() => Colour::Purple,
            e if e.path().is_dir()         => Colour::Cyan,
            _                              => Colour::White
        };
        println!("{}", style.paint(path_str));
    } else {
        println!("{}", path_str);
    }
}

/// Check if filename of entry starts with a dot.
fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

/// Recursively scan the given root path and search for files / pathnames
/// matching the pattern.
fn scan(root: &Path, pattern: &Regex, config: &FdOptions) {
    let walker = WalkDir::new(root)
                     .follow_links(config.follow_links)
                     .into_iter()
                     .filter_entry(|e| !is_hidden(e))
                     .filter_map(|e| e.ok())
                     .filter(|e| e.path() != root);

    for entry in walker {
        if let Ok(path_relative) = entry.path().strip_prefix(root) {
            if let Some(path_str) = path_relative.to_str() {
                let haystack = if config.search_full_path {
                                   path_str
                               } else {
                                   path_relative.file_name()
                                                .and_then(OsStr::to_str)
                                                .unwrap()
                               };
                pattern.find(haystack)
                       .map(|_| print_entry(&entry, path_str, &config));
            }
        }
    }
}

/// Print error message to stderr and exit with status `1`.
fn error(message: &str) -> ! {
    writeln!(&mut std::io::stderr(), "{}", message)
        .expect("Failed writing to stderr");
    process::exit(1);
}

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

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help message");
    opts.optflag("s", "sensitive", "case-sensitive search (default: smart case)");
    opts.optflag("f", "full-path", "search full path (default: only filename)");
    opts.optflag("F", "follow", "follow symlinks (default: off)");
    opts.optflag("n", "no-color", "do not colorize output");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => error(e.description())
    };

    if matches.opt_present("h") {
        let brief = "Usage: fd [PATTERN]";
        print!("{}", opts.usage(&brief));
        process::exit(1);
    }

    let empty = String::new();
    let pattern = matches.free.get(0).unwrap_or(&empty);

    let current_dir_buf = match env::current_dir() {
        Ok(cd) => cd,
        Err(_) => error("Could not get current directory!")
    };
    let current_dir = current_dir_buf.as_path();

    let config = FdOptions {
        // The search will be case-sensitive if the command line flag is set or if
        // the pattern has an uppercase character (smart case).
        case_sensitive:    matches.opt_present("s") ||
                           pattern.chars().any(char::is_uppercase),
        search_full_path:  matches.opt_present("f"),
        colored:          !matches.opt_present("n"),
        follow_links:      matches.opt_present("F")
    };

    match RegexBuilder::new(pattern)
              .case_insensitive(!config.case_sensitive)
              .build() {
        Ok(re) => scan(&current_dir, &re, &config),
        Err(err) => error(err.description())
    }
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate readline;

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

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

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

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

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
}

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

    for i in v {
        match *i {
            Atom::Integer(d) => result += d,
            _ => 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 default_env() -> Env {
    let mut env = Env{func_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>);

    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 {
    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(&")") => 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 eval(node: &Node, env: &mut Env) -> AtomResult {
    match node.atom {
        Atom::Nil => {
            // TODO: use the iterators
            let mut args: Vec<Atom> = vec![];
            for i in node.children.iter().skip(1) {
                let a = try!(eval(i, env));
                args.push(a);
            }

            match node.children[0].atom {
                Atom::Symbol(ref s) => {
                    if *s == "define" {
                        println!("define!");
                        return Ok(Atom::Nil);
                    }

                    match env.func_map.get(s) {
                        Some(f) => return f(&args),
                        None => return Ok(Atom::Nil)
                    }
                },
                _ => unreachable!()
            }
        },
        Atom::Integer(i) => {
            println!("an integer: {}", i);
        },
        Atom::Float(f) => {
            println!("a float: {}", f);
        },
        Atom::Symbol(ref s) => {
            println!("a symbol, {}", s);
        }
    }

    return Ok(node.atom.clone());
}

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

fn flush() {
    let out = std::io::stdout();
    let mut o = out.lock();
    o.flush().unwrap();
}

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)");

        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))");

        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]
    #[should_panic]
    fn unmatched_bracket() {
        let x = parse("(+ 1");
    }

    #[test]
    #[should_panic]
    fn eof() {
        let x = parse("");
    }
}
<commit_msg>some 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),
    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
}

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 default_env() -> Env {
    let mut env = Env{func_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>);

    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 {
    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(&")") => 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 eval(node: &Node, env: &mut Env) -> AtomResult {
    if let Atom::Nil = node.atom {
        // TODO: use the iterators
        let mut args: Vec<Atom> = vec![];
        for i in node.children.iter().skip(1) {
            let a = try!(eval(i, env));
            args.push(a);
        }

        if let Atom::Symbol(ref s) = node.children[0].atom {
            if *s == "define" {
                return Err(Error::NotImplemented)
            }

            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)");

        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))");

        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]
    #[should_panic]
    fn unmatched_bracket() {
        let x = parse("(+ 1");
    }

    #[test]
    #[should_panic]
    fn eof() {
        let x = parse("");
    }
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate libc;
extern crate time;
extern crate hyper;
extern crate rustc_serialize;

use std::path::Path;
use std::env;
use std::io::prelude::Read;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use hyper::client::{Client, Response};
use rustc_serialize::json::Json;

struct TwitchFileSystem;

impl Filesystem for TwitchFileSystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        let ts = Timespec::new(0, 0);
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o755,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0
        };
        let ttl = Timespec::new(1, 0);

        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if ino == 1 {
            if offset == 0 {
                let mut body = String::new();
                Client::new()
                    .get("https://api.twitch.tv/kraken/games/top")
                    .send()
                    .expect("Couldn't load twitch")
                    .read_to_string(&mut body);

                println!("{}", body);

                reply.add(1, 0, FileType::Directory, &Path::new("."));
                reply.add(1, 1, FileType::Directory, &Path::new(".."));
            }

            reply.ok();
        } else {
            reply.error(ENOSYS)
        }
    }
}

fn main() {
    let mountpoint = match env::args().nth(1) {
        Some(path) => path,
        None => {
            println!("Usage: {} <Mountpoint>", env::args().nth(0).unwrap());
            return;
        }
    };
    fuse::mount(TwitchFileSystem, &mountpoint, &[])
}
<commit_msg>Add listing games as directories<commit_after>extern crate fuse;
extern crate libc;
extern crate time;
extern crate hyper;
extern crate rustc_serialize;

use std::path::Path;
use std::env;
use std::io::prelude::Read;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use hyper::client::{Client, Response};
use rustc_serialize::json::Json;

struct TwitchFileSystem;

impl Filesystem for TwitchFileSystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        let ts = Timespec::new(0, 0);
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o755,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0
        };
        let ttl = Timespec::new(1, 0);

        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if offset == 0 {
            let mut body = String::new();
            Client::new()
                .get("https://api.twitch.tv/kraken/games/top")
                .send()
                .expect("Couldn't load twitch")
                .read_to_string(&mut body);

            match Json::from_str(&body) {
                Ok(data) => {
                    let games = data.find("top").unwrap().as_array().unwrap();
                    for (i, game) in games.iter().enumerate() {
                        let name = game
                            .find_path(&["game", "name"])
                            .unwrap()
                            .as_string()
                            .unwrap();
                        reply.add(1, 1 + 1 as u64,
                                  FileType::Directory,
                                  &Path::new(name));
                    }
                },
                Err(_) => println!("Twitch returned invalid json")
            }

            reply.add(1, 0, FileType::Directory, &Path::new("."));
            reply.add(1, 1, FileType::Directory, &Path::new(".."));
        }

        reply.ok();
    }
}

fn main() {
    let mountpoint = match env::args().nth(1) {
        Some(path) => path,
        None => {
            println!("Usage: {} <Mountpoint>", env::args().nth(0).unwrap());
            return;
        }
    };
    fuse::mount(TwitchFileSystem, &mountpoint, &[])
}
<|endoftext|>