<commit_before>extern crate irc;
extern crate slack;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::thread;
use std::sync::mpsc::{Sender, channel};
use std::default::Default;
use irc::client::prelude::*;
use regex::Regex;
use rustc_serialize::json;

#[derive(Debug)]
enum SlackToIrc {
    Message { to: String, msg: String },
    MeMessage { to: String, msg: String },
    Raw(String),
    Away(bool),
}

#[derive(Debug)]
enum IrcToSlack {
    Message { to: String, from: Option<String>, msg: String },
    Topic { chan: String, topic: Option<String> },
    Kick { by: Option<String>, chans: String, nicks: String, reason: Option<String> },
    Join { nick: String, chans: String },
    Part { nick: String, chans: String, reason: Option<String> },
    Quit { nick: String, reason: Option<String> },
    Nick { old_nick: String, new_nick: String },
    Mode { by: Option<String>, name: String, modes: String, params: Option<String> },
    Error(String),
}

struct SlackHandler<'a, T: 'a> {
    chan: &'a Sender<T>,
}

fn get_channel_with_id(id: &str, channels: Vec<slack::Channel>) -> Option<slack::Channel> {
    channels.into_iter().find(|channel| {
        channel.id == id
    })
}

fn get_user_with_id(id: &str, users: Vec<slack::User>) -> Option<slack::User> {
    users.into_iter().find(|user| {
        user.id == id
    })
}

