<commit_before>use scanner::Scanner;
use regex::Regex;

const COMPARISON           : &'static str = r"^(==|!=|<>|<=?|>=?|contains)";
const SINGLE_STRING_LITERAL: &'static str = r"^'[^']*'";
const DOUBLE_STRING_LITERAL: &'static str = r#"^"[^"]*""#;
const NUMBER_LITERAL:        &'static str = r"^-?\d+(\.\d+)?";
const IDENTIFIER:            &'static str = r"^[a-zA-Z_][\w-]*\??";
const RANGE_OP:              &'static str = r"^\.\.";

#[derive(Debug, PartialEq)]
pub enum Token {
    Comparison(String),
    Identifier(String),
    Number(String),
    String(String),
    Range,
    EndOfString,
}

macro_rules! token {
    (Comparison => $e:expr) => (Token::Comparison(String::from($e)));
    (Identifier => $e:expr) => (Token::Identifier(String::from($e)));
    (Number => $e:expr) => (Token::Number(String::from($e)));
    (String => $e:expr) => (Token::String(String::from($e)));
    (Range) => (Token::Range);
    (EndOfString) => (Token::EndOfString);
}

pub struct Tokens<'t> {
    scanner: &'t Scanner<'t>
}

impl<'t> Tokens<'t> {
    fn token_for(&self, pattern: &Regex, value: &str) -> Token {
        match pattern.as_str() {
            COMPARISON            => token!(Comparison => value),
            SINGLE_STRING_LITERAL => token!(String => value),
            DOUBLE_STRING_LITERAL => token!(String => value),
            NUMBER_LITERAL        => token!(Number => value),
            IDENTIFIER            => token!(Identifier => value),
            RANGE_OP              => token!(Range),
            _                     => token!(EndOfString)
        }
    }
}

impl<'t> Iterator for Tokens<'t> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        let matchers = vec![
            Regex::new(COMPARISON).unwrap(),
            Regex::new(SINGLE_STRING_LITERAL).unwrap(),
            Regex::new(DOUBLE_STRING_LITERAL).unwrap(),
            Regex::new(NUMBER_LITERAL).unwrap(),
            Regex::new(IDENTIFIER).unwrap(),
            Regex::new(RANGE_OP).unwrap()
        ];

        match matchers.iter().find(|&m| self.scanner.check(m)) {
            None => None,
            Some(regex) => {
                let value = self.scanner.scan(&regex).unwrap();
                Some(self.token_for(&regex, &value))
            }
        }
    }
}

pub struct Lexer<'t> {
    scanner: Scanner<'t>
}

impl<'t> Lexer<'t> {
    pub fn new<'a>(source: &'a str) -> Lexer<'a> {
        Lexer { scanner: Scanner::new(source) }
    }

    pub fn tokens(&self) -> Tokens {
        Tokens { scanner: &self.scanner }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new_creates_a_new_instance() {
        let lexer = Lexer::new("doSomthing | filter");
        assert_eq!("doSomthing | filter", lexer.scanner.rest().unwrap());
    }

    #[test]
    fn tokens_when_given_a_blank_string() {
        let lexer              = Lexer::new("");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_when_given_a_whitespace_only_string() {
        let lexer              = Lexer::new("  \t \n\r ");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_parses_identifiers() {
        let lexer              = Lexer::new("high five?");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "high"), tokens[0]);
        assert_eq!(token!(Identifier => "five?"), tokens[1]);
    }

    #[test]
    fn tokens_knows_that_identifiers_dont_start_with_numbers() {
        let lexer              = Lexer::new("2foo 5.0bar");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(4, tokens.len());
        assert_eq!(token!(Number => "2"), tokens[0]);
        assert_eq!(token!(Identifier => "foo"), tokens[1]);
        assert_eq!(token!(Number => "5.0"), tokens[2]);
        assert_eq!(token!(Identifier => "bar"), tokens[3]);
    }

    #[test]
    fn tokens_parses_string_literals() {
        let lexer              = Lexer::new(r#" 'this is a test""' "wat 'lol'" "#);
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(String => r#"'this is a test""'"#), tokens[0]);
        assert_eq!(token!(String => r#""wat 'lol'""#), tokens[1]);
    }

    #[test]
    fn tokens_parses_integers() {
        let lexer              = Lexer::new("hi 50");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "hi"), tokens[0]);
        assert_eq!(token!(Number => "50"), tokens[1]);
    }

    #[test]
    fn tokens_parses_floats() {
        let lexer              = Lexer::new("hi 5.0");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "hi"), tokens[0]);
        assert_eq!(token!(Number => "5.0"), tokens[1]);
    }

    #[test]
    fn tokens_parses_comparisons() {
        let lexer              = Lexer::new("== <> contains");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Comparison => "=="), tokens[0]);
        assert_eq!(token!(Comparison => "<>"), tokens[1]);
        assert_eq!(token!(Comparison => "contains"), tokens[2]);
    }

    #[test]
    fn tokens_parses_range_operator() {
        let lexer              = Lexer::new("1..10");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Number => "1"), tokens[0]);
        assert_eq!(token!(Range), tokens[1]);
        assert_eq!(token!(Number => "10"), tokens[2]);
    }
}
<commit_msg>marking unreachable code accordingly<commit_after>use scanner::Scanner;
use regex::Regex;

const COMPARISON           : &'static str = r"^(==|!=|<>|<=?|>=?|contains)";
const SINGLE_STRING_LITERAL: &'static str = r"^'[^']*'";
const DOUBLE_STRING_LITERAL: &'static str = r#"^"[^"]*""#;
const NUMBER_LITERAL:        &'static str = r"^-?\d+(\.\d+)?";
const IDENTIFIER:            &'static str = r"^[a-zA-Z_][\w-]*\??";
const RANGE_OP:              &'static str = r"^\.\.";

#[derive(Debug, PartialEq)]
pub enum Token {
    Comparison(String),
    Identifier(String),
    Number(String),
    String(String),
    Range(String)
}

macro_rules! token {
    (Comparison => $e:expr) => (Token::Comparison(String::from($e)));
    (Identifier => $e:expr) => (Token::Identifier(String::from($e)));
    (Number => $e:expr) => (Token::Number(String::from($e)));
    (String => $e:expr) => (Token::String(String::from($e)));
    (Range) => (Token::Range("..".into()));
}

pub struct Tokens<'t> {
    scanner: &'t Scanner<'t>
}

impl<'t> Tokens<'t> {
    fn token_for(&self, pattern: &Regex, value: &str) -> Token {
        match pattern.as_str() {
            COMPARISON            => token!(Comparison => value),
            SINGLE_STRING_LITERAL => token!(String => value),
            DOUBLE_STRING_LITERAL => token!(String => value),
            NUMBER_LITERAL        => token!(Number => value),
            IDENTIFIER            => token!(Identifier => value),
            RANGE_OP              => token!(Range),
            _                     => unreachable!()
        }
    }
}

impl<'t> Iterator for Tokens<'t> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        let matchers = vec![
            Regex::new(COMPARISON).unwrap(),
            Regex::new(SINGLE_STRING_LITERAL).unwrap(),
            Regex::new(DOUBLE_STRING_LITERAL).unwrap(),
            Regex::new(NUMBER_LITERAL).unwrap(),
            Regex::new(IDENTIFIER).unwrap(),
            Regex::new(RANGE_OP).unwrap()
        ];

        match matchers.iter().find(|&m| self.scanner.check(m)) {
            None => None,
            Some(regex) => {
                let value = self.scanner.scan(&regex).unwrap();
                Some(self.token_for(&regex, &value))
            }
        }
    }
}

pub struct Lexer<'t> {
    scanner: Scanner<'t>
}

impl<'t> Lexer<'t> {
    pub fn new<'a>(source: &'a str) -> Lexer<'a> {
        Lexer { scanner: Scanner::new(source) }
    }

    pub fn tokens(&self) -> Tokens {
        Tokens { scanner: &self.scanner }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new_creates_a_new_instance() {
        let lexer = Lexer::new("doSomthing | filter");
        assert_eq!("doSomthing | filter", lexer.scanner.rest().unwrap());
    }

    #[test]
    fn tokens_when_given_a_blank_string() {
        let lexer              = Lexer::new("");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_when_given_a_whitespace_only_string() {
        let lexer              = Lexer::new("  \t \n\r ");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(0, tokens.len());
    }

    #[test]
    fn tokens_parses_identifiers() {
        let lexer              = Lexer::new("high five?");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "high"), tokens[0]);
        assert_eq!(token!(Identifier => "five?"), tokens[1]);
    }

    #[test]
    fn tokens_knows_that_identifiers_dont_start_with_numbers() {
        let lexer              = Lexer::new("2foo 5.0bar");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(4, tokens.len());
        assert_eq!(token!(Number => "2"), tokens[0]);
        assert_eq!(token!(Identifier => "foo"), tokens[1]);
        assert_eq!(token!(Number => "5.0"), tokens[2]);
        assert_eq!(token!(Identifier => "bar"), tokens[3]);
    }

    #[test]
    fn tokens_parses_string_literals() {
        let lexer              = Lexer::new(r#" 'this is a test""' "wat 'lol'" "#);
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(String => r#"'this is a test""'"#), tokens[0]);
        assert_eq!(token!(String => r#""wat 'lol'""#), tokens[1]);
    }

    #[test]
    fn tokens_parses_integers() {
        let lexer              = Lexer::new("hi 50");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "hi"), tokens[0]);
        assert_eq!(token!(Number => "50"), tokens[1]);
    }

    #[test]
    fn tokens_parses_floats() {
        let lexer              = Lexer::new("hi 5.0");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(2, tokens.len());
        assert_eq!(token!(Identifier => "hi"), tokens[0]);
        assert_eq!(token!(Number => "5.0"), tokens[1]);
    }

    #[test]
    fn tokens_parses_comparisons() {
        let lexer              = Lexer::new("== <> contains");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Comparison => "=="), tokens[0]);
        assert_eq!(token!(Comparison => "<>"), tokens[1]);
        assert_eq!(token!(Comparison => "contains"), tokens[2]);
    }

    #[test]
    fn tokens_parses_range_operator() {
        let lexer              = Lexer::new("1..10");
        let tokens: Vec<Token> = lexer.tokens().collect();

        assert_eq!(3, tokens.len());
        assert_eq!(token!(Number => "1"), tokens[0]);
        assert_eq!(token!(Range), tokens[1]);
        assert_eq!(token!(Number => "10"), tokens[2]);
    }
}
<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::str;

