<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//!  Note: this documentation is relative to `crowbook` *as a library*.
//!  For documentation regarding the *program* `crowbook`, see
//!  [the Github page](https://github.com/lise-henry/crowbook).
//!
//! # Usage
//!
//! Just like any other library, just add a dependency on `crowbook`
//! in your `Cargo.toml` file. You will probably want to deactivate
//! default features that are mostly useful for the binary:
//!
//! ```ignore
//! crowbook = {version = "0.10", default-features = false}
//! ```
//!
//! # Book
//!
//! The central structure of Crowbook is `Book`, which coordinates everything.
//!
//! Its roles are:
//!
//! * read a book configuration file and setting the book options accordingly;
//! * read the chapters (written in Markdown) listed in this
//!   configuration file and pass them to to `Parser`, get back an AST and store it in memory
//! * call the various renderers according to the book's parameters
//! and generate the appopriate files.
//!
//! ## Example
//!
//! ```ignore
//! use crowbook::{Book, InfoLevel};
//! // Reads configuration file "foo.book" (and set verbosity do default level)
//! let mut book = Book::new_from_file("foo.book", InfoLevel::Info, &[]).unwrap();
//! // Render all formats according to this configuration file
//! book.render_all().unwrap();
//! ```
//!
//! This is basically the code for the `crowbook` binary (though it contains a
//! bit more error handling, checking parameters from command line and so on).
//! This is, however, not very interesting for a library usage.
//!
//! The `Book` structure, however, exposes its `chapter` fields, which contains
//! a vector with an element by chapter. With it, you can access the Markdown
//! for all chapters represented as an Abstact Syntax Tree (i.e., a vector of `Token`s).
//! It is thus possible to create a new renderer (or manipulate this AST in other ways).
//!
//! # Parser
//!
//! It is also possible to directly use `Parser` to transform some markdown string or file
//! to this AST:
//!
//! ```
//! use crowbook::{Parser,Token};
//! let mut parser = Parser::new();
//! let result = parser.parse("Some *valid* Markdown").unwrap();
//! assert_eq!(format!("{:?}", result),
//! r#"[Paragraph([Str("Some "), Emphasis([Str("valid")]), Str(" Markdown")])]"#);
//! ```
//!
//! Of course, you probably want to do something else with this AST than display it.
//! Let's assume you want to count the number of links in a document.
//!
//! ```
//! use crowbook::{Parser,Token};
//! fn count(ast: &[Token]) -> u32 {
//!    let mut n = 0;
//!    for token in ast {
//!        match *token {
//!            // It's a link, increase counter
//!            Token::Link(_,_,_) => n += 1,
//!            // It's not a link, let's count the number of links
//!            // inside of the inner element (if there is one)
//!           _ => {
//!                if let Some(sub_ast) = token.inner() {
//!                    n += count(sub_ast);
//!                }
//!            }
//!       }
//!    }
//!    n
//! }
//!
//! let md = "# Here's a [link](http://foo.bar) #\n And *another [one](http://foo.bar)* !";
//!
//! let mut parser = Parser::new();
//! let ast = parser.parse(md).unwrap();
//! assert_eq!(count(&ast), 2);
//! ```

extern crate pulldown_cmark as cmark;
extern crate mustache;
extern crate chrono;
extern crate uuid;
extern crate yaml_rust;
extern crate mime_guess;
extern crate walkdir;
extern crate rustc_serialize;
extern crate crossbeam;
extern crate crowbook_text_processing;
extern crate crowbook_intl_runtime;
extern crate term;
#[macro_use]
extern crate lazy_static;

#[cfg(feature = "proofread")]
extern crate hyper;
#[cfg(feature = "proofread")]
extern crate url;
#[cfg(feature = "proofread")]
extern crate caribon;

pub use parser::Parser;
pub use book::Book;
pub use bookoption::BookOption;
pub use bookoptions::BookOptions;
pub use html::HtmlRenderer;
pub use epub::EpubRenderer;
pub use latex::LatexRenderer;
pub use odt::OdtRenderer;
pub use error::{Result, Error, Source};
pub use token::Token;
pub use token::Data;
pub use number::Number;
pub use resource_handler::ResourceHandler;
pub use logger::{Logger, InfoLevel};
pub use html_dir::HtmlDirRenderer;
pub use html_single::HtmlSingleRenderer;
pub use renderer::Renderer;
pub use crowbook_intl_runtime::set_lang;
pub use crowbook_intl_runtime::__get_lang;

#[macro_use]
#[doc(hidden)]
pub mod localize_macros;
#[macro_use]
mod html;
mod html_dir;
mod error;
mod book;
mod epub;
mod latex;
mod odt;
mod parser;
mod token;
mod cleaner;

mod number;
mod resource_handler;
mod logger;
mod bookoptions;
mod lang;
mod renderer;
mod html_single;

mod toc;
mod zipper;
mod templates;
mod bookoption;
mod misc;

#[cfg(feature = "proofread")]
mod grammar_check;
#[cfg(feature = "proofread")]
mod text_view;

#[cfg(test)]
mod tests;
<commit_msg>Make Parser private<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//!  Note: this documentation is relative to `crowbook` *as a library*.
//!  For documentation regarding the *program* `crowbook`, see
//!  [the Github page](https://github.com/lise-henry/crowbook).
//!
//! # Usage
//!
//! Just like any other library, just add a dependency on `crowbook`
//! in your `Cargo.toml` file. You will probably want to deactivate
//! default features that are mostly useful for the binary:
//!
//! ```ignore
//! crowbook = {version = "0.10", default-features = false}
//! ```
//!
//! # Book
//!
//! The central structure of Crowbook is `Book`, which coordinates everything.
//!
//! Its roles are:
//!
//! * read a book configuration file and setting the book options accordingly;
//! * read the chapters (written in Markdown) listed in this
//!   configuration file and pass them to to `Parser`, get back an AST and store it in memory
//! * call the various renderers according to the book's parameters
//! and generate the appopriate files.
//!
//! ## Example
//!
//! ```ignore
//! use crowbook::{Book, InfoLevel};
//! // Reads configuration file "foo.book" (and set verbosity do default level)
//! let mut book = Book::new_from_file("foo.book", InfoLevel::Info, &[]).unwrap();
//! // Render all formats according to this configuration file
//! book.render_all().unwrap();
//! ```
//!
//! This is basically the code for the `crowbook` binary (though it contains a
//! bit more error handling, checking parameters from command line and so on).
//! This is, however, not very interesting for a library usage.
//!
//! The `Book` structure, however, exposes its `chapter` fields, which contains
//! a vector with an element by chapter. With it, you can access the Markdown
//! for all chapters represented as an Abstact Syntax Tree (i.e., a vector of `Token`s).
//! It is thus possible to create a new renderer (or manipulate this AST in other ways).
//!
//! # Parser
//!
//! It is also possible to directly use `Parser` to transform some markdown string or file
//! to this AST:
//!
//! ```
//! use crowbook::{Parser,Token};
//! let mut parser = Parser::new();
//! let result = parser.parse("Some *valid* Markdown").unwrap();
//! assert_eq!(format!("{:?}", result),
//! r#"[Paragraph([Str("Some "), Emphasis([Str("valid")]), Str(" Markdown")])]"#);
//! ```
//!
//! Of course, you probably want to do something else with this AST than display it.
//! Let's assume you want to count the number of links in a document.
//!
//! ```
//! use crowbook::{Parser,Token};
//! fn count(ast: &[Token]) -> u32 {
//!    let mut n = 0;
//!    for token in ast {
//!        match *token {
//!            // It's a link, increase counter
//!            Token::Link(_,_,_) => n += 1,
//!            // It's not a link, let's count the number of links
//!            // inside of the inner element (if there is one)
//!           _ => {
//!                if let Some(sub_ast) = token.inner() {
//!                    n += count(sub_ast);
//!                }
//!            }
//!       }
//!    }
//!    n
//! }
//!
//! let md = "# Here's a [link](http://foo.bar) #\n And *another [one](http://foo.bar)* !";
//!
//! let mut parser = Parser::new();
//! let ast = parser.parse(md).unwrap();
//! assert_eq!(count(&ast), 2);
//! ```