fn parse_slack_text(text: &str, cli: &slack::RtmClient) -> String {
    lazy_static!{
        static ref REPLACEMENTS: Vec<(Regex, &'static str)> = vec![
            (Regex::new(r"\n|\r\n|\r").unwrap(), " "),
            (Regex::new(r"&").unwrap(), "&"),
            (Regex::new(r"<").unwrap(), "<"),
            (Regex::new(r">").unwrap(), ">"),
            (Regex::new(r"<!channel>").unwrap(), "@channel"),
            (Regex::new(r"<!group>").unwrap(), "@group"),
            (Regex::new(r"<!everyone>").unwrap(), "@everyone"),
        ];
        static ref EMOJIS: HashMap<&'static str, &'static str> = {
            let mut m = HashMap::new();
            m.insert("smile", ":)");
            m.insert("simple_smile", ":)");
            m.insert("smiley", ":-)");
            m.insert("grin", ":D");
            m.insert("wink", ";)");
            m.insert("smirk", ";)");
            m.insert("blush", ":$");
            m.insert("stuck_out_tongue", ":P");
            m.insert("stuck_out_tongue_winking_eye", ";P");
            m.insert("stuck_out_tongue_closed_eyes", "xP");
            m.insert("disappointed", ":(");
            m.insert("astonished", ":O");
            m.insert("open_mouth", ":O");
            m.insert("heart", "<3");
            m.insert("broken_heart", "</3");
            m.insert("confused", ":S");
            m.insert("angry", ">:(");
            m.insert("cry", ":,(");
            m.insert("frowning", ":(");
            m.insert("imp", "]:(");
            m.insert("innocent", "o:)");
            m.insert("joy", ":,)");
            m.insert("kissing", ":*");
            m.insert("laughing", "x)");
            m.insert("neutral_face", ":|");
            m.insert("no_mouth", ":-");
            m.insert("rage", ":@");
            m.insert("smiling_imp", "]:)");
            m.insert("sob", ":,'(");
            m.insert("sunglasses", "8)");
            m.insert("sweat", ",:(");
            m.insert("sweat_smile", ",:)");
            m.insert("unamused", ":$");
            m
        };
        static ref FUNCTIONS: Vec<(Regex, Box<Fn(&regex::Captures, &slack::RtmClient) -> String + Sync>)> = vec![
            (Regex::new(r"<#(C\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(channel) = get_channel_with_id(id, cli.get_channels()) {
                        return format!("#{}", channel.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<@(U\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(user) = get_user_with_id(id, cli.get_users()) {
                        return format!("@{}", user.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<(?!!)(\S+)>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                captures.at(1).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<!(\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                format!("<{}>", captures.at(2).or(captures.at(1)).unwrap_or("")).to_owned()
            })),
            (Regex::new(r"\:(\w+)\:").unwrap(), Box::new(|captures: &regex::Captures, _| {
                if let Some(&emoji) = EMOJIS.get(captures.at(1).unwrap()) {
                    emoji.to_owned()
                } else {
                    captures.at(0).unwrap().to_owned()
                }
            })),
        ];
    }

    let text = REPLACEMENTS.iter().fold(text.to_owned(), |text, &(ref re, replacement)| {
        re.replace_all(&text, replacement)
    });

    FUNCTIONS.iter().fold(text, |text, &(ref re, ref replacement)| {
        re.replace_all(&text, |captures: &regex::Captures| {
            replacement(captures, cli)
        })
    })
}

impl<'a> slack::EventHandler for SlackHandler<'a, SlackToIrc> {
    fn on_event(&mut self, cli: &mut slack::RtmClient, event: Result<&slack::Event, slack::Error>, _raw_json: &str) {
        let slack_user = &"TEMP_REPLACE_ME";
        let bot_channel = &"TEMP_REPLACE_ME";
        match event {
            Ok(&slack::Event::Message(ref message)) => match message {
                &slack::Message::Standard { channel: Some(ref channel), user: Some(ref user), text: Some(ref text), .. } if user == slack_user => {
                    lazy_static!{
                        static ref COMMAND_RE: Regex = Regex::new(r"^%[A-Z]{3,}\s\S").unwrap();
                        static ref PM_RE: Regex = Regex::new(r"^(\S+):\s+(.+)").unwrap();
                    }

                    let text = parse_slack_text(&text, cli);

                    if COMMAND_RE.is_match(&text) {
                        self.chan.send(SlackToIrc::Raw(text[1..].to_owned())).unwrap();
                        cli.send_message(channel, "_sent raw command_").unwrap();
                    } else if channel == bot_channel {
                        if let Some(captures) = PM_RE.captures(&text) {
                            self.chan.send(SlackToIrc::Message { to: captures.at(1).unwrap().to_owned(), msg: captures.at(2).unwrap().to_owned() }).unwrap();
                        } else {
                            cli.send_message(channel, "_no message sent, are you missing a `user: ` prefix?_").unwrap();
                        }
                    } else {
                        self.chan.send(SlackToIrc::Message { to: channel.clone(), msg: text.clone() }).unwrap();
                    }
                },
                &slack::Message::MeMessage { ref channel, ref user, ref text, .. } if user == slack_user => {
                    self.chan.send(SlackToIrc::MeMessage { to: channel.clone(), msg: text.clone() }).unwrap();
                },
                _ => (),
            },
            Ok(&slack::Event::PresenceChange { ref user, ref presence }) if user == slack_user => {
                self.chan.send(SlackToIrc::Away(presence == "active")).unwrap();
            },
            _ => (),
        }
    }

    fn on_ping(&mut self, _cli: &mut slack::RtmClient) {}

    fn on_close(&mut self, _cli: &mut slack::RtmClient) {
        println!("Disconnected from Slack");
    }

    fn on_connect(&mut self, _cli: &mut slack::RtmClient) {
        println!("Connected to Slack");
    }
}

fn make_slack_action(username: Option<String>, text: String) -> String {
    #[derive(RustcEncodable)]
    struct SlackAction {
        text: String,
        username: Option<String>,
        parse: String,
        icon_url: Option<String>,
    }

    json::encode(&SlackAction {
        text: text,
        username: username.clone(),
        parse: "full".to_owned(),
        icon_url: username.map(|username| { format!("http://api.adorable.io/avatars/48/{}.png", username) }),
    }).unwrap()
}

fn main() {
    let (slack_tx, slack_rx) = channel();
    let (irc_tx, irc_rx) = channel();

    let slack_thread = thread::Builder::new().name("slack".to_owned()).spawn(move || {
        let mut handler = SlackHandler { chan: &irc_tx };
        let mut cli = slack::RtmClient::new(&"SLACK_TOKEN_REPLACE_ME");

        cli.login_and_run(&mut handler).unwrap();

        let all_channels = ["ALL_CHANNELS_REPLACE_ME"];
        let dm_channel = "SLACK_DM_CHANNEL_TODO_REPLACE_ME";

        for msg in slack_rx {
            match msg {
                IrcToSlack::Message { to, from, msg } => {
                    let to: &str = if to.starts_with("#") {
                        dm_channel
                    } else {
                        &to
                    };

                    let msg = make_slack_action(from, msg);

                    cli.post_message(to, &msg, None).unwrap();
                },
                IrcToSlack::Topic { chan, topic } => {
                    cli.set_topic(&chan, &topic.unwrap_or("".to_owned())).unwrap();
                },
                IrcToSlack::Kick { by, chans, nicks, reason } => {
                    let by = &by.unwrap_or("server".to_owned());
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        for nick in nicks.split(",") {
                            cli.send_message(&chan, &format!("*{}* has kicked *{}* (_{}_)", by, nick, reason)).unwrap();
                        }
                    }
                },
                IrcToSlack::Join { nick, chans } => {
                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has joined", nick)).unwrap();
                    }
                },
                IrcToSlack::Part { nick, chans, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has left (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Quit { nick, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* has quit (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Nick { old_nick, new_nick } => {
                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* is now known as *{}*", old_nick, new_nick)).unwrap();
                    }
                },
                IrcToSlack::Mode { by, name, modes, params } => {
                    if name.starts_with("#") {
                        cli.send_message(&name, &format!("*{}* sets mode *{}* on _{}_", by.unwrap_or("server".to_owned()), modes, params.unwrap_or(name.clone()))).unwrap();
                    }
                },
                IrcToSlack::Error(msg) => {
                    cli.send_message(dm_channel, &msg).unwrap();
                },
            }
        }
    }).unwrap();

    let irc_thread = thread::Builder::new().name("irc".to_owned()).spawn(move || {
        let config = Config {
            nickname: Some("NICK_REPLACE_ME".to_owned()),
            server: Some("SERVER_REPLACE_ME".to_owned()),
            channels: Some(vec!["CHANNELS_REPLACE_ME".to_owned()]),
            port: Some(6697),
            use_ssl: Some(true),
            ..Default::default()
        };

        let server = IrcServer::from_config(config).unwrap();

        server.identify().unwrap();

        let server_thread = {
            let server = server.clone();
            thread::Builder::new().name("irc_server".to_owned()).spawn(move || {
                for message in server.iter() {
                    let message = message.unwrap();
                    match message.command {
                        Command::ERROR(msg) => {
                            slack_tx.send(IrcToSlack::Error(msg)).unwrap();
                        },
                        Command::PRIVMSG(to, text) | Command::NOTICE(to, text) => {
                            lazy_static!{
                                static ref ACTION_RE: Regex = Regex::new("^\x01ACTION (.+)\x01$").unwrap();
                            }

                            if ACTION_RE.is_match(&text) {
                                slack_tx.send(IrcToSlack::Message {
                                    to: to,
                                    from: message.prefix,
                                    msg: format!("_{}_", ACTION_RE.captures(&text).unwrap().at(1).unwrap())
                                }).unwrap();
                            } else {
                                slack_tx.send(IrcToSlack::Message { to: to, from: message.prefix, msg: text }).unwrap();
                            }
                        },
                        Command::TOPIC(channel, topic) => {
                            slack_tx.send(IrcToSlack::Topic { chan: channel, topic: topic }).unwrap();
                        },
                        Command::KICK(channels, users, reason) => {
                            slack_tx.send(IrcToSlack::Kick { by: message.prefix, chans: channels, nicks: users, reason: reason }).unwrap();
                        },
                        Command::JOIN(channels, _, _) => {
                            slack_tx.send(IrcToSlack::Join { nick: message.prefix.unwrap(), chans: channels }).unwrap();
                        },
                        Command::PART(channels, reason) => {
                            slack_tx.send(IrcToSlack::Part { nick: message.prefix.unwrap(), chans: channels, reason: reason }).unwrap();
                        },
                        Command::QUIT(reason) => {
                            slack_tx.send(IrcToSlack::Quit { nick: message.prefix.unwrap(), reason: reason }).unwrap();
                        },
                        Command::NICK(nick) => {
                            slack_tx.send(IrcToSlack::Nick { old_nick: message.prefix.unwrap(), new_nick: nick }).unwrap();
                        },
                        Command::MODE(name, modes, params) => {
                            slack_tx.send(IrcToSlack::Mode { by: message.prefix, name: name, modes: modes, params: params }).unwrap();
                        }
                        _ => (),
                    }
                }
            }).unwrap()
        };

        for msg in irc_rx {
            match msg {
                SlackToIrc::Message { to, msg } => {
                    server.send_privmsg(&to, &msg).unwrap();
                },
                SlackToIrc::MeMessage { to, msg } => {
                    server.send_privmsg(&to, &format!("\x01ACTION {}\x01", msg)).unwrap();
                },
                SlackToIrc::Raw(msg) => {
                    server.send(Command::Raw(msg, vec![], None)).unwrap();
                },
                SlackToIrc::Away(is_away) => {
                    server.send(Command::AWAY(Some(if is_away { " ".to_owned() } else { "".to_owned() }))).unwrap();
                },
            }
        }

        server_thread.join().unwrap();
    }).unwrap();

    slack_thread.join().unwrap();
    irc_thread.join().unwrap();
}
<commit_msg>simplify command check, any message starting with `%` will do<commit_after>extern crate irc;
extern crate slack;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::thread;
use std::sync::mpsc::{Sender, channel};
use std::default::Default;
use irc::client::prelude::*;
use regex::Regex;
use rustc_serialize::json;

#[derive(Debug)]
enum SlackToIrc {
    Message { to: String, msg: String },
    MeMessage { to: String, msg: String },
    Raw(String),
    Away(bool),
}

#[derive(Debug)]
enum IrcToSlack {
    Message { to: String, from: Option<String>, msg: String },
    Topic { chan: String, topic: Option<String> },
    Kick { by: Option<String>, chans: String, nicks: String, reason: Option<String> },
    Join { nick: String, chans: String },
    Part { nick: String, chans: String, reason: Option<String> },
    Quit { nick: String, reason: Option<String> },
    Nick { old_nick: String, new_nick: String },
    Mode { by: Option<String>, name: String, modes: String, params: Option<String> },
    Error(String),
}

struct SlackHandler<'a, T: 'a> {
    chan: &'a Sender<T>,
}

fn get_channel_with_id(id: &str, channels: Vec<slack::Channel>) -> Option<slack::Channel> {
    channels.into_iter().find(|channel| {
        channel.id == id
    })
}

fn get_user_with_id(id: &str, users: Vec<slack::User>) -> Option<slack::User> {
    users.into_iter().find(|user| {
        user.id == id
    })
}

fn parse_slack_text(text: &str, cli: &slack::RtmClient) -> String {
    lazy_static!{
        static ref REPLACEMENTS: Vec<(Regex, &'static str)> = vec![
            (Regex::new(r"\n|\r\n|\r").unwrap(), " "),
            (Regex::new(r"&").unwrap(), "&"),
            (Regex::new(r"<").unwrap(), "<"),
            (Regex::new(r">").unwrap(), ">"),
            (Regex::new(r"<!channel>").unwrap(), "@channel"),
            (Regex::new(r"<!group>").unwrap(), "@group"),
            (Regex::new(r"<!everyone>").unwrap(), "@everyone"),
        ];
        static ref EMOJIS: HashMap<&'static str, &'static str> = {
            let mut m = HashMap::new();
            m.insert("smile", ":)");
            m.insert("simple_smile", ":)");
            m.insert("smiley", ":-)");
            m.insert("grin", ":D");
            m.insert("wink", ";)");
            m.insert("smirk", ";)");
            m.insert("blush", ":$");
            m.insert("stuck_out_tongue", ":P");
            m.insert("stuck_out_tongue_winking_eye", ";P");
            m.insert("stuck_out_tongue_closed_eyes", "xP");
            m.insert("disappointed", ":(");
            m.insert("astonished", ":O");
            m.insert("open_mouth", ":O");
            m.insert("heart", "<3");
            m.insert("broken_heart", "</3");
            m.insert("confused", ":S");
            m.insert("angry", ">:(");
            m.insert("cry", ":,(");
            m.insert("frowning", ":(");
            m.insert("imp", "]:(");
            m.insert("innocent", "o:)");
            m.insert("joy", ":,)");
            m.insert("kissing", ":*");
            m.insert("laughing", "x)");
            m.insert("neutral_face", ":|");
            m.insert("no_mouth", ":-");
            m.insert("rage", ":@");
            m.insert("smiling_imp", "]:)");
            m.insert("sob", ":,'(");
            m.insert("sunglasses", "8)");
            m.insert("sweat", ",:(");
            m.insert("sweat_smile", ",:)");
            m.insert("unamused", ":$");
            m
        };
        static ref FUNCTIONS: Vec<(Regex, Box<Fn(&regex::Captures, &slack::RtmClient) -> String + Sync>)> = vec![
            (Regex::new(r"<#(C\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(channel) = get_channel_with_id(id, cli.get_channels()) {
                        return format!("#{}", channel.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<@(U\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(user) = get_user_with_id(id, cli.get_users()) {
                        return format!("@{}", user.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<(?!!)(\S+)>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                captures.at(1).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<!(\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                format!("<{}>", captures.at(2).or(captures.at(1)).unwrap_or("")).to_owned()
            })),
            (Regex::new(r"\:(\w+)\:").unwrap(), Box::new(|captures: &regex::Captures, _| {
                if let Some(&emoji) = EMOJIS.get(captures.at(1).unwrap()) {
                    emoji.to_owned()
                } else {
                    captures.at(0).unwrap().to_owned()
                }
            })),
        ];
    }

    let text = REPLACEMENTS.iter().fold(text.to_owned(), |text, &(ref re, replacement)| {
        re.replace_all(&text, replacement)
    });

    FUNCTIONS.iter().fold(text, |text, &(ref re, ref replacement)| {
        re.replace_all(&text, |captures: &regex::Captures| {
            replacement(captures, cli)
        })
    })
}

impl<'a> slack::EventHandler for SlackHandler<'a, SlackToIrc> {
    fn on_event(&mut self, cli: &mut slack::RtmClient, event: Result<&slack::Event, slack::Error>, _raw_json: &str) {
        let slack_user = &"TEMP_REPLACE_ME";
        let bot_channel = &"TEMP_REPLACE_ME";
        match event {
            Ok(&slack::Event::Message(ref message)) => match message {
                &slack::Message::Standard { channel: Some(ref channel), user: Some(ref user), text: Some(ref text), .. } if user == slack_user => {
                    lazy_static!{
                        static ref PM_RE: Regex = Regex::new(r"^(\S+):\s+(.+)").unwrap();
                    }

                    let text = parse_slack_text(&text, cli);

                    if text.starts_with("%") {
                        self.chan.send(SlackToIrc::Raw(text[1..].to_owned())).unwrap();
                        cli.send_message(channel, "_sent raw command_").unwrap();
                    } else if channel == bot_channel {
                        if let Some(captures) = PM_RE.captures(&text) {
                            self.chan.send(SlackToIrc::Message { to: captures.at(1).unwrap().to_owned(), msg: captures.at(2).unwrap().to_owned() }).unwrap();
                        } else {
                            cli.send_message(channel, "_no message sent, are you missing a `user: ` prefix?_").unwrap();
                        }
                    } else {
                        self.chan.send(SlackToIrc::Message { to: channel.clone(), msg: text.clone() }).unwrap();
                    }
                },
                &slack::Message::MeMessage { ref channel, ref user, ref text, .. } if user == slack_user => {
                    self.chan.send(SlackToIrc::MeMessage { to: channel.clone(), msg: text.clone() }).unwrap();
                },
                _ => (),
            },
            Ok(&slack::Event::PresenceChange { ref user, ref presence }) if user == slack_user => {
                self.chan.send(SlackToIrc::Away(presence == "active")).unwrap();
            },
            _ => (),
        }
    }

    fn on_ping(&mut self, _cli: &mut slack::RtmClient) {}

    fn on_close(&mut self, _cli: &mut slack::RtmClient) {
        println!("Disconnected from Slack");
    }

    fn on_connect(&mut self, _cli: &mut slack::RtmClient) {
        println!("Connected to Slack");
    }
}

fn make_slack_action(username: Option<String>, text: String) -> String {
    #[derive(RustcEncodable)]
    struct SlackAction {
        text: String,
        username: Option<String>,
        parse: String,
        icon_url: Option<String>,
    }

    json::encode(&SlackAction {
        text: text,
        username: username.clone(),
        parse: "full".to_owned(),
        icon_url: username.map(|username| { format!("http://api.adorable.io/avatars/48/{}.png", username) }),
    }).unwrap()
}

fn main() {
    let (slack_tx, slack_rx) = channel();
    let (irc_tx, irc_rx) = channel();

    let slack_thread = thread::Builder::new().name("slack".to_owned()).spawn(move || {
        let mut handler = SlackHandler { chan: &irc_tx };
        let mut cli = slack::RtmClient::new(&"SLACK_TOKEN_REPLACE_ME");

        cli.login_and_run(&mut handler).unwrap();

        let all_channels = ["ALL_CHANNELS_REPLACE_ME"];
        let dm_channel = "SLACK_DM_CHANNEL_TODO_REPLACE_ME";

        for msg in slack_rx {
            match msg {
                IrcToSlack::Message { to, from, msg } => {
                    let to: &str = if to.starts_with("#") {
                        dm_channel
                    } else {
                        &to
                    };

                    let msg = make_slack_action(from, msg);

                    cli.post_message(to, &msg, None).unwrap();
                },
                IrcToSlack::Topic { chan, topic } => {
                    cli.set_topic(&chan, &topic.unwrap_or("".to_owned())).unwrap();
                },
                IrcToSlack::Kick { by, chans, nicks, reason } => {
                    let by = &by.unwrap_or("server".to_owned());
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        for nick in nicks.split(",") {
                            cli.send_message(&chan, &format!("*{}* has kicked *{}* (_{}_)", by, nick, reason)).unwrap();
                        }
                    }
                },
                IrcToSlack::Join { nick, chans } => {
                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has joined", nick)).unwrap();
                    }
                },
                IrcToSlack::Part { nick, chans, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has left (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Quit { nick, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* has quit (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Nick { old_nick, new_nick } => {
                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* is now known as *{}*", old_nick, new_nick)).unwrap();
                    }
                },
                IrcToSlack::Mode { by, name, modes, params } => {
                    if name.starts_with("#") {
                        cli.send_message(&name, &format!("*{}* sets mode *{}* on _{}_", by.unwrap_or("server".to_owned()), modes, params.unwrap_or(name.clone()))).unwrap();
                    }
                },
                IrcToSlack::Error(msg) => {
                    cli.send_message(dm_channel, &msg).unwrap();
                },
            }
        }
    }).unwrap();

    let irc_thread = thread::Builder::new().name("irc".to_owned()).spawn(move || {
        let config = Config {
            nickname: Some("NICK_REPLACE_ME".to_owned()),
            server: Some("SERVER_REPLACE_ME".to_owned()),
            channels: Some(vec!["CHANNELS_REPLACE_ME".to_owned()]),
            port: Some(6697),
            use_ssl: Some(true),
            ..Default::default()
        };

        let server = IrcServer::from_config(config).unwrap();

        server.identify().unwrap();

        let server_thread = {
            let server = server.clone();
            thread::Builder::new().name("irc_server".to_owned()).spawn(move || {
                for message in server.iter() {
                    let message = message.unwrap();
                    match message.command {
                        Command::ERROR(msg) => {
                            slack_tx.send(IrcToSlack::Error(msg)).unwrap();
                        },
                        Command::PRIVMSG(to, text) | Command::NOTICE(to, text) => {
                            lazy_static!{
                                static ref ACTION_RE: Regex = Regex::new("^\x01ACTION (.+)\x01$").unwrap();
                            }

                            if ACTION_RE.is_match(&text) {
                                slack_tx.send(IrcToSlack::Message {
                                    to: to,
                                    from: message.prefix,
                                    msg: format!("_{}_", ACTION_RE.captures(&text).unwrap().at(1).unwrap())
                                }).unwrap();
                            } else {
                                slack_tx.send(IrcToSlack::Message { to: to, from: message.prefix, msg: text }).unwrap();
                            }
                        },
                        Command::TOPIC(channel, topic) => {
                            slack_tx.send(IrcToSlack::Topic { chan: channel, topic: topic }).unwrap();
                        },
                        Command::KICK(channels, users, reason) => {
                            slack_tx.send(IrcToSlack::Kick { by: message.prefix, chans: channels, nicks: users, reason: reason }).unwrap();
                        },
                        Command::JOIN(channels, _, _) => {
                            slack_tx.send(IrcToSlack::Join { nick: message.prefix.unwrap(), chans: channels }).unwrap();
                        },
                        Command::PART(channels, reason) => {
                            slack_tx.send(IrcToSlack::Part { nick: message.prefix.unwrap(), chans: channels, reason: reason }).unwrap();
                        },
                        Command::QUIT(reason) => {
                            slack_tx.send(IrcToSlack::Quit { nick: message.prefix.unwrap(), reason: reason }).unwrap();
                        },
                        Command::NICK(nick) => {
                            slack_tx.send(IrcToSlack::Nick { old_nick: message.prefix.unwrap(), new_nick: nick }).unwrap();
                        },
                        Command::MODE(name, modes, params) => {
                            slack_tx.send(IrcToSlack::Mode { by: message.prefix, name: name, modes: modes, params: params }).unwrap();
                        }
                        _ => (),
                    }
                }
            }).unwrap()
        };

        for msg in irc_rx {
            match msg {
                SlackToIrc::Message { to, msg } => {
                    server.send_privmsg(&to, &msg).unwrap();
                },
                SlackToIrc::MeMessage { to, msg } => {
                    server.send_privmsg(&to, &format!("\x01ACTION {}\x01", msg)).unwrap();
                },
                SlackToIrc::Raw(msg) => {
                    server.send(Command::Raw(msg, vec![], None)).unwrap();
                },
                SlackToIrc::Away(is_away) => {
                    server.send(Command::AWAY(Some(if is_away { " ".to_owned() } else { "".to_owned() }))).unwrap();
                },
            }
        }

        server_thread.join().unwrap();
    }).unwrap();

    slack_thread.join().unwrap();
    irc_thread.join().unwrap();
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Zero;

use assimp::Vector3D;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 700 * 700] = [-1.; 700 * 700];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    let light_dir = Vector3::new(0., 0., -1.);

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];

            for j in 0..3 {
                let v = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let (p1, p2) = ((v.x + 1.) * WIDTH as f32 / 2., (v.y + 1.) * HEIGHT as f32 / 2.);
                screen_coords[j as usize] = Vector3::<f32>::new(p1, (HEIGHT as f32 - p2), v.z);

                world_coords[j as usize] = v.into();
            }

            let n = (world_coords[2] - world_coords[0]).cross(world_coords[1] - world_coords[0]).normalize();
            let intensity = n.dot(light_dir);

            if intensity > 0.0 { // back-face culling
                renderer.triangle(
                    screen_coords[0],
                    screen_coords[1],
                    screen_coords[2],
                    Color::RGB(
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8
                    )
                );
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Draft<commit_after>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Zero;

use assimp::Vector3D;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 700 * 700] = [-1.; 700 * 700];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    let light_dir = Vector3::new(0., 0., -1.);

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];

            for j in 0..3 {
                let v = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let (p1, p2) = ((v.x + 1.) * WIDTH as f32 / 2., (v.y + 1.) * HEIGHT as f32 / 2.);
                screen_coords[j as usize] = Vector3::<f32>::new(p1, (HEIGHT as f32 - p2), v.z);

                world_coords[j as usize] = v.into();
            }

            let n = (world_coords[2] - world_coords[0]).cross(world_coords[1] - world_coords[0]).normalize();
            let intensity = n.dot(light_dir);

            if intensity > 0.0 { // back-face culling
                renderer.triangle(
                    screen_coords[0],
                    screen_coords[1],
                    screen_coords[2],
                    Color::RGB(
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8
                    )
                );
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate itertools;
extern crate unicode_xid;
extern crate lalrpop_util;
use clap::{Arg, App};

use std::fs::File;
use std::io::Read;
use std::io;
use std::path::Path;

mod ast;
mod parser;
mod lexer;
mod diagnostics;
mod ir;
mod codegen;

fn read_file<P: AsRef<Path>>(path: P) -> io::Result<String> {
    let mut file = File::open(path)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;
    Ok(buffer)
}

fn main() {
    let matches = App::new("Elang Compiler")
        .version("0.1")
        .author("Paul CACHEUX <paulcacheux@gmail.com>")
        .arg(Arg::with_name("ast").long("ast").help("Dump AST"))
        .arg(Arg::with_name("ir").long("ir").help("Dump IR"))
        .arg(Arg::with_name("opt")
                 .short("O")
                 .help("Activate optimizations"))
        .arg(Arg::with_name("INPUT")
                 .help("Input file")
                 .required(true)
                 .index(1))
        .get_matches();

    let input = read_file(matches.value_of("INPUT").unwrap()).expect("Can't read input file");
    let lex = lexer::Lexer::new(&input);
    let tu = match parser::parse_TranslationUnit(lex) {
        Ok(tu) => tu,
        Err(err) => {
            return diagnostics::print_diagnostic(&input, err);
        }
    };

    if matches.is_present("ast") {
        ast::printer::print_ast(&tu);
    }

    let mut tu = match ir::builder::build_translation_unit(tu) {
        Ok(tu) => tu,
        Err(err) => {
            return diagnostics::print_diagnostic(&input, err);
        }
    };

    if matches.is_present("opt") {
        ir::opt::opt_translation_unit(&mut tu);
    }

    if matches.is_present("ir") {
        ir::printer::print_ir(&tu);
    }

    let output = "elang_examples/OUTPUT.c";
    let mut file = File::create(output).unwrap();
    codegen::c_gen::gen_translation_unit(&mut file, tu).expect("error gen");
}
<commit_msg>Add output option<commit_after>extern crate clap;
extern crate itertools;
extern crate unicode_xid;
extern crate lalrpop_util;
use clap::{Arg, App};

use std::fs::File;
use std::io::Read;
use std::io;
use std::path::Path;

mod ast;
mod parser;
mod lexer;
mod diagnostics;
mod ir;
mod codegen;

fn read_file<P: AsRef<Path>>(path: P) -> io::Result<String> {
    let mut file = File::open(path)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;
    Ok(buffer)
}

fn main() {
    let matches = App::new("Elang Compiler")
        .version("0.1")
        .author("Paul CACHEUX <paulcacheux@gmail.com>")
        .arg(Arg::with_name("ast").long("ast").help("Dump AST"))
        .arg(Arg::with_name("ir").long("ir").help("Dump IR"))
        .arg(Arg::with_name("opt")
                 .short("O")
                 .help("Activate optimizations"))
        .arg(Arg::with_name("INPUT")
                 .help("Input file")
                 .required(true)
                 .index(1))
        .arg(Arg::with_name("OUTPUT")
                 .help("Output file")
                 .long("output")
                 .short("o")
                 .value_name("FILE")
                 .takes_value(true))
        .get_matches();

    let input_path = matches.value_of("INPUT").unwrap();
    let input = read_file(input_path).expect("Can't read input file");
    let lex = lexer::Lexer::new(&input);
    let tu = match parser::parse_TranslationUnit(lex) {
        Ok(tu) => tu,
        Err(err) => {
            return diagnostics::print_diagnostic(&input, err);
        }
    };

    if matches.is_present("ast") {
        ast::printer::print_ast(&tu);
    }

    let mut tu = match ir::builder::build_translation_unit(tu) {
        Ok(tu) => tu,
        Err(err) => {
            return diagnostics::print_diagnostic(&input, err);
        }
    };

    if matches.is_present("opt") {
        ir::opt::opt_translation_unit(&mut tu);
    }

    if matches.is_present("ir") {
        ir::printer::print_ir(&tu);
    }

    let default_output_path = format!("{}.c", input_path);
    let output_path = matches.value_of("OUTPUT").unwrap_or(&default_output_path);
    let mut file = File::create(output_path).unwrap();
    codegen::c_gen::gen_translation_unit(&mut file, tu).expect("error gen");
}
<|endoftext|>


<commit_before>extern crate ar;
extern crate clap;
extern crate libflate;
extern crate tar;
extern crate xz2;
extern crate zip;

use std::fs;
use std::io;
use std::vec::Vec;

use clap::{Arg, App};

use libflate::gzip;

struct OutputTo {
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FileType {
    GZip,
    Zip,
    Tar,
    Ar,
    BZip2,
    Xz,
    Other,
}

fn identify<'a>(fd: &mut Box<io::BufRead + 'a>) -> io::Result<FileType> {
    let header = fd.fill_buf()?;
    if header.len() >= 20
        && 0x1f == header[0] && 0x8b == header[1] {
        Ok(FileType::GZip)
   } else if header.len() >= 152
        && b'P' == header[0] && b'K' == header[1]
        && 0x03 == header[2] && 0x04 == header[3] {
        Ok(FileType::Zip)
    } else if header.len() > 257 + 10
        && b'u' == header[257] && b's' == header[258]
        && b't' == header[259] && b'a' == header[260]
        && b'r' == header[261]
        && (
            (0 == header[262] && b'0' == header[263] && b'0' == header[264]) ||
            (b' ' == header[262] && b' ' == header[263] && 0 == header[264])
        ) {
        Ok(FileType::Tar)
    } else if header.len() > 8
        && b'!' == header[0] && b'<' == header[1]
        && b'a' == header[2] && b'r' == header[3]
        && b'c' == header[4] && b'h' == header[5]
        && b'>' == header[6] && b'\n' == header[7] {
        Ok(FileType::Ar)
    } else if header.len() > 3
        && b'B' == header[0] && b'Z' == header[1] {
        Ok(FileType::BZip2)
    } else if header.len() > 6
        && 0xfd == header[0] && b'7' == header[1]
        && b'z' == header[2] && b'X' == header[3]
        && b'Z' == header[4] && 0 == header[5] {
        Ok(FileType::Xz)
    } else {
        Ok(FileType::Other)
    }
}

fn plus<T: Clone>(vec: &Vec<T>, thing: T) -> Vec<T> {
    let mut ret = vec.clone();
    ret.push(thing);
    ret
}

fn count_bytes<'a>(mut fd: Box<io::BufRead + 'a>) -> io::Result<u64> {
    let mut block = [0u8; 4096];
    let mut count = 0u64;
    loop {
        let found = fd.read(&mut block[..])?;
        if 0 == found {
            break;
        }
        count += found as u64;
    }
    Ok(count)
}

fn unpack<'a>(mut fd: Box<io::BufRead + 'a>, path: Vec<String>, output: &OutputTo) -> io::Result<()> {
    match identify(&mut fd)? {
        FileType::GZip => {
            let decoder = gzip::Decoder::new(fd)?;
            unpack(Box::new(io::BufReader::new(decoder)), path, output)
        },
        FileType::Ar => {
            let mut decoder = ar::Archive::new(fd);
            while let Some(entry) = decoder.next_entry() {
                let entry = entry?;
                let new_path = plus(&path, entry.header().identifier().to_string());
                unpack(Box::new(io::BufReader::new(entry)), new_path, output)?;
            }
            Ok(())
        },
        FileType::Tar => {
            let mut decoder = tar::Archive::new(fd);
            for entry in decoder.entries()? {
                let entry = entry?;
                let new_path = plus(&path, entry.path()?.to_str().expect("valid utf-8").to_string());
                unpack(Box::new(io::BufReader::new(entry)), new_path, output)?;
            }
            Ok(())
        },
        FileType::Xz => {
            unpack(Box::new(io::BufReader::new(xz2::bufread::XzDecoder::new(fd))), path, output)
        },
        FileType::Zip => {
            let mut angry = io::BufReader::new(fd);
            loop {
                let mut entry = zip::read::read_single(&mut angry)?;
                let new_path = plus(&path, (&*entry.name).to_string());
                let reader = entry.get_reader();
                unpack(Box::new(io::BufReader::new(reader)), new_path, output)?;
            }
            Ok(())
        },
        FileType::Other => {
            println!("{:?}: {}", path, count_bytes(fd)?);
            Ok(())
        },
        x => panic!(format!("{:?}: {:?}", path, x))
    }
}

fn main() {
    let matches = App::new("contentin")
                    .arg(Arg::with_name("to-tar")
                         .long("to-tar")
                         .help("emit a tar file")
                         .required(true))
                    .arg(Arg::with_name("INPUT")
                         .required(true)
                         .multiple(true))
                    .get_matches();
    let output = OutputTo {};
    for path in matches.values_of("INPUT").unwrap() {
        let file = fs::File::open(path).unwrap();
        let read = io::BufReader::new(file);
        unpack(Box::new(read), vec![path.to_string()], &output).unwrap();
    }
}

<commit_msg>zip and tar are ballache<commit_after>extern crate ar;
extern crate clap;
extern crate libflate;
extern crate tar;
extern crate xz2;
extern crate zip;

use std::fs;
use std::io;
use std::vec::Vec;

use clap::{Arg, App};

use libflate::gzip;

struct OutputTo {
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FileType {
    GZip,
    Zip,
    Tar,
    Ar,
    BZip2,
    Xz,
    Other,
}

fn read_octal(bytes: &[u8]) -> Option<u32> {
    let mut start = 0;
    while start < bytes.len() && b' ' == bytes[start] {
        start += 1;
    }

    let mut end = bytes.len() - 1;
    while end > start && (b' ' == bytes[end] || 0 == bytes[end]) {
        end -= 1;
    }

    if let Ok(string) = std::str::from_utf8(&bytes[start..(end+1)]) {
        if let Ok(val) = u32::from_str_radix(string, 8) {
            return Some(val);
        }
    }
    None
}

fn is_probably_tar(header: &[u8]) -> bool {
    if header.len() < 512 {
        return false;
    }

    if let Some(checksum) = read_octal(&header[148..156]) {
        let mut sum: u32 = (b' ' as u32) * 8;
        for i in 0..148 {
            sum += header[i] as u32;
        }
        for i in 156..512 {
            sum += header[i] as u32;
        }

        if checksum == sum {
            return true;
        }
    }

    return false;
}

fn identify<'a>(fd: &mut Box<io::BufRead + 'a>) -> io::Result<FileType> {
    let header = fd.fill_buf()?;
    if header.len() >= 20
        && 0x1f == header[0] && 0x8b == header[1] {
        Ok(FileType::GZip)
   } else if header.len() >= 152
        && b'P' == header[0] && b'K' == header[1]
        && 0x03 == header[2] && 0x04 == header[3] {
        Ok(FileType::Zip)
    } else if header.len() > 257 + 10
        && b'u' == header[257] && b's' == header[258]
        && b't' == header[259] && b'a' == header[260]
        && b'r' == header[261]
        && (
            (0 == header[262] && b'0' == header[263] && b'0' == header[264]) ||
            (b' ' == header[262] && b' ' == header[263] && 0 == header[264])
        ) {
        Ok(FileType::Tar)
    } else if header.len() > 8
        && b'!' == header[0] && b'<' == header[1]
        && b'a' == header[2] && b'r' == header[3]
        && b'c' == header[4] && b'h' == header[5]
        && b'>' == header[6] && b'\n' == header[7] {
        Ok(FileType::Ar)
    } else if header.len() > 3
        && b'B' == header[0] && b'Z' == header[1] {
        Ok(FileType::BZip2)
    } else if header.len() > 6
        && 0xfd == header[0] && b'7' == header[1]
        && b'z' == header[2] && b'X' == header[3]
        && b'Z' == header[4] && 0 == header[5] {
        Ok(FileType::Xz)
    } else if is_probably_tar(header) {
        Ok(FileType::Tar)
    } else {
        Ok(FileType::Other)
    }
}

fn plus<T: Clone>(vec: &Vec<T>, thing: T) -> Vec<T> {
    let mut ret = vec.clone();
    ret.push(thing);
    ret
}

struct BoxReader<'a> {
    fd: Box<io::BufRead + 'a>
}

impl<'a> io::Read for BoxReader<'a> {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        self.fd.read(&mut buf)
    }
}

fn count_bytes<'a, R: io::Read>(mut fd: &mut R) -> io::Result<u64> {
    let mut block = [0u8; 4096];
    let mut count = 0u64;
    loop {
        let found = fd.read(&mut block[..])?;
        if 0 == found {
            break;
        }
        count += found as u64;
    }
    Ok(count)
}

fn unpack<'a>(mut fd: Box<io::BufRead + 'a>, path: Vec<String>, output: &OutputTo) -> io::Result<()> {
    match identify(&mut fd)? {
        FileType::GZip => {
            let decoder = gzip::Decoder::new(fd)?;
            unpack(Box::new(io::BufReader::new(decoder)), path, output)
        },
        FileType::Ar if path.last().unwrap().ends_with(".deb") => {
            let mut decoder = ar::Archive::new(fd);
            while let Some(entry) = decoder.next_entry() {
                let entry = entry?;
                let new_path = plus(&path, entry.header().identifier().to_string());
                unpack(Box::new(io::BufReader::new(entry)), new_path, output)?;
            }
            Ok(())
        },
        FileType::Tar => {
            let mut decoder = tar::Archive::new(fd);
            for entry in decoder.entries()? {
                let entry = entry?;
                let new_path = plus(&path, entry.path()?.to_str().expect("valid utf-8").to_string());
                unpack(Box::new(io::BufReader::new(entry)), new_path, output)?;
            }
            Ok(())
        },
        FileType::Xz => {
            unpack(Box::new(io::BufReader::new(xz2::bufread::XzDecoder::new(fd))), path, output)
        },
        FileType::Zip => {
            let mut angry = BoxReader { fd };
            while let Some(mut entry) = zip::read::read_single(&mut angry)? {
                let new_path = plus(&path, (&*entry.name).to_string());
                let reader = entry.get_reader();
                let unpacked = unpack(Box::new(io::BufReader::new(reader)), new_path, output);
                if let Err(e) = unpacked {
                    if e.kind() == io::ErrorKind::InvalidInput {
                        break;
                    } else {
                        return Err(e)
                    };
                }
            }
            let bytes_at_end = count_bytes(&mut angry)?;
            if 0 != bytes_at_end {
                println!("{:?}: discarding trailing bytes: {}", path, bytes_at_end);
            }
            Ok(())
        },
        other => {
            println!("{:?}: {:?} {}", path, other, count_bytes(&mut BoxReader { fd })?);
            Ok(())
        },
    }
}

fn main() {
    let matches = App::new("contentin")
                    .arg(Arg::with_name("to-tar")
                         .long("to-tar")
                         .help("emit a tar file")
                         .required(true))
                    .arg(Arg::with_name("INPUT")
                         .required(true)
                         .multiple(true))
                    .get_matches();
    let output = OutputTo {};
    for path in matches.values_of("INPUT").unwrap() {
        let file = fs::File::open(path).unwrap();
        let read = io::BufReader::new(file);
        unpack(Box::new(read), vec![path.to_string()], &output).unwrap();
    }
}

<|endoftext|>


<commit_before>#![feature(net)]
extern crate sysly;

use sysly::{ Facility, Syslog };
use std::net::{ IpAddr, SocketAddr };

fn main() {
  let host = SocketAddr::new(IpAddr::new_v4(127,0,0,1), 514);
  let mut syslog = Syslog::udp(host).facility(Facility::LOCAL3).host("foo.local").app("test");
  match syslog.info("Hello syslog. I'm rust.") {
    Err(e) => panic!("error sending -- {}", e),
    Ok(_) => println!("sent")
  };
}
<commit_msg>main is not a test<commit_after>#![feature(net)]
extern crate sysly;

use sysly::{ Facility, Syslog };
use std::net::{ IpAddr, SocketAddr };

#[cfg(not(test))]
fn main() {
  let host = SocketAddr::new(IpAddr::new_v4(127,0,0,1), 514);
  let mut syslog = Syslog::udp(host).facility(Facility::LOCAL3).host("foo.local").app("test");
  match syslog.info("Hello syslog. I'm rust.") {
    Err(e) => panic!("error sending -- {}", e),
    Ok(_) => println!("sent")
  };
}
<|endoftext|>


<commit_before>extern crate image;
extern crate dungenon;

use std::io;
use dungenon::level::Level;
use dungenon::tile::Tile;
use dungenon::generator::MazeGen;

use image::png::PNGEncoder;

fn main() {
    println!("Initializing level...");
    let mut level = init_level();

    println!("This is the dungenon-drawer. \nType Help for list of commands.");
    loop {
        println!("Enter command:");
        let mut command = String::new();
        io::stdin().read_line(&mut command)
        .expect("Failed to read line");
        println!("{}", command);
        match command.trim() {
            "dungeon" => carve_dungeon(&mut level),
            "maze" => carve_maze(&mut level),
            "room" => carve_rooms(&mut level),
            "reset" => level = init_level(),
            "export" => {
                png_export(&mut level);
            },
            "print" => print_level(&level),
            "help" => {
                println!("Help command is not implemented yet!");
            }
            "exit" => break,
            _ => println!("Invalid command"),
        }
    }
}

fn init_level() -> Level {
    println!("Input level width: ");
    let mut x = usize_from_cmd();

    println!("Input level height: ");
    let mut y = usize_from_cmd();

    Level::new_filled_with(Some(Tile::Wall), x, y)
}

fn carve_dungeon(level: &mut Level) {
    println!("Not implemented.");
}

fn carve_maze(level: &mut Level) {
    println!("Input MazeGen startpos x coordinate: ");
    let mut x = usize_from_cmd();

    println!("Input MazeGen startpos y coordinate: ");
    let mut y = usize_from_cmd();
    let mut mazegen = MazeGen::new(x,y);
    level.apply(|m| mazegen.generate(m));
}

fn carve_rooms(level: &mut Level) {
    println!("Not implemented.");
}

fn png_export(level: &mut Level) {

}

fn print_level(level: &Level) {
    let mut string = String::new();
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {
            match level[(x,y)] {
                Some(ref tile) => {
                    match tile {
                        &Tile::Wall => string.push('#'),
                        &Tile::Floor => string.push(' '),
                        &Tile::Void => string.push('*'),
                    }
                },
                None => string.push('*'),
            }
        }
        string.push('\n');
    }
    println!("{}", &string);
}

fn usize_from_cmd() -> usize {
    let mut num = String::new();

    io::stdin().read_line(&mut num)
        .expect("failed to read line");

    let num: usize = num.trim().parse()
        .expect("Please type a number!");
    num
}
<commit_msg>done for today<commit_after>extern crate image;
extern crate dungenon;

use std::io;
use dungenon::level::Level;
use dungenon::tile::Tile;
use dungenon::generator::MazeGen;

use image::png::PNGEncoder;
use image::RgbaImage;

fn main() {
    println!("Initializing level...");
    let mut level = init_level();

    println!("This is the dungenon-drawer. \nType Help for list of commands.");
    loop {
        println!("Enter command:");
        let mut command = String::new();
        io::stdin().read_line(&mut command)
        .expect("Failed to read line");
        println!("{}", command);
        match command.trim() {
            "dungeon" => carve_dungeon(&mut level),
            "maze" => carve_maze(&mut level),
            "room" => carve_rooms(&mut level),
            "reset" => level = init_level(),
            "export" => {
                png_export(&mut level);
            },
            "print" => print_level(&level),
            "help" => {
                println!("Help command is not implemented yet!");
            }
            "exit" => break,
            _ => println!("Invalid command"),
        }
    }
}

fn init_level() -> Level {
    println!("Input level width: ");
    let mut x = usize_from_cmd();

    println!("Input level height: ");
    let mut y = usize_from_cmd();

    Level::new_filled_with(Some(Tile::Wall), x, y)
}

fn carve_dungeon(level: &mut Level) {
    println!("Not implemented.");
}

fn carve_maze(level: &mut Level) {
    println!("Input MazeGen startpos x coordinate: ");
    let mut x = usize_from_cmd();

    println!("Input MazeGen startpos y coordinate: ");
    let mut y = usize_from_cmd();
    let mut mazegen = MazeGen::new(x,y);
    level.apply(|m| mazegen.generate(m));
}

fn carve_rooms(level: &mut Level) {
    println!("Not implemented.");
}

fn png_export(level: &mut Level) {
    let mut level_image = RgbaImage::new(level.get_height(), level.get_height());
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {

        }
    }
}

fn print_level(level: &Level) {
    let mut string = String::new();
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {
            match level[(x,y)] {
                Some(ref tile) => {
                    match tile {
                        &Tile::Wall => string.push('#'),
                        &Tile::Floor => string.push(' '),
                        &Tile::Void => string.push('*'),
                    }
                },
                None => string.push('*'),
            }
        }
        string.push('\n');
    }
    println!("{}", &string);
}