pub enum TokenKind {
    Identifier,
    IntNumber,
    FloatNumber,
    String,
    Char,
    Symbol,
    Newline,
    End,
}

pub struct Token {
    pub kind: TokenKind,
    pub val: String,
    pub line: i32,
}

impl Token {
    pub fn new(kind: TokenKind, val: &str, line: i32) -> Token {
        Token {
            kind: kind,
            val: val.to_string(),
            line: line,
        }
    }
}

pub struct Lexer<'a> {
    cur_line: i32,
    filename: String,
    peek: iter::Peekable<str::Chars<'a>>,
}

impl<'a> Lexer<'a> {
    pub fn new(filename: String, input: &'a str) -> Lexer<'a> {
        let l = Lexer {
            cur_line: 0,
            filename: filename.to_string(),
            peek: input.chars().peekable(),
        };
        l
    }
    pub fn get_filename(self) -> String {
        self.filename
    }

    pub fn read_identifier(&mut self) -> Token {
        let mut ident = String::new();
        loop {
            match self.peek.peek() {
                Some(&c) => {
                    match c {
                        'a'...'z' | 'A'...'Z' | '_' | '0'...'9' => ident.push(c),
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek.next();
        }
        Token::new(TokenKind::Identifier, ident.as_str(), self.cur_line)
    }
    pub fn read_newline(&mut self) -> Token {
        self.peek.next();
        Token::new(TokenKind::Newline, "", self.cur_line)
    }
    pub fn read_symbol(&mut self) -> Token {
        let c = self.peek.next();
        let mut sym = String::new();
        sym.push(c.unwrap());
        Token::new(TokenKind::Symbol, sym.as_str(), self.cur_line)
    }

    pub fn read_token(&mut self) -> Option<Token> {
        match self.peek.peek() {
            Some(&c) => {
                match c {
                    'a'...'z' | 'A'...'Z' | '_' => Some(self.read_identifier()),
                    ' ' | '\t' => {
                        self.peek.next();
                        self.read_token()
                    }
                    '\n' => Some(self.read_newline()),
                    _ => Some(self.read_symbol()),
                }
            }
            None => None as Option<Token>,
        };
    }
}
<commit_msg>add lexer::Lexer::peek_pos<commit_after>use std::io::{BufRead, BufReader};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::str;

pub enum TokenKind {
    Identifier,
    IntNumber,
    FloatNumber,
    String,
    Char,
    Symbol,
    Newline,
    End,
}

pub struct Token {
    pub kind: TokenKind,
    pub val: String,
    pub line: i32,
}

impl Token {
    pub fn new(kind: TokenKind, val: &str, line: i32) -> Token {
        Token {
            kind: kind,
            val: val.to_string(),
            line: line,
        }
    }
}

pub struct Lexer<'a> {
    cur_line: i32,
    filename: String,
    peek: iter::Peekable<str::Chars<'a>>,
    peek_pos: usize,
}

impl<'a> Lexer<'a> {
    pub fn new(filename: String, input: &'a str) -> Lexer<'a> {
        let l = Lexer {
            cur_line: 0,
            filename: filename.to_string(),
            peek: input.chars().peekable(),
            peek_pos: 0,
        };
        l
    }
    pub fn get_filename(self) -> String {
        self.filename
    }

    fn peek_next(&mut self) -> char {
        self.peek_pos += 1;
        self.peek.next().unwrap()
    }

    pub fn read_identifier(&mut self) -> Token {
        let mut ident = String::new();
        loop {
            match self.peek.peek() {
                Some(&c) => {
                    match c {
                        'a'...'z' | 'A'...'Z' | '_' | '0'...'9' => ident.push(c),
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek_next();
        }
        Token::new(TokenKind::Identifier, ident.as_str(), self.cur_line)
    }
    pub fn read_newline(&mut self) -> Token {
        self.peek_next();
        Token::new(TokenKind::Newline, "", self.cur_line)
    }
    pub fn read_symbol(&mut self) -> Token {
        let c = self.peek_next();
        let mut sym = String::new();
        sym.push(c);
        Token::new(TokenKind::Symbol, sym.as_str(), self.cur_line)
    }

    pub fn read_token(&mut self) -> Option<Token> {
        match self.peek.peek() {
            Some(&c) => {
                match c {
                    'a'...'z' | 'A'...'Z' | '_' => Some(self.read_identifier()),
                    ' ' | '\t' => {
                        self.peek_next();
                        self.read_token()
                    }
                    '\n' => Some(self.read_newline()),
                    _ => Some(self.read_symbol()),
                }
            }
            None => None as Option<Token>,
        }
    }
}
<|endoftext|>


<commit_before>use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

pub struct Lexer<I> {
    chars: I,
    cx: Rc<Cell<Context>>
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer { chars: chars, cx: cx }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        let char = self.chars.by_ref().find(|c| !c.is_es_whitespace() );

        char.map(|chr| {
            match chr {
                '1' => Token::DecimalInt(String::from_str("1")),
                '+' => Token::Plus,
                _ => Token::Error(chr)
            }
        })
    }
}
<commit_msg>move source location tracking into separate LineOrientedReader abstraction<commit_after>use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    //chars: I,
    cx: Rc<Cell<Context>>
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx
        }
    }

    // private methods

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<|endoftext|>


<commit_before>#![crate_name="json_macros"]
#![crate_type="dylib"]
#![feature(phase, plugin_registrar, macro_rules, quote)]

extern crate rustc;
extern crate syntax;
extern crate "rustc-serialize" as rustc_serialize;

use syntax::ast::TokenTree;
use syntax::codemap::Span;
use syntax::ptr::P;

use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
use syntax::parse::token;
use syntax::print::pprust;
use rustc::plugin::Registry;

type PExpr = P<ast::Expr>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("json", expand);
}

fn expand<'cx>(cx: &'cx mut ExtCtxt, sp: Span,
               tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    let tt = match tts.get(0) {
        Some(tt) => tt,
        None => {
            cx.span_err(sp, "expected JSON literal");
            return DummyResult::expr(sp);
        }
    };

    let expr = match tt_to_expr(cx, tt) {
        Some(e) => e,
        None => return DummyResult::expr(sp)
    };
    MacExpr::new(expr)
}

fn tt_to_expr(cx: &ExtCtxt, tt: &TokenTree) -> Option<PExpr> {
    use syntax::ext::build::AstBuilder;

    match *tt {
        ast::TtToken(sp, ref tok) => token_to_expr(cx, sp, tok),
        ast::TtDelimited(sp, ref d) => {
            let ref toks = d.tts;
            match d.delim {
                // array
                token::Bracket => {
                    let exprs = match parse_array(cx, sp, toks.as_slice()) {
                        Some(e) => e,
                        None => return None
                    };
                    let exprs = cx.expr_vec(sp, exprs);
                    Some(quote_expr!(cx, {
                        {
                            use std::slice::BoxedSliceExt;
                            let xs: ::std::boxed::Box<[_]> = box $exprs;
                            ::rustc_serialize::json::Json::Array(xs.into_vec())
                        }
                    }))
                }
                // object
                token::Brace => {
                    let items = match parse_object(cx, sp, toks.as_slice()) {
                        Some(i) => i,
                        None => return None
                    };
                    let ob = quote_expr!(cx, _ob);
                    let mut stmts = vec![];
                    for &(ref key, ref value) in items.iter() {
                        stmts.push(quote_stmt!(cx, $ob.insert($key, $value)));
                    }

                    Some(quote_expr!(cx, {
                        {
                            let mut $ob = ::std::collections::BTreeMap::new();
                            $stmts;
                            ::rustc_serialize::json::Json::Object($ob)
                        }
                    }))
                }
                token::Paren => {
                    let mut parser = cx.new_parser_from_tts(toks.as_slice());
                    let expr = parser.parse_expr();

                    Some(quote_expr!(cx, {
                        use rustc_serialize::json::ToJson;
                        ($expr).to_json()
                    }))
                }
            }
        }
        ast::TtSequence(sp, _) => {
            cx.span_err(sp, "`json!` unexpected TtSequence");
            None
        }
    }
}

fn parse_array(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<PExpr>> {
    let mut exprs = Vec::with_capacity(tts.len() / 2);
    for (i, tt) in tts.iter().enumerate() {
        if i % 2 == 1 {
            match tt {
                &ast::TtToken(_, token::Comma) => {
                    continue;
                }
                _ => {
                    expected_but_found(cx, sp, "`,`", tt);
                    return None;
                }
            }
        }
        let expr = tt_to_expr(cx, tt);
        let expr = match expr {
            Some(e) => e,
            None => return None,
        };
        exprs.push(expr);
    }
    Some(exprs)
}

fn parse_object(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<(PExpr, PExpr)>> {
    use syntax::ast::TtToken;

    macro_rules! comma {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Comma)
        }
    }

    macro_rules! colon {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Colon)
        };
        ($sp:ident) => {
            ::syntax::ast::TtToken($sp, ::syntax::parse::token::Colon)
        }
    }