extern crate pulldown_cmark as cmark;
extern crate mustache;
extern crate chrono;
extern crate uuid;
extern crate yaml_rust;
extern crate mime_guess;
extern crate walkdir;
extern crate rustc_serialize;
extern crate crossbeam;
extern crate crowbook_text_processing;
extern crate crowbook_intl_runtime;
extern crate term;
#[macro_use]
extern crate lazy_static;

#[cfg(feature = "proofread")]
extern crate hyper;
#[cfg(feature = "proofread")]
extern crate url;
#[cfg(feature = "proofread")]
extern crate caribon;

pub use book::Book;
pub use bookoption::BookOption;
pub use bookoptions::BookOptions;
pub use html::HtmlRenderer;
pub use epub::EpubRenderer;
pub use latex::LatexRenderer;
pub use odt::OdtRenderer;
pub use error::{Result, Error, Source};
pub use token::Token;
pub use token::Data;
pub use number::Number;
pub use resource_handler::ResourceHandler;
pub use logger::{Logger, InfoLevel};
pub use html_dir::HtmlDirRenderer;
pub use html_single::HtmlSingleRenderer;
pub use renderer::Renderer;
pub use crowbook_intl_runtime::set_lang;
pub use crowbook_intl_runtime::__get_lang;

#[macro_use]
#[doc(hidden)]
pub mod localize_macros;
#[macro_use]
mod html;
mod html_dir;
mod error;
mod book;
mod epub;
mod latex;
mod odt;
mod parser;
mod token;
mod cleaner;

mod number;
mod resource_handler;
mod logger;
mod bookoptions;
mod lang;
mod renderer;
mod html_single;

mod toc;
mod zipper;
mod templates;
mod bookoption;
mod misc;