fn usize_from_cmd() -> usize {
    let mut num = String::new();

    io::stdin().read_line(&mut num)
        .expect("failed to read line");

    let num: usize = num.trim().parse()
        .expect("Please type a number!");
    num
}
<|endoftext|>


<commit_before>#[derive(Clone, Copy, Debug)]
enum Const {
  Data,
  Codata,
}

impl ToString for Const {
  fn to_string(&self) -> String {
    use Const::*;
    match *self {
      Data => "data".to_string(),
      Codata => "codata".to_string(),
    }
  }
}

#[derive(Clone, Debug)]
struct Var {
  name: String,
  idx: i32,
}

impl Var {
  pub fn new(name: &str, idx: i32) -> Var {
    Var {
      name: name.to_string(),
      idx: idx,
    }
  }
}

fn vn(name: &str, idx: i32) -> Var {
  Var::new(name, idx)
}

fn v(name: &str) -> Var {
  vn(name, 0)
}

impl ToString for Var {
  fn to_string(&self) -> String {
    if self.idx == 0 {
      self.name.clone()
    } else {
      self.name.clone() + "@" + &self.idx.to_string()
    }
  }
}

#[derive(Clone, Debug)]
enum Expr {
  // Type system constants
  Const(Const),
  // Bound variables
  Var(Var),
  // Lambda
  Lam(Var, Box<Expr>, Box<Expr>),
  // "forall"
  Pi(Var, Box<Expr>, Box<Expr>),
  // Function application
  App(Box<Expr>, Box<Expr>),
}