    let mut items = Vec::with_capacity(tts.len() / 4);
    if tts.len() == 0 {
        return Some(items);
    }

    // horrible
    for entry in tts.chunks(4) {
        use syntax::parse::token::{Lit, Literal};
        let item = match entry {
            // "foo": VALUE | "foo": VALUE,
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v] |
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v, comma!()] => {
                let k = n.as_str();
                let v = tt_to_expr(cx, v);
                if v.is_none() {
                    return None;
                }
                let k = quote_expr!(cx, $k.into_string());
                let v = quote_expr!(cx, $v);
                (k, v)
            }
            // "foo": VALUE X
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(), _, ref tt] => {
                expected_but_found(cx, sp, "`,`", tt);
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(sp)] => {
                cx.span_err(sp, "found `:` but no value afterwards");
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_) ,_)), ref tt, ..] => {
                expected_but_found(cx, sp, "`:`", tt);
                return None;
            }
            [TtToken(sp, Literal(Lit::Str_(_), _))] => {
                cx.span_err(sp, "found name but no colon-value afterwards");
                return None;
            }
            [ref tt, ..] => {
                expected_but_found(cx, sp, "string literal", tt);
                return None;
            }
            [] => unreachable!(), // chunks() never returns an empty slice
        };
        items.push(item);
    }

    Some(items)
}

fn token_to_expr(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> Option<PExpr> {
    use syntax::print::pprust;
    use syntax::parse::token::{Lit, Literal};

    match *tok {
        Literal(Lit::Str_(ref n), _) => {
            let s = n.as_str();
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::String($s.into_string())
            }))
        }
        // FIXME: handle suffixed literals (i.e. u64) correctly
        // FIXME: handle negative numbers
        Literal(Lit::Integer(_), _)=> {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::I64($tt as i64)
            }))
        }
        Literal(Lit::Float(_), _) => {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::F64($tt)
            }))
        }
        token::Ident(ref id, token::Plain) if id.as_str() == "null" => {
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::Null
            }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::True) => {
            Some(quote_expr!(cx, { ::rustc_serialize::json::Json::Boolean(true) }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::False) => {
            Some(quote_expr!(cx, { ::rustc_serialize::json::Json::Boolean(false) }))
        }
        _ => {
            let tt = ast::TtToken(sp, tok.clone());
            let s = pprust::tt_to_string(&tt);
            cx.span_err(sp, format!("unexpected `{}` in JSON", s).as_slice());
            None
        }
    }
}

fn best_span(sp: Span, tt: &TokenTree) -> Span {
    let sp = match *tt {
        ast::TtToken(tok_sp, _) => tok_sp,
        _ => sp // the span passed into the function!
    };
    sp
}

fn expected_but_found(cx: &ExtCtxt, sp: Span, expected: &str, found: &TokenTree) {
    let pp = pprust::tt_to_string(found);
    let err = format!("expected {} but found: `{}`", expected, pp);
    cx.span_err(best_span(sp, found), err.as_slice());
}
<commit_msg>Remove use of deprecated into_string()<commit_after>#![crate_name="json_macros"]
#![crate_type="dylib"]
#![feature(phase, plugin_registrar, macro_rules, quote)]

extern crate rustc;
extern crate syntax;
extern crate "rustc-serialize" as rustc_serialize;

use syntax::ast::TokenTree;
use syntax::codemap::Span;
use syntax::ptr::P;

use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
use syntax::parse::token;
use syntax::print::pprust;
use rustc::plugin::Registry;

type PExpr = P<ast::Expr>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("json", expand);
}

fn expand<'cx>(cx: &'cx mut ExtCtxt, sp: Span,
               tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    let tt = match tts.get(0) {
        Some(tt) => tt,
        None => {
            cx.span_err(sp, "expected JSON literal");
            return DummyResult::expr(sp);
        }
    };

    let expr = match tt_to_expr(cx, tt) {
        Some(e) => e,
        None => return DummyResult::expr(sp)
    };
    MacExpr::new(expr)
}

fn tt_to_expr(cx: &ExtCtxt, tt: &TokenTree) -> Option<PExpr> {
    use syntax::ext::build::AstBuilder;

    match *tt {
        ast::TtToken(sp, ref tok) => token_to_expr(cx, sp, tok),
        ast::TtDelimited(sp, ref d) => {
            let ref toks = d.tts;
            match d.delim {
                // array
                token::Bracket => {
                    let exprs = match parse_array(cx, sp, toks.as_slice()) {
                        Some(e) => e,
                        None => return None
                    };
                    let exprs = cx.expr_vec(sp, exprs);
                    Some(quote_expr!(cx, {
                        {
                            use std::slice::BoxedSliceExt;
                            let xs: ::std::boxed::Box<[_]> = box $exprs;
                            ::rustc_serialize::json::Json::Array(xs.into_vec())
                        }
                    }))
                }
                // object
                token::Brace => {
                    let items = match parse_object(cx, sp, toks.as_slice()) {
                        Some(i) => i,
                        None => return None
                    };
                    let ob = quote_expr!(cx, _ob);
                    let mut stmts = vec![];
                    for &(ref key, ref value) in items.iter() {
                        stmts.push(quote_stmt!(cx, $ob.insert($key, $value)));
                    }

                    Some(quote_expr!(cx, {
                        {
                            let mut $ob = ::std::collections::BTreeMap::new();
                            $stmts;
                            ::rustc_serialize::json::Json::Object($ob)
                        }
                    }))
                }
                token::Paren => {
                    let mut parser = cx.new_parser_from_tts(toks.as_slice());
                    let expr = parser.parse_expr();

                    Some(quote_expr!(cx, {
                        use rustc_serialize::json::ToJson;
                        ($expr).to_json()
                    }))
                }
            }
        }
        ast::TtSequence(sp, _) => {
            cx.span_err(sp, "`json!` unexpected TtSequence");
            None
        }
    }
}

fn parse_array(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<PExpr>> {
    let mut exprs = Vec::with_capacity(tts.len() / 2);
    for (i, tt) in tts.iter().enumerate() {
        if i % 2 == 1 {
            match tt {
                &ast::TtToken(_, token::Comma) => {
                    continue;
                }
                _ => {
                    expected_but_found(cx, sp, "`,`", tt);
                    return None;
                }
            }
        }
        let expr = tt_to_expr(cx, tt);
        let expr = match expr {
            Some(e) => e,
            None => return None,
        };
        exprs.push(expr);
    }
    Some(exprs)
}

fn parse_object(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<(PExpr, PExpr)>> {
    use syntax::ast::TtToken;

    macro_rules! comma {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Comma)
        }
    }

    macro_rules! colon {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Colon)
        };
        ($sp:ident) => {
            ::syntax::ast::TtToken($sp, ::syntax::parse::token::Colon)
        }
    }

    let mut items = Vec::with_capacity(tts.len() / 4);
    if tts.len() == 0 {
        return Some(items);
    }

    // horrible
    for entry in tts.chunks(4) {
        use syntax::parse::token::{Lit, Literal};
        let item = match entry {
            // "foo": VALUE | "foo": VALUE,
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v] |
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v, comma!()] => {
                let k = n.as_str();
                let v = tt_to_expr(cx, v);
                if v.is_none() {
                    return None;
                }
                let k = quote_expr!(cx, {
                    use std::borrow::ToOwned;
                    $k.to_owned()
                });
                let v = quote_expr!(cx, $v);
                (k, v)
            }
            // "foo": VALUE X
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(), _, ref tt] => {
                expected_but_found(cx, sp, "`,`", tt);
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(sp)] => {
                cx.span_err(sp, "found `:` but no value afterwards");
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_) ,_)), ref tt, ..] => {
                expected_but_found(cx, sp, "`:`", tt);
                return None;
            }
            [TtToken(sp, Literal(Lit::Str_(_), _))] => {
                cx.span_err(sp, "found name but no colon-value afterwards");
                return None;
            }
            [ref tt, ..] => {
                expected_but_found(cx, sp, "string literal", tt);
                return None;
            }
            [] => unreachable!(), // chunks() never returns an empty slice
        };
        items.push(item);
    }

    Some(items)
}