#[cfg(feature = "proofread")]
mod grammar_check;
#[cfg(feature = "proofread")]
mod text_view;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Sender<LuaQuery>> = {
        let (tx, rx) = channel::<LuaQuery>();
        Mutex::new(tx)
    };

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Receiver<LuaResponse>> = {
        let (tx, rx) = channel::<LuaResponse>();
        Mutex::new(rx)
    };

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Messages sent to the lua thread
pub enum LuaQuery {
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,
    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecuteFile(String),
    /// Get a variable
    GetVariable(String),
    /// Set a value
    SetValue {
        name: Box<::std::borrow::Borrow<str> + Sized>,
        val: Box<hlua::Push<&'static mut Lua<'static>> + Sized>
    },
    /// Create a new array
    EmptyArray(String),
    /// Unused send type
    Unused,
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>)
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Send a value to the lua thread
pub fn send(query: LuaQuery) {
    SENDER.lock().unwrap().send(query).unwrap();
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = query_tx;
        *receiver = answer_rx;
    }

    thread::spawn(move || {
        trace!("thread: Inside thread!");
        let sender = answer_tx;
        let receiver = query_rx;
        let mut lua = Lua::new();
        trace!("thread: Loading libraries...");
        lua.openlibs();
        trace!("thread: Libraries loaded");
        trace!("thread: Testing hello world...");
        let mut file = File::create("/tmp/init.lua").unwrap();
        file.write(b"print('Hello world!')").unwrap();
        lua.execute_from_reader::<(), File>(File::open("/tmp/init.lua")
                                            .unwrap()).unwrap();
        trace!("thread: Done!");
        trace!("thread: Entering loop...");
        thread_main_loop(sender, receiver, &mut lua);
    });
    trace!("Created thread. Init finished.");
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>, request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");

            error!("thread: Lua thread restart not supported!");
            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecuteFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetVariable(varname) => {
            trace!("thread: Received request to get variable {}", varname);
            let var_result = lua.get(varname.as_str());

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: name, val: val } => {

        },

        LuaQuery::EmptyArray(name) => {

        },

        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(e) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<commit_msg>Add lua thread running checks<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Sender<LuaQuery>> = {
        let (tx, rx) = channel::<LuaQuery>();
        Mutex::new(tx)
    };

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Receiver<LuaResponse>> = {
        let (tx, rx) = channel::<LuaResponse>();
        Mutex::new(rx)
    };

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Messages sent to the lua thread
pub enum LuaQuery {
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,
    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecuteFile(String),
    /// Get a variable
    GetVariable(String),
    /// Set a value
    SetValue {
        name: Box<::std::borrow::Borrow<str> + Sized>,
        val: Box<hlua::Push<&'static mut Lua<'static>> + Sized>
    },
    /// Create a new array
    EmptyArray(String),
    /// Unused send type
    Unused,
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>)
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Send a value to the lua thread
pub fn send(query: LuaQuery) {
    if !thread_running() {
        panic!("lua: Attempted to message the lua thread while it is not active!");
    }
    SENDER.lock().unwrap().send(query).unwrap();
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = query_tx;
        *receiver = answer_rx;
    }

    thread::spawn(move || {
        trace!("thread: Inside thread!");
        let sender = answer_tx;
        let receiver = query_rx;
        let mut lua = Lua::new();
        trace!("thread: Loading libraries...");
        lua.openlibs();
        trace!("thread: Libraries loaded");
        *RUNNING.write().unwrap() = true;
        trace!("thread: Testing hello world...");
        let mut file = File::create("/tmp/init.lua").unwrap();
        file.write(b"print('Hello world!')").unwrap();
        lua.execute_from_reader::<(), File>(File::open("/tmp/init.lua")
                                            .unwrap()).unwrap();
        trace!("thread: Done!");
        trace!("thread: Entering loop...");
        thread_main_loop(sender, receiver, &mut lua);
    });
    trace!("Created thread. Init finished.");
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>, request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecuteFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetVariable(varname) => {
            trace!("thread: Received request to get variable {}", varname);
            let var_result = lua.get(varname.as_str());

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: name, val: val } => {

        },

        LuaQuery::EmptyArray(name) => {

        },

        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(e) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] x M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // M[A] <- M[B] / M[C]
            10 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b / c;
                self.counter += 4;
            },

            // M[A] <- M[B] modulo M[C]
            11 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b % c;
                self.counter += 4;
            },

            // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
            12 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b < c {
                  self.memory[a as usize] = 1;
                } else {
                  self.memory[a as usize] = 0;
                }
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(9, 0, 1, 2);
        assert_eq!(Some(&6), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_10() {
        let mut m = Machine::with_data(vec![1, 6, 2]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(10, 0, 1, 2);
        assert_eq!(Some(&3), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_11() {
        let mut m = Machine::with_data(vec![1, 11, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(11, 0, 1, 2);
        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_then_branch() {
        let mut m = Machine::with_data(vec![2, 3, 4]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_else_branch() {
        let mut m = Machine::with_data(vec![2, 4, 3]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<commit_msg>Keep test names for branching opcodes the same.<commit_after>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] x M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // M[A] <- M[B] / M[C]
            10 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b / c;
                self.counter += 4;
            },

            // M[A] <- M[B] modulo M[C]
            11 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b % c;
                self.counter += 4;
            },

            // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
            12 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b < c {
                  self.memory[a as usize] = 1;
                } else {
                  self.memory[a as usize] = 0;
                }
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_then_branch() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else_branch() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(9, 0, 1, 2);
        assert_eq!(Some(&6), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_10() {
        let mut m = Machine::with_data(vec![1, 6, 2]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(10, 0, 1, 2);
        assert_eq!(Some(&3), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_11() {
        let mut m = Machine::with_data(vec![1, 11, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(11, 0, 1, 2);
        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_then_branch() {
        let mut m = Machine::with_data(vec![2, 3, 4]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_else_branch() {
        let mut m = Machine::with_data(vec![2, 4, 3]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<|endoftext|>


<commit_before>//! Network interface name resolution.
//!
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.

use libc;
use libc::c_uint;
use std::ffi::{CString, NulError};
use ::{Result, Error};

/// Resolve an interface into a interface number.
pub fn if_nametoindex(name: &str) -> Result<c_uint> {
    let name = match CString::new(name) {
        Err(e) => match e { NulError(..) => {
            // A NulError indicates that a '\0' was found inside the string,
            // making it impossible to create valid C-String. To avoid having
            // to create a new error type for this rather rare case,
            // nix::Error's invalid_argument() constructor is used.
            //
            // We match the NulError individually here to ensure to avoid
            // accidentally returning invalid_argument() for errors other than
            // NulError (which currently don't exist).
            return Err(Error::invalid_argument());
        }},
        Ok(s) => s
    };

    let if_index;
    unsafe {
        if_index = libc::if_nametoindex(name.as_ptr());
    }

    if if_index == 0 { Err(Error::last()) } else { Ok(if_index) }
}
<commit_msg>Use NixPath for if_nametoindex<commit_after>//! Network interface name resolution.
//!
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.

use libc;
use libc::c_uint;
use {Result, Error, NixPath};

/// Resolve an interface into a interface number.
pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
    let if_index = try!(name.with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) }));

    if if_index == 0 {
        Err(Error::last())
    } else {
        Ok(if_index)
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Prepare
//!
//! If a pattern needs to be matched against many different things, it can be prepared in order to generate an object that can
//! be used many times without the delay of generating a DFA.
//!
//! ```
//! # use ndfa::*;
//! let match_abcs      = "abc".prepare_to_match();
//! let match_many_abcs = "abc".repeat_forever(1).prepare_to_match();
//! ```
//!

use super::countable::*;
use super::symbol_range::*;
use super::state_machine::*;
use super::regular_pattern::*;
use super::symbol_range_dfa::*;
use super::dfa_compiler::*;

///
/// Can be applied to patterns and other objects in order to match them
///
pub trait PrepareToMatch<As> where As: Sized {
    fn prepare_to_match(self) -> As where Self: Sized;
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol: Ord+Clone> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let builder       = SymbolRangeDfaBuilder::new();
        let state_machine = DfaCompiler::build(self, builder);

        state_machine
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for Pattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let ndfa = self.to_ndfa(true);

        ndfa.prepare_to_match()
    }
}

impl<'a, InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for &'a ToPattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        self
    }
}

impl<'a> PrepareToMatch<SymbolRangeDfa<char, bool>>
for &'a str {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<char, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}
<commit_msg>Where clause not needed<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Prepare
//!
//! If a pattern needs to be matched against many different things, it can be prepared in order to generate an object that can
//! be used many times without the delay of generating a DFA.
//!
//! ```
//! # use ndfa::*;
//! let match_abcs      = "abc".prepare_to_match();
//! let match_many_abcs = "abc".repeat_forever(1).prepare_to_match();
//! ```
//!

use super::countable::*;
use super::symbol_range::*;
use super::state_machine::*;
use super::regular_pattern::*;
use super::symbol_range_dfa::*;
use super::dfa_compiler::*;

///
/// Can be applied to patterns and other objects in order to match them
///
pub trait PrepareToMatch<As> where As: Sized {
    fn prepare_to_match(self) -> As;
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol: Ord+Clone> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let builder       = SymbolRangeDfaBuilder::new();
        let state_machine = DfaCompiler::build(self, builder);

        state_machine
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for Pattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let ndfa = self.to_ndfa(true);

        ndfa.prepare_to_match()
    }
}

impl<'a, InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for &'a ToPattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        self
    }
}

impl<'a> PrepareToMatch<SymbolRangeDfa<char, bool>>
for &'a str {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<char, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::process::{Command, Stdio};
use std::io::prelude::*;
use std::io::BufReader;
use std::error::Error;
use std::fmt;

const PROBLEMS_DIR: &'static str = "problems";
const INPUT_DIR: &'static str = "input";
const OUTPUT_DIR: &'static str = "output";

pub struct Problem {
	str_id: String,
	statement: Vec<String>,
	name: Vec<String>,
	authors: Vec<String>,
}

enum State {
	Default,
	Name,
	Statement,
	Authors,
}

struct ProblemError {
	sys_part: String,
	reason: &'static str,
	problem_strid: String,
	test_no: i32,
}

impl Error for ProblemError {
	fn description(&self) -> &str {
        self.reason
    }
}

impl fmt::Display for ProblemError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		if self.test_no >= 0 {
			write!(f, "{} on problem {} at test {}: {}", self.reason, self.problem_strid,
				self.test_no, self.sys_part)
		}
		else {
			write!(f, "{} on problem {}: {}", self.reason, self.problem_strid,
				self.sys_part)
		}
	}
}

impl fmt::Debug for ProblemError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		if self.test_no >= 0 {
			write!(f, "{} on problem {} at test {}: {}", self.reason, self.problem_strid,
				self.test_no, self.sys_part)
		}
		else {
			write!(f, "{} on problem {}: {}", self.reason, self.problem_strid,
				self.sys_part)
		}
	}
}

impl Problem {
	pub fn new(str_id: String) -> Problem {
		let mut statement = vec![];
		let mut name = vec![];
		let mut authors = vec![];
		match File::open(format!("{}/{}/info.txt", PROBLEMS_DIR, str_id)) {
			Ok(file) => {
				let buf = BufReader::new(&file);
				let mut state = State::Default;
				for line in buf.lines()  {
					let l = line.unwrap();
					match l.as_ref() {
						"[authors]" => state = State::Authors,
						"[name]" => state = State::Name,
						"[statement]" => state = State::Statement,
						"[end]" => break,
						_ => {
							match state {
								State::Authors => authors.push(l.trim().to_string()),
								State::Name => name.push(l.trim().to_string()),
								State::Statement => statement.push(l.trim().to_string()),
								_ => continue
							}
						}
					}
				}
			},
			Err(err) => panic!("Unable to load problem \"{}\" info: {}", str_id, err),
		};
		Problem {
			str_id: str_id,
			statement: statement,
			name: name,
			authors: authors,
		}
	}
	pub fn run(&self) -> Result<(), ProblemError> {
		let builder = match Command::new("rustc")
			.arg(format!("{}/{}/{}.rs", PROBLEMS_DIR, self.str_id, self.str_id))
			.arg("--out-dir")
			.arg(format!("{}/{}", PROBLEMS_DIR, self.str_id))
			.output() {
				Ok(cmd) => cmd,
				Err(e) => return self.make_error("failed to execute rustc", e.to_string(), -1),
			};

		if !builder.status.success() {
			let s = String::from_utf8_lossy(&builder.stderr);
			return self.make_error("rustc failed to build problem", s.into_owned(), -1)
		}
		return self.run_test(1);
	}

	fn run_test(&self, test_no: i32) -> Result<(), ProblemError> {
		let mut input = match File::open(format!("{}/{}/{}/{}.txt",
			PROBLEMS_DIR, self.str_id, INPUT_DIR, test_no)) {
			Ok(file) => file,
			Err(e) => return self.make_error("failed to load test", e.to_string(), test_no),
		};

		let mut s = String::new(); // passing throw String coz as_slice still unstable
		let result = input.read_to_string(&mut s);
		if result.is_err() {
			return self.make_error("couldn't read test", result.err().unwrap().to_string(), test_no);
		}

		let problem = match Command::new(format!("{}/{}/{}", PROBLEMS_DIR, self.str_id, self.str_id))
			.stdin(Stdio::piped())
			.stdout(Stdio::piped())
			.spawn() {
				Ok(cmd) => cmd,
				Err(e) => return self.make_error("failed to execute test", e.to_string(), test_no),
			};

		let result = problem.stdin.unwrap().write_all(s.as_bytes());
		if result.is_err() {
			return self.make_error("couldn't send stdin to test", result.err().unwrap().to_string(), test_no);
		}

		let mut s = String::new(); // passing throw String coz as_slice still unstable
		let result = problem.stdout.unwrap().read_to_string(&mut s);
		if result.is_err() {
			return self.make_error("couldn't read stdout from test", result.err().unwrap().to_string(), test_no);
		}

		let mut output = match File::create(format!("{}/{}/{}/{}.txt",
			PROBLEMS_DIR, self.str_id, OUTPUT_DIR, test_no)) {
			Ok(file) => file,
			Err(e) => return self.make_error("failed to create test output file", e.to_string(), test_no),
		};

		let result = output.write_all(s.as_bytes());
		if result.is_err() {
			return self.make_error("couldn't write test answer", result.err().unwrap().to_string(), test_no);
		}
		Ok(())
	}

	fn make_error(&self, reason: &'static str, sys_part: String, test_no: i32) -> Result<(), ProblemError> {
		Err(ProblemError {
			reason:reason,
			sys_part: sys_part,
			problem_strid: self.str_id.clone(),
			test_no: test_no
		})
	}
}

#[test]
fn read_test() {
	let p = Problem::new("test".to_string());
	assert_eq!(p.str_id, "test");
	assert_eq!(p.authors, vec!["Testhor", "qwerty"]);
	assert_eq!(p.name, vec!["Test name", "check"]);
	assert_eq!(p.statement, vec!["Test statement", "3", "4"]);
	let result = p.run();
	if result.is_err() {
		panic!(result.err().unwrap().to_string());
	}
}<commit_msg>fixed build<commit_after>use std::fs;
use std::fs::File;
use std::process::{Command, Stdio};
use std::io::prelude::*;
use std::io::BufReader;
use std::error::Error;
use std::fmt;

const PROBLEMS_DIR: &'static str = "problems";
const INPUT_DIR: &'static str = "input";
const OUTPUT_DIR: &'static str = "output";

pub struct Problem {
	str_id: String,
	statement: Vec<String>,
	name: Vec<String>,
	authors: Vec<String>,
}

enum State {
	Default,
	Name,
	Statement,
	Authors,
}

struct ProblemError {
	sys_part: String,
	reason: &'static str,
	problem_strid: String,
	test_no: i32,
}

impl Error for ProblemError {
	fn description(&self) -> &str {
        self.reason
    }
}

impl fmt::Display for ProblemError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		if self.test_no >= 0 {
			write!(f, "{} on problem {} at test {}: {}", self.reason, self.problem_strid,
				self.test_no, self.sys_part)
		}
		else {
			write!(f, "{} on problem {}: {}", self.reason, self.problem_strid,
				self.sys_part)
		}
	}
}

impl fmt::Debug for ProblemError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		if self.test_no >= 0 {
			write!(f, "{} on problem {} at test {}: {}", self.reason, self.problem_strid,
				self.test_no, self.sys_part)
		}
		else {
			write!(f, "{} on problem {}: {}", self.reason, self.problem_strid,
				self.sys_part)
		}
	}
}

impl Problem {
	pub fn new(str_id: String) -> Problem {
		let mut statement = vec![];
		let mut name = vec![];
		let mut authors = vec![];
		match File::open(format!("{}/{}/info.txt", PROBLEMS_DIR, str_id)) {
			Ok(file) => {
				let buf = BufReader::new(&file);
				let mut state = State::Default;
				for line in buf.lines()  {
					let l = line.unwrap();
					match l.as_ref() {
						"[authors]" => state = State::Authors,
						"[name]" => state = State::Name,
						"[statement]" => state = State::Statement,
						"[end]" => break,
						_ => {
							match state {
								State::Authors => authors.push(l.trim().to_string()),
								State::Name => name.push(l.trim().to_string()),
								State::Statement => statement.push(l.trim().to_string()),
								_ => continue
							}
						}
					}
				}
			},
			Err(err) => panic!("Unable to load problem \"{}\" info: {}", str_id, err),
		};
		Problem {
			str_id: str_id,
			statement: statement,
			name: name,
			authors: authors,
		}
	}
	pub fn run(&self) -> Result<(), ProblemError> {
		let builder = match Command::new("rustc")
			.arg(format!("{}/{}/{}.rs", PROBLEMS_DIR, self.str_id, self.str_id))
			.arg("--out-dir")
			.arg(format!("{}/{}", PROBLEMS_DIR, self.str_id))
			.output() {
				Ok(cmd) => cmd,
				Err(e) => return self.make_error("failed to execute rustc", e.to_string(), -1),
			};

		if !builder.status.success() {
			let s = String::from_utf8_lossy(&builder.stderr);
			return self.make_error("rustc failed to build problem", s.into_owned(), -1)
		}
		return self.run_test(1);
	}

	fn run_test(&self, test_no: i32) -> Result<(), ProblemError> {
		let mut input = match File::open(format!("{}/{}/{}/{}.txt",
			PROBLEMS_DIR, self.str_id, INPUT_DIR, test_no)) {
			Ok(file) => file,
			Err(e) => return self.make_error("failed to load test", e.to_string(), test_no),
		};

		let mut s = String::new(); // passing throw String coz as_slice still unstable
		let result = input.read_to_string(&mut s);
		if result.is_err() {
			return self.make_error("couldn't read test", result.err().unwrap().to_string(), test_no);
		}

		let problem = match Command::new(format!("{}/{}/{}", PROBLEMS_DIR, self.str_id, self.str_id))
			.stdin(Stdio::piped())
			.stdout(Stdio::piped())
			.spawn() {
				Ok(cmd) => cmd,
				Err(e) => return self.make_error("failed to execute test", e.to_string(), test_no),
			};

		let result = problem.stdin.unwrap().write_all(s.as_bytes());
		if result.is_err() {
			return self.make_error("couldn't send stdin to test", result.err().unwrap().to_string(), test_no);
		}

		let mut s = String::new(); // passing throw String coz as_slice still unstable
		let result = problem.stdout.unwrap().read_to_string(&mut s);
		if result.is_err() {
			return self.make_error("couldn't read stdout from test", result.err().unwrap().to_string(), test_no);
		}

		let result = fs::create_dir_all(format!("{}/{}/{}", PROBLEMS_DIR, self.str_id, OUTPUT_DIR));
		if result.is_err() {
			return self.make_error("couldn't write test answer", result.err().unwrap().to_string(), test_no);
		}
		let mut output = match File::create(format!("{}/{}/{}/{}.txt",
			PROBLEMS_DIR, self.str_id, OUTPUT_DIR, test_no)) {
			Ok(file) => file,
			Err(e) => return self.make_error("failed to create test output file", e.to_string(), test_no),
		};

		let result = output.write_all(s.as_bytes());
		if result.is_err() {
			return self.make_error("couldn't write test answer", result.err().unwrap().to_string(), test_no);
		}
		Ok(())
	}

	fn make_error(&self, reason: &'static str, sys_part: String, test_no: i32) -> Result<(), ProblemError> {
		Err(ProblemError {
			reason:reason,
			sys_part: sys_part,
			problem_strid: self.str_id.clone(),
			test_no: test_no
		})
	}
}

#[test]
fn read_test() {
	let p = Problem::new("test".to_string());
	assert_eq!(p.str_id, "test");
	assert_eq!(p.authors, vec!["Testhor", "qwerty"]);
	assert_eq!(p.name, vec!["Test name", "check"]);
	assert_eq!(p.statement, vec!["Test statement", "3", "4"]);
	let result = p.run();
	if result.is_err() {
		panic!(result.err().unwrap().to_string());
	}
}<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::ffi::CString;
use super::gl_lib as gl;
use super::gl_lib::types::*;
use super::types::GLError;
use super::context::Context;
use super::shader::Shader;

pub struct Program {
    gl_id: GLuint
}

impl Program {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Program {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteProgram(self.gl_id);
        }
    }
}

impl Context {
    pub fn create_program(&self) -> Result<Program, ()> {
        unsafe {
            let id = gl::CreateProgram();
            if id > 0 {
                Ok(Program { gl_id: id })
            }
            else {
                Err(())
            }
        }
    }

    pub fn attach_shader(&self, program: &mut Program, shader: &Shader) {
        unsafe {
            gl::AttachShader(program.gl_id(), shader.gl_id());
        }
    }

    pub fn link_program(&self, program: &mut Program) -> Result<(), GLError> {
        let success = unsafe {
            gl::LinkProgram(program.gl_id());
            let mut link_status : GLint = 0;
            gl::GetProgramiv(program.gl_id(),
                             gl::LINK_STATUS,
                             &mut link_status as *mut GLint);

            link_status == gl::TRUE as GLint
        };

        if success {
            Ok(())
        }
        else {
            unsafe {
                let mut info_length : GLint = mem::uninitialized();
                gl::GetProgramiv(program.gl_id(),
                                 gl::INFO_LOG_LENGTH,
                                 &mut info_length as *mut GLint);

                let mut bytes = Vec::<u8>::with_capacity(info_length as usize);

                gl::GetProgramInfoLog(program.gl_id(),
                                      info_length,
                                      ptr::null_mut(),
                                      bytes.as_mut_ptr() as *mut GLchar);
                bytes.set_len((info_length - 1) as usize);

                let msg = String::from_utf8(bytes)
                                 .unwrap_or(String::from("<Unknown error>"));

                Err(GLError { message: msg })
            }
        }
    }

    pub fn get_attrib_location(&self, program: &Program, name: &str)
        -> Result<ProgramAttrib, ()>
    {
        let c_str = try!(CString::new(name).or(Err(())));
        let str_ptr = c_str.as_ptr() as *const GLchar;
        unsafe {
            let index = gl::GetAttribLocation(program.gl_id(), str_ptr);
            if index >= 0 {
                Ok(ProgramAttrib { gl_index: index as GLuint })
            }
            else {
                Err(())
            }
        }
    }

    pub fn use_program(&self, program: &Program) {
        unsafe {
            gl::UseProgram(program.gl_id())
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramAttrib {
    pub gl_index: GLuint
}
<commit_msg>Add `ProgramUniform` newtype<commit_after>use std::mem;
use std::ptr;
use std::ffi::CString;
use super::gl_lib as gl;
use super::gl_lib::types::*;
use super::types::GLError;
use super::context::Context;
use super::shader::Shader;

pub struct Program {
    gl_id: GLuint
}

impl Program {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Program {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteProgram(self.gl_id);
        }
    }
}

impl Context {
    pub fn create_program(&self) -> Result<Program, ()> {
        unsafe {
            let id = gl::CreateProgram();
            if id > 0 {
                Ok(Program { gl_id: id })
            }
            else {
                Err(())
            }
        }
    }

    pub fn attach_shader(&self, program: &mut Program, shader: &Shader) {
        unsafe {
            gl::AttachShader(program.gl_id(), shader.gl_id());
        }
    }

    pub fn link_program(&self, program: &mut Program) -> Result<(), GLError> {
        let success = unsafe {
            gl::LinkProgram(program.gl_id());
            let mut link_status : GLint = 0;
            gl::GetProgramiv(program.gl_id(),
                             gl::LINK_STATUS,
                             &mut link_status as *mut GLint);

            link_status == gl::TRUE as GLint
        };

        if success {
            Ok(())
        }
        else {
            unsafe {
                let mut info_length : GLint = mem::uninitialized();
                gl::GetProgramiv(program.gl_id(),
                                 gl::INFO_LOG_LENGTH,
                                 &mut info_length as *mut GLint);

                let mut bytes = Vec::<u8>::with_capacity(info_length as usize);

                gl::GetProgramInfoLog(program.gl_id(),
                                      info_length,
                                      ptr::null_mut(),
                                      bytes.as_mut_ptr() as *mut GLchar);
                bytes.set_len((info_length - 1) as usize);

                let msg = String::from_utf8(bytes)
                                 .unwrap_or(String::from("<Unknown error>"));

                Err(GLError { message: msg })
            }
        }
    }

    pub fn get_attrib_location(&self, program: &Program, name: &str)
        -> Result<ProgramAttrib, ()>
    {
        let c_str = try!(CString::new(name).or(Err(())));
        let str_ptr = c_str.as_ptr() as *const GLchar;
        unsafe {
            let index = gl::GetAttribLocation(program.gl_id(), str_ptr);
            if index >= 0 {
                Ok(ProgramAttrib { gl_index: index as GLuint })
            }
            else {
                Err(())
            }
        }
    }

    pub fn use_program(&self, program: &Program) {
        unsafe {
            gl::UseProgram(program.gl_id())
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramAttrib {
    pub gl_index: GLuint
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramUniform {
    pub gl_index: GLuint
}
<|endoftext|>


<commit_before>use {Value, Response};
use parser::parse_response;
use error::RequestError;
use utils::escape_xml;

use hyper::client::{Client, Body};
use hyper::header::UserAgent;

use std::io::{self, Write};

/// A request to call a procedure.
pub struct Request<'a> {
    name: &'a str,
    args: Vec<(&'a str, Value)>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name: name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, name: &'a str, value: T) -> Self {
        self.args.push((name, value.into()));

        Request {
            name: self.name,
            args: self.args,
        }
    }

    /// Calls the method using the given `Client`.
    ///
    /// This will send the request to the `/` URL.
    ///
    /// Returns a `RequestResult` indicating whether the request was sent and processed successfully
    /// (according to the rules of XML-RPC).
    pub fn call(self, client: Client) -> RequestResult {
        // First, build the body XML
        let mut body = Vec::new();
        try!(self.write_as_xml(&mut body));

        // Send XML-RPC request
        let mut response = try!(client.post("/")
            .header(UserAgent("Rust xmlrpc".to_string()))
            .body(Body::BufBody(&body, body.len()))
            .send());

        // FIXME Check that the response headers are correct

        // Read the response and parse it
        // FIXME `BufRead`?
        Ok(try!(parse_response(&mut response)))
    }

    /// Formats this `Request` as XML.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        try!(write!(fmt, r#"<?xml version="1.1" encoding="utf-8"?>"#));
        try!(write!(fmt, r#"<methodCall>"#));
        try!(write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name)));
        try!(write!(fmt, r#"    <params>"#));
        for &(_, ref value) in &self.args {
            try!(write!(fmt, r#"        <param>"#));
            try!(value.format(fmt));
            try!(write!(fmt, r#"        </param>"#));
        }
        try!(write!(fmt, r#"    </params>"#));
        try!(write!(fmt, r#"</methodCall>"#));
        Ok(())
    }
}

/// The result of executing a request.
///
/// When the request was executed without major errors (like an HTTP error or a malformed response),
/// this is `Ok`. The `Response` can still denote a `Fault` if the server returned a `<fault>`
/// response.
pub type RequestResult = Result<Response, RequestError>;

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

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<commit_msg>Add Content-Type header to requests<commit_after>use {Value, Response};
use parser::parse_response;
use error::RequestError;
use utils::escape_xml;

use hyper::client::{Client, Body};
use hyper::header::{ContentType, UserAgent};

use std::io::{self, Write};

/// A request to call a procedure.
pub struct Request<'a> {
    name: &'a str,
    args: Vec<(&'a str, Value)>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name: name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, name: &'a str, value: T) -> Self {
        self.args.push((name, value.into()));

        Request {
            name: self.name,
            args: self.args,
        }
    }

    /// Calls the method using the given `Client`.
    ///
    /// This will send the request to the `/` URL.
    ///
    /// Returns a `RequestResult` indicating whether the request was sent and processed successfully
    /// (according to the rules of XML-RPC).
    pub fn call(self, client: Client) -> RequestResult {
        use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

        // First, build the body XML
        let mut body = Vec::new();
        try!(self.write_as_xml(&mut body));

        // Send XML-RPC request
        let mut response = try!(client.post("/")
            .header(UserAgent("Rust xmlrpc".to_string()))
            .header(ContentType(Mime(TopLevel::Text, SubLevel::Xml, vec![(Attr::Charset, Value::Utf8)])))
            .body(Body::BufBody(&body, body.len()))
            .send());

        // FIXME Check that the response headers are correct

        // Read the response and parse it
        // FIXME `BufRead`?
        Ok(try!(parse_response(&mut response)))
    }

    /// Formats this `Request` as XML.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        try!(write!(fmt, r#"<?xml version="1.1" encoding="utf-8"?>"#));
        try!(write!(fmt, r#"<methodCall>"#));
        try!(write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name)));
        try!(write!(fmt, r#"    <params>"#));
        for &(_, ref value) in &self.args {
            try!(write!(fmt, r#"        <param>"#));
            try!(value.format(fmt));
            try!(write!(fmt, r#"        </param>"#));
        }
        try!(write!(fmt, r#"    </params>"#));
        try!(write!(fmt, r#"</methodCall>"#));
        Ok(())
    }
}

/// The result of executing a request.
///
/// When the request was executed without major errors (like an HTTP error or a malformed response),
/// this is `Ok`. The `Response` can still denote a `Fault` if the server returned a `<fault>`
/// response.
pub type RequestResult = Result<Response, RequestError>;

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

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<|endoftext|>


<commit_before>use errors::{Result, ErrorKind};
use token::Token;
use token_type::TokenType;
use literal::{Literal, Number};

pub struct Scanner {
    characters: Vec<char>,
    start: usize,
    current: usize,
    line: usize,
}

impl Scanner {
    pub fn new(source: &str) -> Scanner {
        let source: String = source.into();
        let chars = source.chars().collect::<Vec<_>>();
        Scanner {
            characters: chars,
            start: 0,
            current: 0,
            line: 1,
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.characters.len()
    }

    pub fn scan(mut self) -> Result<Vec<Token>> {
        let mut tokens = vec![];

        while !self.is_at_end() {
            self.start = self.current;
            let token = self.scan_token()?;
            if let Some(token) = token {
                tokens.push(token);
            }
        }

        tokens.push(Token::new(TokenType::Eof, "", None, self.line));
        Ok(tokens)
    }

    fn scan_token(&mut self) -> Result<Option<Token>> {
        let ch = self.next();
        Ok(match ch {
            // Single-char tokens
            '(' => Some(self.make_token(TokenType::LeftParen, None)),
            ')' => Some(self.make_token(TokenType::RightParen, None)),
            '{' => Some(self.make_token(TokenType::LeftBrace, None)),
            '}' => Some(self.make_token(TokenType::RightBrace, None)),
            ',' => Some(self.make_token(TokenType::Comma, None)),
            '.' => Some(self.make_token(TokenType::Dot, None)),
            '-' => Some(self.make_token(TokenType::Minus, None)),
            '+' => Some(self.make_token(TokenType::Plus, None)),
            ';' => Some(self.make_token(TokenType::Semicolon, None)),
            '*' => Some(self.make_token(TokenType::Star, None)),

            // Single-or-double-char tokens
            '!' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::BangEqual, None))
                } else {
                    Some(self.make_token(TokenType::Bang, None))
                }
            },
            '=' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::EqualEqual, None))
                } else {
                    Some(self.make_token(TokenType::Equal, None))
                }
            },
            '<' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::LesserEqual, None))
                } else {
                    Some(self.make_token(TokenType::Lesser, None))
                }
            },
            '>' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::GreaterEqual, None))
                } else {
                    Some(self.make_token(TokenType::Greater, None))
                }
            },

            // Could be single-char token, or a comment
            '/' => {
                if self.match_char('/') {
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.next();
                    }
                    None
                } else {
                    Some(self.make_token(TokenType::Slash, None))
                }
            },

            // Ignore Whitespace
            ' ' | '\r' | 't' => {
                None
            },

            '\n' => {
                self.line += 1;
                self.scan_token()?
            },

            '"' => Some(self.scan_string()?),

            digit if self.is_digit(digit) => {
                Some(self.scan_number()?)
            },

            alpha if self.is_alpha(alpha) => {
                Some(self.scan_ident()?)
            },

            _ => return Err(ErrorKind::LoxError(self.line, "no matched token".into()).into())
        })
    }

    fn is_digit(&self, ch: char) -> bool {
        ch >= '0' && ch <= '9'
    }

    fn is_alpha(&self, ch: char) -> bool {
        (ch >= 'a' && ch <= 'z') ||
        (ch >= 'A' && ch <= 'Z') ||
        ch == '_'
    }

    fn is_alphanumeric(&self, ch: char) -> bool {
        self.is_alpha(ch) || self.is_digit(ch)
    }

    fn scan_ident(&mut self) -> Result<Token> {
        while self.is_alphanumeric(self.peek()) {
            self.next();
        }

        let text = self.characters[self.start..self.current].iter().cloned().collect::<String>();
        if let Some(ttype) = TokenType::keyword(&text) {
            Ok(self.make_token(ttype, None))
        } else {
            Ok(self.make_token(TokenType::Identifier, None))
        }
    }

    fn scan_number(&mut self) -> Result<Token> {
        let mut is_float = false;
        while self.is_digit(self.peek()) {
            self.next();
        }

        if self.peek() == '.' && self.is_digit(self.peek_next()) {
            is_float = true;
            // Consume the '.'
            self.next();

            while self.is_digit(self.peek()) {
                self.next();
            }
        }

        let lexeme = self.characters[self.start..self.current].iter().cloned().collect::<String>();
        Ok(self.make_token(TokenType::Number, if is_float {
            let parsed: f64 = lexeme.parse()?;
            let literal = Number::Float(parsed);
            Some(Literal::Number(literal))
        } else {
            let parsed: i64 = lexeme.parse()?;
            let literal = Number::Int(parsed);
            Some(Literal::Number(literal))
        }))
    }

    fn scan_string(&mut self) -> Result<Token> {
        while self.peek() != '"' && !self.is_at_end() {
            if self.peek() == '\n' {
                self.line += 1;
            }
            self.next();
        }

        if self.is_at_end() {
            return Err(ErrorKind::LoxError(self.line, "unterminated string!".into()).into());
        }

        // the closing '"'
        self.next();

        let start = self.start + 1;
        let end = self.current - 1;
        let val = self.characters[start..end].iter().cloned().collect::<String>();
        let lit = Literal::String(val);
        Ok(self.make_token(TokenType::String, Some(lit)))
    }

    fn peek(&self) -> char {
        if self.is_at_end() {
            '\0'
        } else {
            self.characters[self.current]
        }
    }

    fn peek_next(&self) -> char {
        if self.current + 1 >= self.characters.len() {
            '\0'
        } else {
            self.characters[self.current + 1]
        }
    }

    fn next(&mut self) -> char {
        self.current += 1;
        self.characters[self.current - 1]
    }

    fn match_char(&mut self, expected: char) -> bool {
        if self.is_at_end() {
            return false;
        }
        if self.characters[self.current] != expected {
            return false;
        }

        self.current += 1;
        return true;
    }

    fn make_token(&mut self, ttype: TokenType, literal: Option<Literal>) -> Token {
        let lexeme = self.characters[self.start..self.current].iter().cloned().collect::<String>();
        Token::new(ttype, &lexeme, literal, self.line)
    }
}

<commit_msg>Fix typo<commit_after>use errors::{Result, ErrorKind};
use token::Token;
use token_type::TokenType;
use literal::{Literal, Number};

pub struct Scanner {
    characters: Vec<char>,
    start: usize,
    current: usize,
    line: usize,
}

impl Scanner {
    pub fn new(source: &str) -> Scanner {
        let source: String = source.into();
        let chars = source.chars().collect::<Vec<_>>();
        Scanner {
            characters: chars,
            start: 0,
            current: 0,
            line: 1,
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.characters.len()
    }

    pub fn scan(mut self) -> Result<Vec<Token>> {
        let mut tokens = vec![];

        while !self.is_at_end() {
            self.start = self.current;
            let token = self.scan_token()?;
            if let Some(token) = token {
                tokens.push(token);
            }
        }

        tokens.push(Token::new(TokenType::Eof, "", None, self.line));
        Ok(tokens)
    }

    fn scan_token(&mut self) -> Result<Option<Token>> {
        let ch = self.next();
        Ok(match ch {
            // Single-char tokens
            '(' => Some(self.make_token(TokenType::LeftParen, None)),
            ')' => Some(self.make_token(TokenType::RightParen, None)),
            '{' => Some(self.make_token(TokenType::LeftBrace, None)),
            '}' => Some(self.make_token(TokenType::RightBrace, None)),
            ',' => Some(self.make_token(TokenType::Comma, None)),
            '.' => Some(self.make_token(TokenType::Dot, None)),
            '-' => Some(self.make_token(TokenType::Minus, None)),
            '+' => Some(self.make_token(TokenType::Plus, None)),
            ';' => Some(self.make_token(TokenType::Semicolon, None)),
            '*' => Some(self.make_token(TokenType::Star, None)),

            // Single-or-double-char tokens
            '!' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::BangEqual, None))
                } else {
                    Some(self.make_token(TokenType::Bang, None))
                }
            },
            '=' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::EqualEqual, None))
                } else {
                    Some(self.make_token(TokenType::Equal, None))
                }
            },
            '<' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::LesserEqual, None))
                } else {
                    Some(self.make_token(TokenType::Lesser, None))
                }
            },
            '>' => {
                if self.match_char('=') {
                    Some(self.make_token(TokenType::GreaterEqual, None))
                } else {
                    Some(self.make_token(TokenType::Greater, None))
                }
            },

            // Could be single-char token, or a comment
            '/' => {
                if self.match_char('/') {
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.next();
                    }
                    None
                } else {
                    Some(self.make_token(TokenType::Slash, None))
                }
            },

            // Ignore Whitespace
            ' ' | '\r' | '\t' => {
                None
            },

            '\n' => {
                self.line += 1;
                self.scan_token()?
            },

            '"' => Some(self.scan_string()?),

            digit if self.is_digit(digit) => {
                Some(self.scan_number()?)
            },

            alpha if self.is_alpha(alpha) => {
                Some(self.scan_ident()?)
            },

            _ => return Err(ErrorKind::LoxError(self.line, "no matched token".into()).into())
        })
    }

    fn is_digit(&self, ch: char) -> bool {
        ch >= '0' && ch <= '9'
    }

    fn is_alpha(&self, ch: char) -> bool {
        (ch >= 'a' && ch <= 'z') ||
        (ch >= 'A' && ch <= 'Z') ||
        ch == '_'
    }

    fn is_alphanumeric(&self, ch: char) -> bool {
        self.is_alpha(ch) || self.is_digit(ch)
    }

    fn scan_ident(&mut self) -> Result<Token> {
        while self.is_alphanumeric(self.peek()) {
            self.next();
        }

        let text = self.characters[self.start..self.current].iter().cloned().collect::<String>();
        if let Some(ttype) = TokenType::keyword(&text) {
            Ok(self.make_token(ttype, None))
        } else {
            Ok(self.make_token(TokenType::Identifier, None))
        }
    }

    fn scan_number(&mut self) -> Result<Token> {
        let mut is_float = false;
        while self.is_digit(self.peek()) {
            self.next();
        }

        if self.peek() == '.' && self.is_digit(self.peek_next()) {
            is_float = true;
            // Consume the '.'
            self.next();

            while self.is_digit(self.peek()) {
                self.next();
            }
        }

        let lexeme = self.characters[self.start..self.current].iter().cloned().collect::<String>();
        Ok(self.make_token(TokenType::Number, if is_float {
            let parsed: f64 = lexeme.parse()?;
            let literal = Number::Float(parsed);
            Some(Literal::Number(literal))
        } else {
            let parsed: i64 = lexeme.parse()?;
            let literal = Number::Int(parsed);
            Some(Literal::Number(literal))
        }))
    }

    fn scan_string(&mut self) -> Result<Token> {
        while self.peek() != '"' && !self.is_at_end() {
            if self.peek() == '\n' {
                self.line += 1;
            }
            self.next();
        }

        if self.is_at_end() {
            return Err(ErrorKind::LoxError(self.line, "unterminated string!".into()).into());
        }

        // the closing '"'
        self.next();

        let start = self.start + 1;
        let end = self.current - 1;
        let val = self.characters[start..end].iter().cloned().collect::<String>();
        let lit = Literal::String(val);
        Ok(self.make_token(TokenType::String, Some(lit)))
    }

    fn peek(&self) -> char {
        if self.is_at_end() {
            '\0'
        } else {
            self.characters[self.current]
        }
    }

    fn peek_next(&self) -> char {
        if self.current + 1 >= self.characters.len() {
            '\0'
        } else {
            self.characters[self.current + 1]
        }
    }

    fn next(&mut self) -> char {
        self.current += 1;
        self.characters[self.current - 1]
    }

    fn match_char(&mut self, expected: char) -> bool {
        if self.is_at_end() {
            return false;
        }
        if self.characters[self.current] != expected {
            return false;
        }

        self.current += 1;
        return true;
    }

    fn make_token(&mut self, ttype: TokenType, literal: Option<Literal>) -> Token {
        let lexeme = self.characters[self.start..self.current].iter().cloned().collect::<String>();
        Token::new(ttype, &lexeme, literal, self.line)
    }
}

<|endoftext|>