impl Expr {
  pub fn constant(constant: Const) -> Expr {
    Expr::Const(constant)
  }
  pub fn var(v: &Var) -> Expr {
    Expr::Var(v.clone())
  }
  pub fn lam(var: Var, ty: Expr, body: Expr) -> Expr {
    Expr::Lam(var, Box::new(ty), Box::new(body))
  }
  pub fn pi(var: Var, ty: Expr, body: Expr) -> Expr {
    Expr::Pi(var, Box::new(ty), Box::new(body))
  }
  pub fn app(f: Expr, arg: Expr) -> Expr {
    Expr::App(Box::new(f), Box::new(arg))
  }

  pub fn is_constant(&self) -> bool {
    use Expr::*;
    match *self {
      Const(_) => true,
      _ => false,
    }
  }
  pub fn is_var(&self) -> bool {
    use Expr::*;
    match *self {
      Var(_) => true,
      _ => false,
    }
  }
  pub fn is_lam(&self) -> bool {
    use Expr::*;
    match *self {
      Lam(_, _, _) => true,
      _ => false,
    }
  }
  pub fn is_pi(&self) -> bool {
    use Expr::*;
    match *self {
      Pi(_, _, _) => true,
      _ => false,
    }
  }
  pub fn is_app(&self) -> bool {
    use Expr::*;
    match *self {
      App(_, _) => true,
      _ => false,
    }
  }
}