fn token_to_expr(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> Option<PExpr> {
    use syntax::print::pprust;
    use syntax::parse::token::{Lit, Literal};

    match *tok {
        Literal(Lit::Str_(ref n), _) => {
            let s = n.as_str();
            Some(quote_expr!(cx, {
                use std::borrow::ToOwned;
                ::rustc_serialize::json::Json::String($s.to_owned())
            }))
        }
        // FIXME: handle suffixed literals (i.e. u64) correctly
        // FIXME: handle negative numbers
        Literal(Lit::Integer(_), _)=> {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::I64($tt as i64)
            }))
        }
        Literal(Lit::Float(_), _) => {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::F64($tt)
            }))
        }
        token::Ident(ref id, token::Plain) if id.as_str() == "null" => {
            Some(quote_expr!(cx, {
                ::rustc_serialize::json::Json::Null
            }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::True) => {
            Some(quote_expr!(cx, { ::rustc_serialize::json::Json::Boolean(true) }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::False) => {
            Some(quote_expr!(cx, { ::rustc_serialize::json::Json::Boolean(false) }))
        }
        _ => {
            let tt = ast::TtToken(sp, tok.clone());
            let s = pprust::tt_to_string(&tt);
            cx.span_err(sp, format!("unexpected `{}` in JSON", s).as_slice());
            None
        }
    }
}

fn best_span(sp: Span, tt: &TokenTree) -> Span {
    let sp = match *tt {
        ast::TtToken(tok_sp, _) => tok_sp,
        _ => sp // the span passed into the function!
    };
    sp
}

fn expected_but_found(cx: &ExtCtxt, sp: Span, expected: &str, found: &TokenTree) {
    let pp = pprust::tt_to_string(found);
    let err = format!("expected {} but found: `{}`", expected, pp);
    cx.span_err(best_span(sp, found), err.as_slice());
}
<|endoftext|>


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

use super::{Graphics, Drawer};
use draw::resize;
use std::time::Instant;

use glium::glutin::{Event, ElementState};

pub use glium::glutin::{VirtualKeyCode, MouseButton};

/// Methods `run_until_closed()` will call
pub trait Game{
    /// Method that gets called each frame from `run_until_closed()`.
    ///
    /// Should return a `GameUpdate` specifying things the game should do.
    fn frame(&mut self, FrameInfo, Drawer) -> GameUpdate;
}

impl<F: FnMut(FrameInfo, Drawer) -> GameUpdate> Game for F{
    fn frame(&mut self, info: FrameInfo, drawer: Drawer) -> GameUpdate{
        (self)(info, drawer)
    }
}

/// This is returned each frame from an object implementing `Game`.
///
/// It describes anything the game should do, e.g. closing the game.
pub struct GameUpdate{
    /// Describes whether the game should be closed
    pub close: bool,
    _fill: ()
}

impl GameUpdate {
    /// Nothing should be changed
    #[inline]
    pub fn nothing() -> Self{
        GameUpdate{
            close: false,
            _fill: ()
        }
    }

    /// Set whether to close the game
    pub fn set_close(self, close: bool) -> Self{
        GameUpdate{
            close: close,
            .. self
        }
    }
}

/// Runs the game until the window is closed
pub fn run_until_closed<G: Game>(mut graphics: Graphics, mut g: G){
    let mut last = Instant::now();
    let mut mousepos = (0., 0.);
    let mut down_keys = HashSet::new();

    'game: loop{
        let mut keys = Vec::new();
        let mut mouses = Vec::new();

        let mut resized = None::<(u32, u32)>;

        for ev in graphics.poll_events() {
            match ev {
                Event::Closed => break 'game,
                Event::KeyboardInput(es, _, Some(vkc)) => match es{
                    ElementState::Pressed  => {
                        down_keys.insert( vkc);
                        keys.push((true , vkc));
                    },
                    ElementState::Released => {
                        down_keys.remove(&vkc);
                        keys.push((false, vkc));
                    }
                },
                Event::MouseMoved(x, y) => {
                    let (w, h) = graphics.get_h_size();

                    mousepos = (x as f32 - w, h - y as f32);
                },
                // This is only neccessary because `graphics` gets immutably borrowed for this for-loop
                Event::Resized(w, h) => resized = Some((w, h)),
                Event::MouseInput(state, button) => mouses.push((state == ElementState::Pressed, button)),
                _ => ()
            }
        }

        if let Some((w, h)) = resized{
            resize(&mut graphics, w, h);
        }

        let dur = last.elapsed();
        let delta = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1e9;
        last = Instant::now();

        let update = FrameInfo{
            delta    : delta,
            key_events: keys,
            mouse_events: mouses,
            down_keys: &down_keys,
            mousepos : mousepos
        };

        let update = g.frame(update, Drawer::new(&graphics));

        if update.close{
            break
        }
    }
}

/// Wraps together useful data about what has happened (e.g. events)
#[derive(Debug)]
pub struct FrameInfo<'a>{
    /// The amount of time passed since last frame
    pub delta: f64,
    /// The last position of the mouse on the screen
    pub mousepos: (f32, f32),
    mouse_events: Vec<(bool, MouseButton)>,
    key_events: Vec<(bool, VirtualKeyCode)>,

    // All keys that are pressed down
    down_keys: &'a HashSet<VirtualKeyCode>
}

impl<'a> FrameInfo<'a>{
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_key_events(&self) -> &[(bool, VirtualKeyCode)]{
        &self.key_events
    }
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_mouse_events(&self) -> &[(bool, MouseButton)]{
        &self.mouse_events
    }
    #[inline]
    /// Checks whether a key is pressed down
    pub fn is_down(&self, key: &VirtualKeyCode) -> bool{
        self.down_keys.contains(key)
    }
}

/// Macro for easily doing things if particular keys are down
/// # Example
///
/// ```rust
// Sadly the macro has to written here again, becauase the example doesn't use macros from the crate
/// # macro_rules! is_down{( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{$( if $( $info.is_down(&$crate::VirtualKeyCode::$key) )||+ $b )+}}}
/// fn logic(player_y: &mut f32, info: korome::FrameInfo){
///     is_down!{info;
///         W, Up => {
///             *player_y -= l_args.delta() as f32;
///         },
///         S, Down => {
///             *player_y += l_args.delta() as f32;
///         }
///     };
/// }
/// ```
#[macro_export]
macro_rules! is_down{
    ( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{
        $( if $( $info.is_down(&$crate::VirtualKeyCode::$key) )||+ $b )+
    }}
}
<commit_msg>Fix is_down! test<commit_after>use std::collections::HashSet;

use super::{Graphics, Drawer};
use draw::resize;
use std::time::Instant;

use glium::glutin::{Event, ElementState};

pub use glium::glutin::{VirtualKeyCode, MouseButton};

/// Methods `run_until_closed()` will call
pub trait Game{
    /// Method that gets called each frame from `run_until_closed()`.
    ///
    /// Should return a `GameUpdate` specifying things the game should do.
    fn frame(&mut self, FrameInfo, Drawer) -> GameUpdate;
}

impl<F: FnMut(FrameInfo, Drawer) -> GameUpdate> Game for F{
    fn frame(&mut self, info: FrameInfo, drawer: Drawer) -> GameUpdate{
        (self)(info, drawer)
    }
}

/// This is returned each frame from an object implementing `Game`.
///
/// It describes anything the game should do, e.g. closing the game.
pub struct GameUpdate{
    /// Describes whether the game should be closed
    pub close: bool,
    _fill: ()
}

impl GameUpdate {
    /// Nothing should be changed
    #[inline]
    pub fn nothing() -> Self{
        GameUpdate{
            close: false,
            _fill: ()
        }
    }

    /// Set whether to close the game
    pub fn set_close(self, close: bool) -> Self{
        GameUpdate{
            close: close,
            .. self
        }
    }
}

/// Runs the game until the window is closed
pub fn run_until_closed<G: Game>(mut graphics: Graphics, mut g: G){
    let mut last = Instant::now();
    let mut mousepos = (0., 0.);
    let mut down_keys = HashSet::new();

    'game: loop{
        let mut keys = Vec::new();
        let mut mouses = Vec::new();

        let mut resized = None::<(u32, u32)>;

        for ev in graphics.poll_events() {
            match ev {
                Event::Closed => break 'game,
                Event::KeyboardInput(es, _, Some(vkc)) => match es{
                    ElementState::Pressed  => {
                        down_keys.insert( vkc);
                        keys.push((true , vkc));
                    },
                    ElementState::Released => {
                        down_keys.remove(&vkc);
                        keys.push((false, vkc));
                    }
                },
                Event::MouseMoved(x, y) => {
                    let (w, h) = graphics.get_h_size();

                    mousepos = (x as f32 - w, h - y as f32);
                },
                // This is only neccessary because `graphics` gets immutably borrowed for this for-loop
                Event::Resized(w, h) => resized = Some((w, h)),
                Event::MouseInput(state, button) => mouses.push((state == ElementState::Pressed, button)),
                _ => ()
            }
        }

        if let Some((w, h)) = resized{
            resize(&mut graphics, w, h);
        }

        let dur = last.elapsed();
        let delta = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1e9;
        last = Instant::now();

        let update = FrameInfo{
            delta    : delta,
            key_events: keys,
            mouse_events: mouses,
            down_keys: &down_keys,
            mousepos : mousepos
        };

        let update = g.frame(update, Drawer::new(&graphics));

        if update.close{
            break
        }
    }
}

/// Wraps together useful data about what has happened (e.g. events)
#[derive(Debug)]
pub struct FrameInfo<'a>{
    /// The amount of time passed since last frame
    pub delta: f64,
    /// The last position of the mouse on the screen
    pub mousepos: (f32, f32),
    mouse_events: Vec<(bool, MouseButton)>,
    key_events: Vec<(bool, VirtualKeyCode)>,

    // All keys that are pressed down
    down_keys: &'a HashSet<VirtualKeyCode>
}

impl<'a> FrameInfo<'a>{
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_key_events(&self) -> &[(bool, VirtualKeyCode)]{
        &self.key_events
    }
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_mouse_events(&self) -> &[(bool, MouseButton)]{
        &self.mouse_events
    }
    #[inline]
    /// Checks whether a key is pressed down
    pub fn is_down(&self, key: &VirtualKeyCode) -> bool{
        self.down_keys.contains(key)
    }
}

/// Macro for easily doing things if particular keys are down
/// # Example
///
/// ```rust
// Sadly the macro has to written here again, becauase the example doesn't use macros from the crate
/// # macro_rules! is_down{( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{$( if $( $info.is_down(&korome::VirtualKeyCode::$key) )||+ $b )+}}}
/// fn logic(player_y: &mut f64, info: korome::FrameInfo){
///     is_down!{info;
///         W, Up => {
///             *player_y -= info.delta
///         },
///         S, Down => {
///             *player_y += info.delta
///         }
///     };
/// }
/// ```
#[macro_export]
macro_rules! is_down{
    ( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{
        $( if $( $info.is_down(&$crate::VirtualKeyCode::$key) )||+ $b )+
    }}
}
<|endoftext|>


<commit_before>//! Mouse utility functions.

use crate::context::Context;
use crate::error::GameError;
use crate::error::GameResult;
use crate::graphics;
use crate::graphics::Point2;
use std::collections::HashMap;
use winit::dpi;
pub use winit::{MouseButton, MouseCursor};

/// Stores state information for the mouse.
#[derive(Clone, Debug)]
pub struct MouseContext {
    last_position: Point2,
    last_delta: Point2,
    buttons_pressed: HashMap<MouseButton, bool>,
    cursor_type: MouseCursor,
    cursor_grabbed: bool,
    cursor_hidden: bool,
}

impl MouseContext {
    pub(crate) fn new() -> Self {
        Self {
            last_position: Point2::origin(),
            last_delta: Point2::origin(),
            cursor_type: MouseCursor::Default,
            buttons_pressed: HashMap::new(),
            cursor_grabbed: false,
            cursor_hidden: false,
        }
    }

    pub(crate) fn set_last_position(&mut self, p: Point2) {
        self.last_position = p;
    }

    pub(crate) fn set_last_delta(&mut self, p: Point2) {
        self.last_delta = p;
    }

    pub(crate) fn set_button(&mut self, button: MouseButton, pressed: bool) {
        let _ = self.buttons_pressed.insert(button, pressed);
    }

    fn button_pressed(&self, button: MouseButton) -> bool {
        *(self.buttons_pressed.get(&button).unwrap_or(&false))
    }
}

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

/// Returns the current mouse cursor type of the window.
pub fn cursor_type(ctx: &Context) -> MouseCursor {
    ctx.mouse_context.cursor_type
}

/// Modifies the mouse cursor type of the window.
pub fn set_cursor_type(ctx: &mut Context, cursor_type: MouseCursor) {
    ctx.mouse_context.cursor_type = cursor_type;
    graphics::window(ctx).set_cursor(cursor_type);
}

/// Get whether or not the mouse is grabbed (confined to the window)
pub fn cursor_grabbed(ctx: &Context) -> bool {
    ctx.mouse_context.cursor_grabbed
}

/// Set whether or not the mouse is grabbed (confined to the window)
pub fn set_cursor_grabbed(ctx: &mut Context, grabbed: bool) -> GameResult<()> {
    ctx.mouse_context.cursor_grabbed = grabbed;
    graphics::window(ctx)
        .grab_cursor(grabbed)
        .map_err(|e| GameError::WindowError(e.to_string()))
}

/// Set whether or not the mouse is hidden (invisible)
pub fn cursor_hidden(ctx: &Context) -> bool {
    ctx.mouse_context.cursor_hidden
}

/// Set whether or not the mouse is hidden (invisible).
pub fn set_cursor_hidden(ctx: &mut Context, hidden: bool) {
    ctx.mouse_context.cursor_hidden = hidden;
    graphics::window(ctx).hide_cursor(hidden)
}

/// Get the current position of the mouse cursor, in pixels.
/// Complement to [`set_position()`](fn.set_position.html).
/// Uses strictly window-only coordinates.
pub fn position(ctx: &Context) -> Point2 {
    ctx.mouse_context.last_position
}

/// Set the current position of the mouse cursor, in pixels.
/// Uses strictly window-only coordinates.
pub fn set_position(ctx: &mut Context, point: Point2) -> GameResult<()> {
    ctx.mouse_context.last_position = point;
    graphics::window(ctx)
        .set_cursor_position(dpi::LogicalPosition {
            x: f64::from(point.x),
            y: f64::from(point.y),
        })
        .map_err(|_| GameError::WindowError("Couldn't set mouse cursor position!".to_owned()))
}

/// Get the distance the cursor was moved during last frame, in pixels.
pub fn delta(ctx: &Context) -> Point2 {
    ctx.mouse_context.last_delta
}

/// Returns whether or not the given mouse button is pressed.
pub fn button_pressed(ctx: &Context, button: MouseButton) -> bool {
    ctx.mouse_context.button_pressed(button)
}

/// TODO: Can we implement this?  Check with Winit peoples.
/// Winit doesn't implement it itself, we can do it by locking
/// the cursor to the window and resetting it to center each frame?
pub fn relative_mode() -> bool {
    unimplemented!()
}

/// TODO: Can we impement this?  Check with Winit peoples.
pub fn set_relative_mode() {
    unimplemented!()
}
<commit_msg>Remove nalgebra types from ggez::mouse interface.<commit_after>//! Mouse utility functions.

use crate::context::Context;
use crate::error::GameError;
use crate::error::GameResult;
use crate::graphics;
use crate::graphics::Point2;
use std::collections::HashMap;
use winit::dpi;
pub use winit::{MouseButton, MouseCursor};

/// Stores state information for the mouse.
#[derive(Clone, Debug)]
pub struct MouseContext {
    last_position: Point2,
    last_delta: Point2,
    buttons_pressed: HashMap<MouseButton, bool>,
    cursor_type: MouseCursor,
    cursor_grabbed: bool,
    cursor_hidden: bool,
}

impl MouseContext {
    pub(crate) fn new() -> Self {
        Self {
            last_position: Point2::origin(),
            last_delta: Point2::origin(),
            cursor_type: MouseCursor::Default,
            buttons_pressed: HashMap::new(),
            cursor_grabbed: false,
            cursor_hidden: false,
        }
    }

    pub(crate) fn set_last_position(&mut self, p: Point2) {
        self.last_position = p;
    }

    pub(crate) fn set_last_delta(&mut self, p: Point2) {
        self.last_delta = p;
    }

    pub(crate) fn set_button(&mut self, button: MouseButton, pressed: bool) {
        let _ = self.buttons_pressed.insert(button, pressed);
    }

    fn button_pressed(&self, button: MouseButton) -> bool {
        *(self.buttons_pressed.get(&button).unwrap_or(&false))
    }
}

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

/// Returns the current mouse cursor type of the window.
pub fn cursor_type(ctx: &Context) -> MouseCursor {
    ctx.mouse_context.cursor_type
}

/// Modifies the mouse cursor type of the window.
pub fn set_cursor_type(ctx: &mut Context, cursor_type: MouseCursor) {
    ctx.mouse_context.cursor_type = cursor_type;
    graphics::window(ctx).set_cursor(cursor_type);
}

/// Get whether or not the mouse is grabbed (confined to the window)
pub fn cursor_grabbed(ctx: &Context) -> bool {
    ctx.mouse_context.cursor_grabbed
}

/// Set whether or not the mouse is grabbed (confined to the window)
pub fn set_cursor_grabbed(ctx: &mut Context, grabbed: bool) -> GameResult<()> {
    ctx.mouse_context.cursor_grabbed = grabbed;
    graphics::window(ctx)
        .grab_cursor(grabbed)
        .map_err(|e| GameError::WindowError(e.to_string()))
}

/// Set whether or not the mouse is hidden (invisible)
pub fn cursor_hidden(ctx: &Context) -> bool {
    ctx.mouse_context.cursor_hidden
}