fn constant(c: Const) -> Expr {
  Expr::constant(c)
}
fn var(v: &Var) -> Expr {
  Expr::var(v)
}
fn lam(var: Var, ty: Expr, body: Expr) -> Expr {
  Expr::lam(var, ty, body)
}
fn pi(var: Var, ty: Expr, body: Expr) -> Expr {
  Expr::pi(var, ty, body)
}
fn app(f: Expr, arg: Expr) -> Expr {
  Expr::app(f, arg)
}

impl ToString for Expr {
  fn to_string(&self) -> String {
    use Expr::*;
    match *self {
      Const(ref constant) => constant.to_string(),
      Var(ref var) => var.to_string(),
      Lam(ref var, ref ty, ref body) => {
        "(".to_string() + &var.to_string() + " : " + &ty.to_string() + ") -> " +
        &body.to_string()
      }
      Pi(ref var, ref ty, ref body) => {
        "forall (".to_string() + &var.to_string() + " : " + &ty.to_string() +
        ") -> " + &body.to_string()
      }
      App(ref f, ref arg) => {
        if f.is_lam() || f.is_pi() {
          "(".to_string() + &f.to_string() + ") " + &arg.to_string()
        } else {
          f.to_string() + " " + &arg.to_string()
        }
      }
    }
  }
}