/// Set whether or not the mouse is hidden (invisible).
pub fn set_cursor_hidden(ctx: &mut Context, hidden: bool) {
    ctx.mouse_context.cursor_hidden = hidden;
    graphics::window(ctx).hide_cursor(hidden)
}

/// Get the current position of the mouse cursor, in pixels.
/// Complement to [`set_position()`](fn.set_position.html).
/// Uses strictly window-only coordinates.
pub fn position(ctx: &Context) -> mint::Point2<f32> {
    ctx.mouse_context.last_position.into()
}

/// Set the current position of the mouse cursor, in pixels.
/// Uses strictly window-only coordinates.
pub fn set_position<P>(ctx: &mut Context, point: P) -> GameResult<()>
    where P: Into<mint::Point2<f32>> {
    let mintpoint = point.into();
    ctx.mouse_context.last_position = Point2::from(mintpoint);
    graphics::window(ctx)
        .set_cursor_position(dpi::LogicalPosition {
            x: f64::from(mintpoint.x),
            y: f64::from(mintpoint.y),
        })
        .map_err(|_| GameError::WindowError("Couldn't set mouse cursor position!".to_owned()))
}

/// Get the distance the cursor was moved during last frame, in pixels.
pub fn delta(ctx: &Context) -> mint::Point2<f32> {
    ctx.mouse_context.last_delta.into()
}

/// Returns whether or not the given mouse button is pressed.
pub fn button_pressed(ctx: &Context, button: MouseButton) -> bool {
    ctx.mouse_context.button_pressed(button)
}

/// TODO: Can we implement this?  Check with Winit peoples.
/// Winit doesn't implement it itself, we can do it by locking
/// the cursor to the window and resetting it to center each frame?
pub fn relative_mode() -> bool {
    unimplemented!()
}

/// TODO: Can we impement this?  Check with Winit peoples.
pub fn set_relative_mode() {
    unimplemented!()
}
<|endoftext|>


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

type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<'a, T> {
    data_stack: Stack<T>,
    vocabulary: HashMap<&'a str, Word<T>>,
}