fn main() {
  println!("{}", Const::Data.to_string());
  let a = v("a");
  let x = v("x");
  let expra = var(&a);
  let exprx = var(&x);
  println!("{}", x.to_string());
  let id = pi(a.clone(), constant(Const::Data), lam(x, expra, exprx));
  println!("{}", id.to_string());
  let apply_id = app(app(id, var(&v("int"))), var(&v("1")));
  println!("{}", apply_id.to_string());
}

#[test]
fn test_to_string() {
  let codata = Const::Codata;
  println!("{}", codata.to_string());
  assert_eq!("codata", codata.to_string());
  let a = v("a");
  let x = v("x");
  let expra = var(&a);
  let exprx = var(&x);
  println!("{}", x.to_string());
  assert_eq!("x", x.to_string());
  let id = pi(a.clone(), constant(Const::Data), lam(x, expra, exprx));
  println!("{}", id.to_string());
  assert_eq!("forall (a : data) -> (x : a) -> x", id.to_string());
  let apply_id = app(app(id, var(&v("int"))), var(&v("1")));
  println!("{}", apply_id.to_string());
  assert_eq!("(forall (a : data) -> (x : a) -> x) int 1",
             apply_id.to_string());
}
<commit_msg>Clean up some functions. Begin implementing normalization.<commit_after>trait Normalize {
  fn normalize(&self) -> Self;
}

#[derive(Clone, Copy, Debug)]
enum Const {
  Data,
  Codata,
}

impl Normalize for Const {
  fn normalize(&self) -> Const {
    *self
  }
}

impl ToString for Const {
  fn to_string(&self) -> String {
    match *self {
      Const::Data => "data".to_string(),
      Const::Codata => "codata".to_string(),
    }
  }
}

#[derive(Clone, Debug)]
struct Var {
  name: String,
  idx: i32,
}

impl Var {
  pub fn new(name: &str, idx: i32) -> Var {
    Var {
      name: name.to_string(),
      idx: idx,
    }
  }
}

fn vn(name: &str, idx: i32) -> Var {
  Var::new(name, idx)
}

fn v(name: &str) -> Var {
  vn(name, 0)
}

impl Normalize for Var {
  fn normalize(&self) -> Var {
    self.clone()
  }
}

impl ToString for Var {
  fn to_string(&self) -> String {
    if self.idx == 0 {
      self.name.clone()
    } else {
      self.name.clone() + "@" + &self.idx.to_string()
    }
  }
}

#[derive(Clone, Debug)]
enum Expr {
  // Type system constants
  Const(Const),
  // Bound variables
  Var(Var),
  // Lambda
  Lam(Var, Box<Expr>, Box<Expr>),
  // "forall"
  Pi(Var, Box<Expr>, Box<Expr>),
  // Function application
  App(Box<Expr>, Box<Expr>),
}

impl Expr {
  pub fn constant(constant: Const) -> Expr {
    Expr::Const(constant)
  }
  pub fn var(v: &Var) -> Expr {
    Expr::Var(v.clone())
  }
  pub fn lam(var: Var, ty: Expr, body: Expr) -> Expr {
    Expr::Lam(var, Box::new(ty), Box::new(body))
  }
  pub fn pi(var: Var, ty: Expr, body: Expr) -> Expr {
    Expr::Pi(var, Box::new(ty), Box::new(body))
  }
  pub fn app(f: Expr, arg: Expr) -> Expr {
    Expr::App(Box::new(f), Box::new(arg))
  }

  pub fn is_constant(&self) -> bool {
    match *self {
      Expr::Const(_) => true,
      _ => false,
    }
  }
  pub fn is_var(&self) -> bool {
    use Expr::*;
    match *self {
      Var(_) => true,
      _ => false,
    }
  }
  pub fn is_lam(&self) -> bool {
    match *self {
      Expr::Lam(_, _, _) => true,
      _ => false,
    }
  }
  pub fn is_pi(&self) -> bool {
    match *self {
      Expr::Pi(_, _, _) => true,
      _ => false,
    }
  }
  pub fn is_app(&self) -> bool {
    match *self {
      Expr::App(_, _) => true,
      _ => false,
    }
  }
}

fn constant(c: Const) -> Expr {
  Expr::constant(c)
}
fn var(v: &Var) -> Expr {
  Expr::var(v)
}
fn lam(var: Var, ty: Expr, body: Expr) -> Expr {
  Expr::lam(var, ty, body)
}
fn pi(var: Var, ty: Expr, body: Expr) -> Expr {
  Expr::pi(var, ty, body)
}
fn app(f: Expr, arg: Expr) -> Expr {
  Expr::app(f, arg)
}

impl Normalize for Expr {
  fn normalize(&self) -> Expr {
    use Expr::*;
    match *self {
      Const(ref constant) => Const(constant.normalize()),
      Var(ref var) => Var(var.normalize()),
      Lam(ref var, ref ty, ref body) => {
        let l = &Lam(var.normalize(),
                     Box::new(ty.normalize()),
                     Box::new(body.normalize()));
        l.clone()
      }
      Pi(ref var, ref ty, ref body) => {
        let p = &Pi(var.normalize(),
                    Box::new(ty.normalize()),
                    Box::new(body.normalize()));
        p.clone()
      }
      App(ref f, ref arg) => {
        let a = &App(Box::new(f.normalize()), Box::new(arg.normalize()));
        a.clone()
      }
    }
  }
}