impl<'a, T> Interpreter<'a, T> where T: FromStr {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }

    fn eval_token(&mut self, token: &str) {
        if let Ok(literal) = token.parse::<T>() {
            self.push(literal);
        }
    }

    fn define_word(&mut self, name: &str, word: &Word<T>) {

    }

    fn lookup(&self, token: &str) -> Option<&Word<T>> {
        self.vocabulary.get(token)
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
        (self.entry)(i)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::Word;

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(move |i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn register_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.define_word("+", &plus);
        interpreter.push(51);
        interpreter.push(42);
        interpreter.eval_token("+");
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn push_literal() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.eval_token("42");
        assert_eq!(Some(42), interpreter.pop());
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<commit_msg>does lifetime have a meaning?<commit_after>use std::str::FromStr;
use std::collections::HashMap;

type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<'a, 'b, T: 'b> {
    data_stack: Stack<T>,
    vocabulary: HashMap<&'a str, &'b Word<T>>,
}

impl<'a, 'b, T: 'b> Interpreter<'a, 'b, T> where T: FromStr {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }

    fn eval_token(&mut self, token: &str) {
        if let Ok(literal) = token.parse::<T>() {
            self.push(literal);
        } else {
            if let Some(&word) = self.vocabulary.get(token) {
                word.eval_within(self);
            }
        }
    }

    fn define_word(&mut self, name: &'a str, word: &'b Word<T>) {
        self.vocabulary.insert(name, word);
    }

    fn lookup(&self, token: &str) -> Option<&&Word<T>> {
        self.vocabulary.get(token)
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, mut i: &mut Interpreter<T>) {
      (self.entry)(&mut i)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::Word;

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(|ref mut i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn register_word() {
        let plus = fixture_plus();
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.define_word("+", &plus);
        interpreter.push(51);
        interpreter.push(42);
        interpreter.eval_token("+");
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn push_literal() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.eval_token("42");
        assert_eq!(Some(42), interpreter.pop());
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<|endoftext|>


<commit_before>//! Contains code to handle an IPC channel which is issuing commands.

use std::io::Error as IOError;
use std::io::prelude::*;

use std::mem::transmute;

use rustc_serialize::Encodable;
use rustc_serialize::json::{Json, ToJson, Encoder, encode, ParserError, EncoderError};

use unix_socket::UnixStream;

/// Reasons a client message might be erroneous
#[derive(Debug)]
enum ResponseError {
    /// Connection was closed
    ConnectionClosed,
    /// Some bytes dun goofed
    InvalidString,
    /// There were IO issues
    IO(IOError),
    /// Json was invalid
    InvalidJson(ParserError),
    /// Couldn't format Json server-side
    UnableToFormat(EncoderError)
}

/// Receives a packet from the given stream.
fn receive_packet(stream: &mut Read) -> Result<Json, ResponseError> {
    let mut buffer = [0u8; 4];
    try!(stream.read_exact(&mut buffer).map_err(ResponseError::IO));
    // This is what the byteorder crate does (needs testing)
    let len = u32::from_be(buffer.as_ptr() as *const u32 as u32);
    trace!("Listening for packet of length {}", len);
    return Json::from_reader(&mut stream.take(len as u64))
        .map_err(ResponseError::InvalidJson);
}

fn write_packet(stream: &mut Write, packet: &Json) -> Result<(), ResponseError> {
    let json_string = try!(encode(packet).map_err(ResponseError::UnableToFormat));
    trace!("Writing packet of length {}: {}", json_string.len(), json_string);
    if json_string.len() > ::std::u32::MAX as usize {
        panic!("Attempted to send reply too big for the channel!");
    }
    let _len = json_string.len() as u32;
    let len_bytes = unsafe { transmute::<_, [u8; 4]>(_len) };
    stream.write_all(&len_bytes);
    stream.write_all(json_string.as_bytes()).map_err(ResponseError::IO)
}

pub fn handle_client(mut stream: UnixStream) {
    println!("Starting connection.");

    // Listen for starting connection
}

fn command(mut stream: UnixStream) {

}

fn event(mut stream: UnixStream) {

}
<commit_msg>Clean up u32 <-> bytes conversion code<commit_after>//! Contains code to handle an IPC channel which is issuing commands.

use std::io::Error as IOError;
use std::io::prelude::*;

use std::mem::transmute;
use std::mem::drop;

use rustc_serialize::Encodable;
use rustc_serialize::json::{Json, ToJson, Encoder, encode, ParserError, EncoderError};

use unix_socket::UnixStream;

/// Reasons a client message might be erroneous
#[derive(Debug)]
enum ResponseError {
    /// Connection was closed
    ConnectionClosed,
    /// Some bytes dun goofed
    InvalidString,
    /// There were IO issues
    IO(IOError),
    /// Json was invalid
    InvalidJson(ParserError),
    /// Couldn't format Json server-side
    UnableToFormat(EncoderError)
}

/// Receives a packet from the given stream.
fn receive_packet(stream: &mut Read) -> Result<Json, ResponseError> {
    let mut buffer = [0u8; 4];
    try!(stream.read_exact(&mut buffer).map_err(ResponseError::IO));
    // This is what the byteorder crate does (needs testing)
    let len: u32 = u32::from_be(unsafe { transmute(buffer) }); drop(buffer);
    trace!("Listening for packet of length {}", len);
    return Json::from_reader(&mut stream.take(len as u64))
        .map_err(ResponseError::InvalidJson);
}

fn write_packet(stream: &mut Write, packet: &Json) -> Result<(), ResponseError> {
    let json_string = try!(encode(packet).map_err(ResponseError::UnableToFormat));
    trace!("Writing packet of length {}: {}", json_string.len(), json_string);
    if json_string.len() > ::std::u32::MAX as usize {
        panic!("Attempted to send reply too big for the channel!");
    }
    let len = (json_string.len() as u32).to_be();
    let len_bytes: [u8; 4] = unsafe { transmute(len) }; drop(len);
    stream.write_all(&len_bytes);
    stream.write_all(json_string.as_bytes()).map_err(ResponseError::IO)
}

pub fn handle_client(mut stream: UnixStream) {
    println!("Starting connection.");

    // Listen for starting connection
}

fn command(mut stream: UnixStream) {

}

fn event(mut stream: UnixStream) {

}
<|endoftext|>


<commit_before>use std::io::{self, Read, BufRead, Write};

pub struct Converter {
    state: State,
    blank_line_count: usize,
    buffered_lines: String,
    warnings: Vec<Warning>,
}

use super::Warning;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum State { MarkdownBlank, MarkdownText, MarkdownMeta, Rust, }
impl Converter {
    pub fn new() -> Converter {
        Converter {
            state: State::MarkdownBlank,
            blank_line_count: 0,
            buffered_lines: String::new(),
            warnings: vec![],
        }
    }
}

pub enum Exception {
    IoError(io::Error),
    Warnings(Vec<Warning>),
}

impl From<io::Error> for Exception {
    fn from(e: io::Error) -> Self {
        Exception::IoError(e)
    }
}

impl Converter {
    pub fn convert<R:io::Read, W:io::Write>(mut self, r:R, mut w:W) -> Result<(), Exception> {
        let source = io::BufReader::new(r);
        for line in source.lines() {
            let line = try!(line);
            try!(self.handle(&line, &mut w));
        }
        if self.warnings.len() == 0 {
            Ok(())
        } else {
            Err(Exception::Warnings(self.warnings))
        }
    }

    pub fn handle(&mut self, line: &str, w: &mut Write) -> io::Result<()> {
        let str9 = line.chars().take(9).collect::<String>();
        let str7 = line.chars().take(7).collect::<String>();
        match (self.state, &str7[..], &str9[..]) {
            (State::MarkdownBlank, "```rust", _) |
            (State::MarkdownText, "```rust", _) => {
                self.buffered_lines = String::new();
                let rest =  &line.chars().skip(7).collect::<String>();
                if rest != "" {
                    try!(self.transition(w, State::MarkdownMeta));
                    try!(self.meta_note(&rest, w));
                }
                self.transition(w, State::Rust)
            }
            (State::MarkdownBlank, _, "```{.rust") |
            (State::MarkdownText, _, "```{.rust") => {
                self.buffered_lines = String::new();
                let rest =  &line.chars().skip(9).collect::<String>();
                if rest != "" {
                    try!(self.transition(w, State::MarkdownMeta));
                    try!(self.meta_note(&format!(" {{{}", rest), w));
                }
                self.transition(w, State::Rust)
            }
            (State::Rust, "```", _) => {
                self.transition(w, State::MarkdownBlank)
            }

            // FIXME: accum blank lines and only emit them with
            // prefix if there's no state transition; otherwise
            // emit them with no prefix. (This is in part the
            // motivation for the `fn finish_section` design.)
            (_, "", _) => {
                self.blank_line(w)
            }

            _ => {
                // HACK: if we find anything that looks like a markdown-named playpen link ...
                let open_pat = "[";
                let close_pat = "]: https://play.rust-lang.org/?code=";
                if let (Some(open), Some(close)) = (line.find(open_pat), line.find(close_pat)) {
                    // ... then we assume it is associated with the (hopefully immediately preceding)
                    // code block, so we emit a `//@@@` named tag for that code block.

                    // checking here that emitted code block matches
                    // up with emitted url. If non-match, then warn
                    // the user, and suggest they re-run `tango` after
                    // touching the file to generate matching url.
                    let expect = super::encode_to_url(&self.buffered_lines);
                    let actual = &line[(close+3)..];
                    if expect != actual {
                        self.warnings.push(Warning::EncodedUrlMismatch {
                            actual: actual.to_string(),
                            expect: expect
                        })
                    }
                    self.name_block(line, &line[open+1..close], w)
                } else {
                    self.nonblank_line(line, w)
                }
            }
        }
    }

    pub fn meta_note(&mut self, note: &str, w: &mut Write) -> io::Result<()> {
        assert!(note != "");
        self.nonblank_line(note, w)
    }

    pub fn name_block(&mut self, _line: &str, name: &str, w: &mut Write) -> io::Result<()> {
        assert!(name != "");
        writeln!(w, "//@@@ {}", name)
    }

    pub fn nonblank_line(&mut self, line: &str, w: &mut Write) -> io::Result<()> {
        let (blank_prefix, line_prefix) = match self.state {
            State::MarkdownBlank => ("", "//@ "),
            State::MarkdownText => ("//@", "//@ "),
            State::MarkdownMeta => ("//@", "//@@"),
            State::Rust => ("", ""),
        };
        for _ in 0..self.blank_line_count {
            try!(writeln!(w, "{}", blank_prefix));

        }
        self.blank_line_count = 0;

        match self.state {
            State::MarkdownBlank =>
                try!(self.transition(w, State::MarkdownText)),
            State::MarkdownMeta => {}
            State::MarkdownText => {}
            State::Rust => {
                self.buffered_lines.push_str("\n");
                self.buffered_lines.push_str(line);
            }
        }

        writeln!(w, "{}{}", line_prefix, line)
    }

    fn blank_line(&mut self, _w: &mut Write) -> io::Result<()> {
        match self.state {
            State::Rust => {
                self.buffered_lines.push_str("\n");
            }
            State::MarkdownBlank |
            State::MarkdownMeta |
            State::MarkdownText => {}
        }
        self.blank_line_count += 1;
        Ok(())
    }

    fn finish_section(&mut self, w: &mut Write) -> io::Result<()> {
        for _ in 0..self.blank_line_count {
            try!(writeln!(w, ""));
        }
        self.blank_line_count = 0;
        Ok(())
    }

    fn transition(&mut self, w: &mut Write, s: State) -> io::Result<()> {
        match s {
            State::MarkdownMeta => {
                assert!(self.state != State::Rust);
                try!(self.finish_section(w));
            }
            State::Rust => {
                assert!(self.state != State::Rust);
                self.buffered_lines = String::new();
            }
            State::MarkdownText => {
                assert_eq!(self.state, State::MarkdownBlank);
                try!(self.finish_section(w));
            }
            State::MarkdownBlank => {
                assert_eq!(self.state, State::Rust);
                try!(self.finish_section(w));
            }
        }
        self.state = s;
        Ok(())
    }
}
<commit_msg>remove import of unused `io::Read` trait.<commit_after>use std::io::{self, BufRead, Write};

pub struct Converter {
    state: State,
    blank_line_count: usize,
    buffered_lines: String,
    warnings: Vec<Warning>,
}

use super::Warning;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum State { MarkdownBlank, MarkdownText, MarkdownMeta, Rust, }
impl Converter {
    pub fn new() -> Converter {
        Converter {
            state: State::MarkdownBlank,
            blank_line_count: 0,
            buffered_lines: String::new(),
            warnings: vec![],
        }
    }
}

pub enum Exception {
    IoError(io::Error),
    Warnings(Vec<Warning>),
}

impl From<io::Error> for Exception {
    fn from(e: io::Error) -> Self {
        Exception::IoError(e)
    }
}

impl Converter {
    pub fn convert<R:io::Read, W:io::Write>(mut self, r:R, mut w:W) -> Result<(), Exception> {
        let source = io::BufReader::new(r);
        for line in source.lines() {
            let line = try!(line);
            try!(self.handle(&line, &mut w));
        }
        if self.warnings.len() == 0 {
            Ok(())
        } else {
            Err(Exception::Warnings(self.warnings))
        }
    }

    pub fn handle(&mut self, line: &str, w: &mut Write) -> io::Result<()> {
        let str9 = line.chars().take(9).collect::<String>();
        let str7 = line.chars().take(7).collect::<String>();
        match (self.state, &str7[..], &str9[..]) {
            (State::MarkdownBlank, "```rust", _) |
            (State::MarkdownText, "```rust", _) => {
                self.buffered_lines = String::new();
                let rest =  &line.chars().skip(7).collect::<String>();
                if rest != "" {
                    try!(self.transition(w, State::MarkdownMeta));
                    try!(self.meta_note(&rest, w));
                }
                self.transition(w, State::Rust)
            }
            (State::MarkdownBlank, _, "```{.rust") |
            (State::MarkdownText, _, "```{.rust") => {
                self.buffered_lines = String::new();
                let rest =  &line.chars().skip(9).collect::<String>();
                if rest != "" {
                    try!(self.transition(w, State::MarkdownMeta));
                    try!(self.meta_note(&format!(" {{{}", rest), w));
                }
                self.transition(w, State::Rust)
            }
            (State::Rust, "```", _) => {
                self.transition(w, State::MarkdownBlank)
            }

            // FIXME: accum blank lines and only emit them with
            // prefix if there's no state transition; otherwise
            // emit them with no prefix. (This is in part the
            // motivation for the `fn finish_section` design.)
            (_, "", _) => {
                self.blank_line(w)
            }

            _ => {
                // HACK: if we find anything that looks like a markdown-named playpen link ...
                let open_pat = "[";
                let close_pat = "]: https://play.rust-lang.org/?code=";
                if let (Some(open), Some(close)) = (line.find(open_pat), line.find(close_pat)) {
                    // ... then we assume it is associated with the (hopefully immediately preceding)
                    // code block, so we emit a `//@@@` named tag for that code block.

                    // checking here that emitted code block matches
                    // up with emitted url. If non-match, then warn
                    // the user, and suggest they re-run `tango` after
                    // touching the file to generate matching url.
                    let expect = super::encode_to_url(&self.buffered_lines);
                    let actual = &line[(close+3)..];
                    if expect != actual {
                        self.warnings.push(Warning::EncodedUrlMismatch {
                            actual: actual.to_string(),
                            expect: expect
                        })
                    }
                    self.name_block(line, &line[open+1..close], w)
                } else {
                    self.nonblank_line(line, w)
                }
            }
        }
    }

    pub fn meta_note(&mut self, note: &str, w: &mut Write) -> io::Result<()> {
        assert!(note != "");
        self.nonblank_line(note, w)
    }

    pub fn name_block(&mut self, _line: &str, name: &str, w: &mut Write) -> io::Result<()> {
        assert!(name != "");
        writeln!(w, "//@@@ {}", name)
    }

    pub fn nonblank_line(&mut self, line: &str, w: &mut Write) -> io::Result<()> {
        let (blank_prefix, line_prefix) = match self.state {
            State::MarkdownBlank => ("", "//@ "),
            State::MarkdownText => ("//@", "//@ "),
            State::MarkdownMeta => ("//@", "//@@"),
            State::Rust => ("", ""),
        };
        for _ in 0..self.blank_line_count {
            try!(writeln!(w, "{}", blank_prefix));

        }
        self.blank_line_count = 0;

        match self.state {
            State::MarkdownBlank =>
                try!(self.transition(w, State::MarkdownText)),
            State::MarkdownMeta => {}
            State::MarkdownText => {}
            State::Rust => {
                self.buffered_lines.push_str("\n");
                self.buffered_lines.push_str(line);
            }
        }

        writeln!(w, "{}{}", line_prefix, line)
    }

    fn blank_line(&mut self, _w: &mut Write) -> io::Result<()> {
        match self.state {
            State::Rust => {
                self.buffered_lines.push_str("\n");
            }
            State::MarkdownBlank |
            State::MarkdownMeta |
            State::MarkdownText => {}
        }
        self.blank_line_count += 1;
        Ok(())
    }

    fn finish_section(&mut self, w: &mut Write) -> io::Result<()> {
        for _ in 0..self.blank_line_count {
            try!(writeln!(w, ""));
        }
        self.blank_line_count = 0;
        Ok(())
    }

    fn transition(&mut self, w: &mut Write, s: State) -> io::Result<()> {
        match s {
            State::MarkdownMeta => {
                assert!(self.state != State::Rust);
                try!(self.finish_section(w));
            }
            State::Rust => {
                assert!(self.state != State::Rust);
                self.buffered_lines = String::new();
            }
            State::MarkdownText => {
                assert_eq!(self.state, State::MarkdownBlank);
                try!(self.finish_section(w));
            }
            State::MarkdownBlank => {
                assert_eq!(self.state, State::Rust);
                try!(self.finish_section(w));
            }
        }
        self.state = s;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use libc::{c_ulong, c_int};
use libc;
use {Result, NixPath};
use errno::Errno;

libc_bitflags!(
    pub struct MsFlags: c_ulong {
        /// Mount read-only
        MS_RDONLY;
        /// Ignore suid and sgid bits
        MS_NOSUID;
        /// Disallow access to device special files
        MS_NODEV;
        /// Disallow program execution
        MS_NOEXEC;
        /// Writes are synced at once
        MS_SYNCHRONOUS;
        /// Alter flags of a mounted FS
        MS_REMOUNT;
        /// Allow mandatory locks on a FS
        MS_MANDLOCK;
        /// Directory modifications are synchronous
        MS_DIRSYNC;
        /// Do not update access times
        MS_NOATIME;
        /// Do not update directory access times
        MS_NODIRATIME;
        /// Linux 2.4.0 - Bind directory at different place
        MS_BIND;
        MS_MOVE;
        MS_REC;
        MS_SILENT;
        MS_POSIXACL;
        MS_UNBINDABLE;
        MS_PRIVATE;
        MS_SLAVE;
        MS_SHARED;
        MS_RELATIME;
        MS_KERNMOUNT;
        MS_I_VERSION;
        MS_STRICTATIME;
        MS_ACTIVE;
        MS_NOUSER;
        MS_RMT_MASK;
        MS_MGC_VAL;
        MS_MGC_MSK;
    }
);

libc_bitflags!(
    pub struct MntFlags: c_int {
        MNT_FORCE;
        MNT_DETACH;
        MNT_EXPIRE;
    }
);

pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
        source: Option<&P1>,
        target: &P2,
        fstype: Option<&P3>,
        flags: MsFlags,
        data: Option<&P4>) -> Result<()> {
    use libc;

    let res =
        source.with_nix_path(|source| {
            target.with_nix_path(|target| {
                fstype.with_nix_path(|fstype| {
                    data.with_nix_path(|data| {
                        unsafe {
                            libc::mount(source.as_ptr(),
                                       target.as_ptr(),
                                       fstype.as_ptr(),
                                       flags.bits,
                                       data.as_ptr() as *const libc::c_void)
                        }
                    })
                })
            })
        })????;

    Errno::result(res).map(drop)
}

pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
    let res = target.with_nix_path(|cstr| {
        unsafe { libc::umount(cstr.as_ptr()) }
    })?;

    Errno::result(res).map(drop)
}

pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
    let res = target.with_nix_path(|cstr| {
        unsafe { libc::umount2(cstr.as_ptr(), flags.bits) }
    })?;

    Errno::result(res).map(drop)
}
<commit_msg>Remove a redundant "use libc"<commit_after>use libc::{self, c_ulong, c_int};
use {Result, NixPath};
use errno::Errno;

libc_bitflags!(
    pub struct MsFlags: c_ulong {
        /// Mount read-only
        MS_RDONLY;
        /// Ignore suid and sgid bits
        MS_NOSUID;
        /// Disallow access to device special files
        MS_NODEV;
        /// Disallow program execution
        MS_NOEXEC;
        /// Writes are synced at once
        MS_SYNCHRONOUS;
        /// Alter flags of a mounted FS
        MS_REMOUNT;
        /// Allow mandatory locks on a FS
        MS_MANDLOCK;
        /// Directory modifications are synchronous
        MS_DIRSYNC;
        /// Do not update access times
        MS_NOATIME;
        /// Do not update directory access times
        MS_NODIRATIME;
        /// Linux 2.4.0 - Bind directory at different place
        MS_BIND;
        MS_MOVE;
        MS_REC;
        MS_SILENT;
        MS_POSIXACL;
        MS_UNBINDABLE;
        MS_PRIVATE;
        MS_SLAVE;
        MS_SHARED;
        MS_RELATIME;
        MS_KERNMOUNT;
        MS_I_VERSION;
        MS_STRICTATIME;
        MS_ACTIVE;
        MS_NOUSER;
        MS_RMT_MASK;
        MS_MGC_VAL;
        MS_MGC_MSK;
    }
);

libc_bitflags!(
    pub struct MntFlags: c_int {
        MNT_FORCE;
        MNT_DETACH;
        MNT_EXPIRE;
    }
);

pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
        source: Option<&P1>,
        target: &P2,
        fstype: Option<&P3>,
        flags: MsFlags,
        data: Option<&P4>) -> Result<()> {

    let res =
        source.with_nix_path(|source| {
            target.with_nix_path(|target| {
                fstype.with_nix_path(|fstype| {
                    data.with_nix_path(|data| {
                        unsafe {
                            libc::mount(source.as_ptr(),
                                       target.as_ptr(),
                                       fstype.as_ptr(),
                                       flags.bits,
                                       data.as_ptr() as *const libc::c_void)
                        }
                    })
                })
            })
        })????;

    Errno::result(res).map(drop)
}

pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
    let res = target.with_nix_path(|cstr| {
        unsafe { libc::umount(cstr.as_ptr()) }
    })?;

    Errno::result(res).map(drop)
}

pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
    let res = target.with_nix_path(|cstr| {
        unsafe { libc::umount2(cstr.as_ptr(), flags.bits) }
    })?;

    Errno::result(res).map(drop)
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Panic handling.
//!
//! This module contains the `panic_fmt` language item. This function handles
//! panics at runtime.

use core::fmt::{Arguments, Write};
use super::io::term;
use vga::Color;

/// Called to handle a panic.
///
/// Since kernel panics are non-recoverable, this function prints out
/// the error message and hangs forever.
///
/// Eventually – way in the future – when we have disk I/O and stuff,
/// we'll probably want to write out some core dumps here as well.
#[lang = "panic_fmt"]
#[no_mangle] #[inline(never)] #[cold]
pub extern "C" fn rust_begin_unwind( args: Arguments
                                   , file: &'static str
                                   , line: usize )
                                   -> ! {
    let _ = write!( term::CONSOLE.lock()
                        .set_colors(Color::White, Color::Red)
                        .clear()
                  , "Something has gone horribly wrong in {} at line {}. \
                    \n{}\n\
                    This is fine."
                  , file, line, args
                  );
    loop { }
}
<commit_msg>[kernel] made panic handler not clear the screen so you can see what's happening<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Panic handling.
//!
//! This module contains the `panic_fmt` language item. This function handles
//! panics at runtime.

use core::fmt::{Arguments, Write};
use super::io::term;
use vga::Color;

/// Called to handle a panic.
///
/// Since kernel panics are non-recoverable, this function prints out
/// the error message and hangs forever.
///
/// Eventually – way in the future – when we have disk I/O and stuff,
/// we'll probably want to write out some core dumps here as well.
#[lang = "panic_fmt"]
#[no_mangle] #[inline(never)] #[cold]
pub extern "C" fn rust_begin_unwind( args: Arguments
                                   , file: &'static str
                                   , line: usize )
                                   -> ! {
    let _ = write!( term::CONSOLE.lock()
                        .set_colors(Color::White, Color::Red)
                  , "Something has gone horribly wrong in {} at line {}. \
                    \n{}\n\
                    This is fine."
                  , file, line, args
                  );
    loop { }
}
<|endoftext|>