impl ToString for Expr {
  fn to_string(&self) -> String {
    use Expr::*;
    match *self {
      Const(ref constant) => constant.to_string(),
      Var(ref var) => var.to_string(),
      Lam(ref var, ref ty, ref body) => {
        "(".to_string() + &var.to_string() + " : " + &ty.to_string() + ") -> " +
        &body.to_string()
      }
      Pi(ref var, ref ty, ref body) => {
        "forall (".to_string() + &var.to_string() + " : " + &ty.to_string() +
        ") -> " + &body.to_string()
      }
      App(ref f, ref arg) => {
        if f.is_lam() || f.is_pi() {
          "(".to_string() + &f.to_string() + ") " + &arg.to_string()
        } else {
          f.to_string() + " " + &arg.to_string()
        }
      }
    }
  }
}

fn main() {
  println!("{}", Const::Data.to_string());
  let a = v("a");
  let x = v("x");
  let expra = var(&a);
  let exprx = var(&x);
  println!("{}", x.to_string());
  let id = pi(a.clone(), constant(Const::Data), lam(x, expra, exprx));
  println!("{}", id.to_string());
  let apply_id = app(app(id, var(&v("int"))), var(&v("1")));
  println!("{}", apply_id.to_string());
  println!("{}", apply_id.normalize().to_string());
}

#[test]
fn test_to_string() {
  let codata = Const::Codata;
  println!("{}", codata.to_string());
  assert_eq!("codata", codata.to_string());
  let a = v("a");
  let x = v("x");
  let expra = var(&a);
  let exprx = var(&x);
  println!("{}", x.to_string());
  assert_eq!("x", x.to_string());
  let id = pi(a.clone(), constant(Const::Data), lam(x, expra, exprx));
  println!("{}", id.to_string());
  assert_eq!("forall (a : data) -> (x : a) -> x", id.to_string());
  let apply_id = app(app(id, var(&v("int"))), var(&v("1")));
  println!("{}", apply_id.to_string());
  assert_eq!("(forall (a : data) -> (x : a) -> x) int 1",
             apply_id.to_string());
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
// #![deny(clippy_pedantic)]
extern crate termion;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate log4rs;

mod core;

use termion::{clear, cursor};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{stdout, Write, stdin};
use std::sync::mpsc;
use std::{thread, time};
use core::Core;

struct Screen {
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
    size: (u16, u16),
}

impl Screen {

    fn new() -> Screen {
        let mut stdout = stdout().into_raw_mode().unwrap();
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    fn redraw(&mut self, mut update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        for (_, line) in update.lines.iter().enumerate() {
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(line.text.as_bytes()).unwrap();
        }
        // this is pretty weird
        write!(self.stdout, "{}", cursor::Goto(update.scroll_to.1 as u16 + 1, update.scroll_to.0 as u16 + 1)).unwrap();
        self.stdout.flush();
    }

    fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush();
    }

}

struct Update {
    lines: Vec<Line>,
    height: u64,
    scroll_to: (u64, u64),
    first_line: u64
}

impl Update {
    fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        info!("{:?}", object);
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}

struct Line {
    text: String,
    selection: Option<(u64, u64)>,
    cursor: Option<u64>,
}

impl Line {
    fn from_value(value: &serde_json::Value) -> Line {
        let line_arr = value.as_array().unwrap();
        let mut line = Line {
            text: line_arr[0].as_str().unwrap().to_string(),
            cursor: None,
            selection: None,
        };
        for annotation in line_arr.iter().skip(1).map(|a| a.as_array().unwrap()) {
            match annotation[0].as_str().unwrap() {
                "cursor" => {
                    line.cursor = Some(annotation[1].as_u64().unwrap());
                },
                "sel" => {
                    line.selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap()));
                },
                _ => {
                    error!("unknown annotation");
                }
            }
        }
        line
    }
}

fn update_screen(core: &mut Core, screen: &mut Screen) {
    if let Ok(msg) = core.update_rx.try_recv() {
        let update = Update::from_value(msg.as_object().unwrap().get("update").unwrap());
        screen.redraw(&update);
    } else {
        thread::sleep_ms(10);
    }
}

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        info!("event: {:?}", event);
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }
}

impl Default for Input {
	fn default() -> Self {
		Self::new()
	}
}

fn main() {
    log4rs::init_file("log_config.yaml", Default::default()).unwrap();
    let mut core = Core::new("../xi-editor/rust/target/debug/xi-core");
    let mut screen = Screen::new();
    let mut input = Input::new();
    input.run();
    screen.init();
    loop {
        if let Ok(event) = input.rx.try_recv() {
            match event {
                termion::event::Event::Key(key) => {
                    match key {
                        termion::event::Key::Char(c) => {
                            core.char(c);
                        },
                        termion::event::Key::Ctrl(c) => {
                            if c == 'c' {
                                info!("received ^C: exiting");
                                return;
                            }
                        },
                        _ => {
                            error!("unsupported key event");
                        }
                    }
                },
                termion::event::Event::Mouse(_) => {
                    error!("mouse events are not supported yet");
                }
                _ => {
                    error!("unsupported event");
                }
            }
        } else {
            update_screen(&mut core, &mut screen);
        }
    }
}
<commit_msg>fix: unused result warnings<commit_after>#![feature(plugin)]
#![plugin(clippy)]
// #![deny(clippy_pedantic)]
extern crate termion;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate log4rs;

mod core;

use termion::{clear, cursor};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{stdout, Write, stdin};
use std::sync::mpsc;
use std::{thread, time};
use core::Core;

struct Screen {
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
    size: (u16, u16),
}

impl Screen {

    fn new() -> Screen {
        let mut stdout = stdout().into_raw_mode().unwrap();
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    fn redraw(&mut self, mut update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        for (_, line) in update.lines.iter().enumerate() {
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(line.text.as_bytes()).unwrap();
        }
        // this is pretty weird
        write!(self.stdout, "{}", cursor::Goto(update.scroll_to.1 as u16 + 1, update.scroll_to.0 as u16 + 1)).unwrap();
        self.stdout.flush().unwrap();
    }

    fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

}

struct Update {
    lines: Vec<Line>,
    height: u64,
    scroll_to: (u64, u64),
    first_line: u64
}

impl Update {
    fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        info!("{:?}", object);
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}

struct Line {
    text: String,
    selection: Option<(u64, u64)>,
    cursor: Option<u64>,
}

impl Line {
    fn from_value(value: &serde_json::Value) -> Line {
        let line_arr = value.as_array().unwrap();
        let mut line = Line {
            text: line_arr[0].as_str().unwrap().to_string(),
            cursor: None,
            selection: None,
        };
        for annotation in line_arr.iter().skip(1).map(|a| a.as_array().unwrap()) {
            match annotation[0].as_str().unwrap() {
                "cursor" => {
                    line.cursor = Some(annotation[1].as_u64().unwrap());
                },
                "sel" => {
                    line.selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap()));
                },
                _ => {
                    error!("unknown annotation");
                }
            }
        }
        line
    }
}

fn update_screen(core: &mut Core, screen: &mut Screen) {
    if let Ok(msg) = core.update_rx.try_recv() {
        let update = Update::from_value(msg.as_object().unwrap().get("update").unwrap());
        screen.redraw(&update);
    } else {
        thread::sleep_ms(10);
    }
}

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        info!("event: {:?}", event);
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }
}

impl Default for Input {
	fn default() -> Self {
		Self::new()
	}
}

fn main() {
    log4rs::init_file("log_config.yaml", Default::default()).unwrap();
    let mut core = Core::new("../xi-editor/rust/target/debug/xi-core");
    let mut screen = Screen::new();
    let mut input = Input::new();
    input.run();
    screen.init();
    loop {
        if let Ok(event) = input.rx.try_recv() {
            match event {
                termion::event::Event::Key(key) => {
                    match key {
                        termion::event::Key::Char(c) => {
                            core.char(c);
                        },
                        termion::event::Key::Ctrl(c) => {
                            if c == 'c' {
                                info!("received ^C: exiting");
                                return;
                            }
                        },
                        _ => {
                            error!("unsupported key event");
                        }
                    }
                },
                termion::event::Event::Mouse(_) => {
                    error!("mouse events are not supported yet");
                }
                _ => {
                    error!("unsupported event");
                }
            }
        } else {
            update_screen(&mut core, &mut screen);
        }
    }
}
<|endoftext|>