<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

//! Standardized isolation of logic as a `process` wrapper around a `thread`.
//!
//! Basic wrapper around threads to provide some standard API. All long-living Hat threads run
//! as a `process`. The main difference between a normal Rust `thread` and a Hat `process` is
//! currently that the `process` has a bounded input-channel and a standard implementation of a
//! synchronous `send_reply()`.

/// A long-living `thread` is promoted to a standard `process`.
///
/// To create a new `process`, simply define a `Msg` type, a `Reply` type and a state struct
/// that implements the `MsgHandler` trait. You can then create a new process with:
///
/// ```rust,ignore
/// enum Msg {Ping, Foo}
/// enum Reply {Pong, Bar}
///
/// struct MyHandler {
///   fn handle(&mut self, msg: Msg, reply: |Reply|) {
///     match Msg {
///       Ping => return reply(Pong),
///       Foo => return reply(Bar),
///     }
///   }
/// }
///
/// fn main() {
///   let p = Process::new(MyHandler::new());
///   let pong = p.send_reply(Ping);
/// }
/// ```
///
/// The handler must always call `reply()` to release any call to `send_reply()`. It is allowed to
/// call `reply()` "early" - before all work has been done - but calling `reply()` is usually the
/// last thing a handler does. The idiom `return reply(...)` is a simple way of guaranteeing this.
///
/// A handler is allowed to call `reply()` **exactly** once. Not calling it or calling it multiple
/// times will likely cause runtime panicure when using `send_reply()`.

use std::boxed::FnBox;
use std::thread;
use std::sync::mpsc;

pub struct Process<Msg, Reply> {
    sender: mpsc::SyncSender<(Msg, Option<mpsc::Sender<Reply>>)>,
}

/// When cloning a `process` we clone the input-channel, allowing multiple threads to share the same
/// `process`.
impl<Msg: Send, Reply: Send> Clone for Process<Msg, Reply> {
    fn clone(&self) -> Process<Msg, Reply> {
        Process { sender: self.sender.clone() }
    }
}

pub trait MsgHandler<Msg, Reply> {
    fn handle(&mut self, msg: Msg, callback: Box<Fn(Reply)>);
}

impl<Msg: 'static + Send, Reply: 'static + Send> Process<Msg, Reply> {
    /// Create and start a new process using `handler`.
    pub fn new<H>(handler_proc: Box<FnBox() -> H + Send>) -> Process<Msg, Reply>
        where H: 'static + MsgHandler<Msg, Reply>
    {
        let (sender, receiver) = mpsc::sync_channel(10);
        let p = Process { sender: sender };

        p.start(receiver, handler_proc);

        p
    }

    fn start<H>(&self,
                receiver: mpsc::Receiver<(Msg, Option<mpsc::Sender<Reply>>)>,
                handler_proc: Box<FnBox() -> H + Send>)
        where H: 'static + MsgHandler<Msg, Reply>
    {
        thread::spawn(move || {
            // fork handler
            let mut my_handler = handler_proc();
            loop {
                match receiver.recv() {
                    Ok((msg, None)) => {
                        my_handler.handle(msg, Box::new(|_r: Reply| {}));
                    }
                    Ok((msg, Some(rep))) => {
                        my_handler.handle(msg,
                                          Box::new(move |r| {
                                              rep.send(r).unwrap();
                                          }));
                    }
                    Err(_recv_error) => break,
                };
            }
        });
    }

    /// Synchronous send.
    ///
    /// Will always wait for a reply from the receiving `process`.
    pub fn send_reply(&self, msg: Msg) -> Reply {
        let (sender, receiver) = mpsc::channel();
        self.sender.send((msg, Some(sender))).ok();
        return receiver.recv().expect("Failed to get reply for msg");
    }
}
<commit_msg>Add a mechanism to force-shutdown a process early.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

//! Standardized isolation of logic as a `process` wrapper around a `thread`.
//!
//! Basic wrapper around threads to provide some standard API. All long-living Hat threads run
//! as a `process`. The main difference between a normal Rust `thread` and a Hat `process` is
//! currently that the `process` has a bounded input-channel and a standard implementation of a
//! synchronous `send_reply()`.

/// A long-living `thread` is promoted to a standard `process`.
///
/// To create a new `process`, simply define a `Msg` type, a `Reply` type and a state struct
/// that implements the `MsgHandler` trait. You can then create a new process with:
///
/// ```rust,ignore
/// enum Msg {Ping, Foo}
/// enum Reply {Pong, Bar}
///
/// struct MyHandler {
///   fn handle(&mut self, msg: Msg, reply: |Reply|) {
///     match Msg {
///       Ping => return reply(Pong),
///       Foo => return reply(Bar),
///     }
///   }
/// }
///
/// fn main() {
///   let p = Process::new(MyHandler::new());
///   let pong = p.send_reply(Ping);
/// }
/// ```
///
/// The handler must always call `reply()` to release any call to `send_reply()`. It is allowed to
/// call `reply()` "early" - before all work has been done - but calling `reply()` is usually the
/// last thing a handler does. The idiom `return reply(...)` is a simple way of guaranteeing this.
///
/// A handler is allowed to call `reply()` **exactly** once. Not calling it or calling it multiple
/// times will likely cause runtime panicure when using `send_reply()`.

use std::boxed::FnBox;
use std::thread;
use std::sync::mpsc;

pub struct Process<Msg, Reply> {
    sender: mpsc::SyncSender<(Msg, Option<mpsc::Sender<Reply>>)>,
    shutdown_after: Option<i64>,
}

/// When cloning a `process` we clone the input-channel, allowing multiple threads to share the same
/// `process`.
impl<Msg: Send, Reply: Send> Clone for Process<Msg, Reply> {
    fn clone(&self) -> Process<Msg, Reply> {
        Process {
            sender: self.sender.clone(),
            shutdown_after: None,
        }
    }
}

pub trait MsgHandler<Msg, Reply> {
    fn handle(&mut self, msg: Msg, callback: Box<Fn(Reply)>);
}

impl<Msg: 'static + Send, Reply: 'static + Send> Process<Msg, Reply> {
    /// Create and start a new process using `handler`.
    pub fn new<H>(handler_proc: Box<FnBox() -> H + Send>) -> Process<Msg, Reply>
        where H: 'static + MsgHandler<Msg, Reply>
    {
        return Process::new_with_shutdown(handler_proc, None);
    }

    pub fn new_with_shutdown<H>(handler_proc: Box<FnBox() -> H + Send>,
                                shutdown_after: Option<i64>)
                                -> Process<Msg, Reply>
        where H: 'static + MsgHandler<Msg, Reply>
    {
        let (sender, receiver) = mpsc::sync_channel(10);
        let p = Process {
            sender: sender,
            shutdown_after: shutdown_after,
        };

        p.start(receiver, handler_proc);

        p
    }

    fn start<H>(&self,
                receiver: mpsc::Receiver<(Msg, Option<mpsc::Sender<Reply>>)>,
                handler_proc: Box<FnBox() -> H + Send>)
        where H: 'static + MsgHandler<Msg, Reply>
    {
        let shutdown_after = self.shutdown_after.clone();
        thread::spawn(move || {
            // fork handler
            let mut my_handler = handler_proc();
            let mut handle_msg = || {
                match receiver.recv() {
                    Ok((msg, None)) => {
                        my_handler.handle(msg, Box::new(|_r: Reply| {}));
                        Ok(())
                    }
                    Ok((msg, Some(rep))) => {
                        my_handler.handle(msg,
                                          Box::new(move |r| {
                                              rep.send(r).unwrap();
                                          }));
                        Ok(())
                    }
                    Err(err) => Err(err),
                }
            };
            match shutdown_after {
                Some(msg_count) => {
                    for _ in 0..msg_count {
                        if let Err(..) = handle_msg() {
                            break;
                        }
                    }
                }
                None => {
                    while let Ok(..) = handle_msg() {
                    }
                }
            }
        });
    }

    /// Synchronous send.
    ///
    /// Will always wait for a reply from the receiving `process`.
    pub fn send_reply(&self, msg: Msg) -> Reply {
        let (sender, receiver) = mpsc::channel();
        self.sender.send((msg, Some(sender))).ok();
        return receiver.recv().expect("Failed to get reply for msg");
    }
}
<|endoftext|>


<commit_before>use std::old_io::File;
use std::old_io::SeekStyle::SeekSet;
use std::old_io::IoErrorKind::EndOfFile;
use elem::{PerElem, Molecule};
use error::{CTError, CTResult};
use error::CTErrorKind::{SyntaxError, DatabaseError};

macro_rules! read_err (
    () => (Err(CTError {
        kind: DatabaseError,
        desc: "Error reading the database".to_string(),
        pos: None
    }));
);

#[derive(Show, PartialEq)]
pub struct ElemData {
    pub short_name: String,
    pub long_name: String,
    pub mass: f64,
    pub atomic_num: u16,
}

pub struct ElemDatabase {
    db: File,
}

impl ElemDatabase {
    pub fn open(path: &Path) -> CTResult<ElemDatabase> {
        match File::open(path) {
            Ok(db_file) => Ok(ElemDatabase { db: db_file }),
            Err(_) => Err(CTError {
                kind: DatabaseError,
                desc: format!("Could not open database file. Expected at: {:?}",
                              path.as_str().unwrap_or("same directory as the program")),
                pos: None,
            }),
        }
    }

    pub fn get_single_data(&mut self, elem: &PerElem) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.seek(0, SeekSet).ok().expect("Internal error reading database");

        loop {
            // TODO: make so this function returns the 'not found' error
            let line = try!(self.read_line(elem));
            if line.starts_with(elem.name.as_slice()) {
                return decode_line(&line);
            }
        }
    }

    pub fn get_data(&mut self, elems: &Molecule) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
            match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }

    fn read_line(&mut self, elem: &PerElem) -> CTResult<String> {
        // we know that no line in the database is more than 30 characters long
        let mut buf = Vec::with_capacity(30);
        loop {
            match self.db.read_byte() {
                Ok(b) if b == b'\n' => break,
                Ok(b) => buf.push(b),
                // we let EOF error return without error, so we can check for it further up
                Err(ref e) if e.kind == EndOfFile => return Err(CTError {
                    kind: SyntaxError,
                    desc: format!("Could not find element: {:?}", elem.name),
                    pos: Some((elem.pos, elem.len)),
                }),
                Err(_) => return read_err!()
            }
        }
        String::from_utf8(buf).or_else(|_| read_err!())
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(CTError {
            kind: DatabaseError,
            desc: "Missing field in database".to_string(),
            pos: None
        })
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(CTError {
                kind: DatabaseError,
                desc: "Field in database corrupted".to_string(),
                pos: None,
            })
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::old_io::File;
    use std::old_io::fs;
    use elem::PerElem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(&Path::new(name)).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4\n");
        let raw_result = db.get_data(&vec!(
            PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 1 },
            PerElem { name: "A".to_string(), coef: 1, pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0\n");
        let raw_result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12\n");
        let result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12\n");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<commit_msg>Fix small comment error<commit_after>use std::old_io::File;
use std::old_io::SeekStyle::SeekSet;
use std::old_io::IoErrorKind::EndOfFile;
use elem::{PerElem, Molecule};
use error::{CTError, CTResult};
use error::CTErrorKind::{SyntaxError, DatabaseError};

macro_rules! read_err (
    () => (Err(CTError {
        kind: DatabaseError,
        desc: "Error reading the database".to_string(),
        pos: None
    }));
);

#[derive(Show, PartialEq)]
pub struct ElemData {
    pub short_name: String,
    pub long_name: String,
    pub mass: f64,
    pub atomic_num: u16,
}

pub struct ElemDatabase {
    db: File,
}

impl ElemDatabase {
    pub fn open(path: &Path) -> CTResult<ElemDatabase> {
        match File::open(path) {
            Ok(db_file) => Ok(ElemDatabase { db: db_file }),
            Err(_) => Err(CTError {
                kind: DatabaseError,
                desc: format!("Could not open database file. Expected at: {:?}",
                              path.as_str().unwrap_or("same directory as the program")),
                pos: None,
            }),
        }
    }

    pub fn get_single_data(&mut self, elem: &PerElem) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.seek(0, SeekSet).ok().expect("Internal error reading database");

        loop {
            // TODO: make it so this function returns the 'not found' error
            let line = try!(self.read_line(elem));
            if line.starts_with(elem.name.as_slice()) {
                return decode_line(&line);
            }
        }
    }

    pub fn get_data(&mut self, elems: &Molecule) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
            match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }

    fn read_line(&mut self, elem: &PerElem) -> CTResult<String> {
        // we know that no line in the database is more than 30 characters long
        let mut buf = Vec::with_capacity(30);
        loop {
            match self.db.read_byte() {
                Ok(b) if b == b'\n' => break,
                Ok(b) => buf.push(b),
                Err(ref e) if e.kind == EndOfFile => return Err(CTError {
                    kind: SyntaxError,
                    desc: format!("Could not find element: {:?}", elem.name),
                    pos: Some((elem.pos, elem.len)),
                }),
                Err(_) => return read_err!()
            }
        }
        String::from_utf8(buf).or_else(|_| read_err!())
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(CTError {
            kind: DatabaseError,
            desc: "Missing field in database".to_string(),
            pos: None
        })
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(CTError {
                kind: DatabaseError,
                desc: "Field in database corrupted".to_string(),
                pos: None,
            })
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::old_io::File;
    use std::old_io::fs;
    use elem::PerElem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(&Path::new(name)).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4\n");
        let raw_result = db.get_data(&vec!(
            PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 1 },
            PerElem { name: "A".to_string(), coef: 1, pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0\n");
        let raw_result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12\n");
        let result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12\n");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<|endoftext|>


<commit_before>use super::core;
use super::elaborate::{self, ElabCx, LocalElabCx};
use super::error_reporting::{ErrorContext, Report};
use super::parser;
use super::ast::{self, SourceMap};
use super::typeck;

use std::io::{self, Write};
use std::path::{PathBuf};
use readline;

use term::{self, Terminal, StdoutTerminal, Result as TResult};

const HELP_MESSAGE: &'static str = r#"
Commands:
    :help        Show this message
    :type <term> Infer the type of <term>
    :quit        Exit
"#;

pub struct Repl {
    elab_cx: ElabCx,
    root_file: Option<PathBuf>,
    terminal: Box<StdoutTerminal>,
}

// impl From<parser::Error> for Error {
//     fn from(err: parser::Error) -> Error {
//         Error::Parser(err)
//     }
// }
//

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<elaborate::Error> for Error {
    fn from(err: elaborate::Error) -> Error {
        Error::Elaborator(err)
    }
}

impl From<typeck::Error> for Error {
    fn from(err: typeck::Error) -> Error {
        Error::TypeCk(err)
    }
}

impl From<term::Error> for Error {
    fn from(err: term::Error) -> Error {
        Error::Term(err)
    }
}

impl From<parser::Error> for Error {
    fn from(err: parser::Error) -> Error {
        Error::Parser(err)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Elaborator(elaborate::Error),
    UnknownCommand(String),
    TypeCk(typeck::Error),
    Parser(parser::Error),
    Term(term::Error),
}

#[derive(Debug)]
enum Command {
    Quit,
    Reload,
    Unknown(String),
    TypeOf(String),
    Help,
}

pub enum Cont {
    Quit,
    Done,
}

fn split_command(command_text: &str) -> (&str, &str) {

    for (i, c) in command_text.char_indices() {
        if c.is_whitespace() {
            return command_text.split_at(i);
        }
    }

    (command_text, "")
}

impl Repl {
    pub fn from_path(file: &Option<PathBuf>) -> Result<Repl, Error> {
        match file {
            &None => {
                let ecx = ElabCx::from_module(ast::Module::empty(), SourceMap::empty());
                Ok(Repl {
                    elab_cx: ecx,
                    root_file: None,
                    terminal: term::stdout().unwrap(),
                })
            }
            &Some(ref file_path) => {
                let parser = try!(parser::from_file(file_path));
                let module = try!(parser.parse());

                let mut ecx = ElabCx::from_module(module, parser.source_map.clone());

                // Ensure that if a type error occurs here we report it, ideally
                // the REPL should launch anyways.
                match ecx.elaborate_module(file_path) {
                    Err(e) => { try!(e.report(&mut ecx)) },
                    Ok(_) => {}
                }

                Ok(Repl {
                    elab_cx: ecx,
                    root_file: file.clone(),
                    terminal: term::stdout().unwrap(),
                })
            }
        }
    }

    /// Starts the read-eval-print-loop for querying the language.
    pub fn start(mut self) -> Result<(), Error> {
        readline::read_history(&PathBuf::from("~/.hubris_history"));

        loop {
            // First we grab a line ...
            let input = match readline::readline("hubris> ") {
                None => {
                    println!("");
                    break;
                }
                Some(input) => input,
            };

            // Add it to the history
            readline::add_history(input.as_ref());

            match self.repl_interation(input) {
                // please make me look better
                Err(e) => {
                    try!(e.report(&mut self));
                },
                Ok(cont) => {
                    match cont {
                        Cont::Quit => break,
                        Cont::Done => {}
                    }
                }
            }
        }

        readline::write_history(&PathBuf::from("~/.hubris_history"));

        Ok(())
    }

    pub fn repl_interation(&mut self, input: String) -> Result<Cont, Error> {
        if input.len() <= 0 {
            // do nothing
        } else if &input[0..1] == ":" {
            let cmd = self.parse_command(&input[1..]);
            match cmd {
                Command::Quit => return Ok(Cont::Quit),
                Command::Reload => {
                    let new_repl =
                        try!(Repl::from_path(&self.root_file));
                    *self = new_repl;
                }
                Command::Unknown(u) => return Err(Error::UnknownCommand(u)),
                Command::TypeOf(t) => {
                    let term = try!(self.preprocess_term(t));
                    println!("{}", try!(self.type_check_term(&term)));
                }
                Command::Help => println!("{}", HELP_MESSAGE),
            }
        } else {
            try!(self.handle_input(input.to_string()));
        }

        Ok(Cont::Done)
    }

    fn preprocess_term(&mut self, source: String) -> Result<core::Term, Error> {
        let parser = parser::from_string(source).unwrap();
        let term = try!(parser.parse_term());

        let mut lcx = LocalElabCx::from_elab_cx(&mut self.elab_cx);
        let term = try!(lcx.elaborate_term(term));

        Ok(term)
    }

    fn type_check_term(&mut self, term: &core::Term) -> Result<core::Term, Error> {
        let term = try!(self.elab_cx.ty_cx.type_infer_term(&term));
        let ty = try!(self.elab_cx.ty_cx.eval(&term));
        Ok(ty)
    }

    fn handle_input(&mut self, source: String) -> Result<(), Error> {
        let term = try!(self.preprocess_term(source));
        let ty = try!(self.type_check_term(&term));
        println!("{} : {}", term, ty);
        println!("{}", try!(self.elab_cx.ty_cx.eval(&term)));
        Ok(())
    }

    fn parse_command(&self, command_text: &str) -> Command {
        let (command, arg) = split_command(command_text);

        if command == "" {
            Command::Unknown(command_text.to_string())
        } else if "quit".starts_with(command) {
            Command::Quit
        } else if "reload".starts_with(command) {
            Command::Reload
        } else if "type".starts_with(command) {
            Command::TypeOf(arg.to_string())
        } else if "help".starts_with(command) {
            Command::Help
        } else {
            Command::Unknown(command_text.to_string())
        }
    }
}

impl ErrorContext<io::Stdout> for Repl {
    fn get_source_map(&self) -> &SourceMap {
        &self.elab_cx.ty_cx.source_map
    }

    fn get_terminal(&mut self) -> &mut Box<Terminal<Output=io::Stdout> + Send> {
        &mut self.elab_cx.ty_cx.terminal
    }
}

impl<O: Write, E: ErrorContext<O>> Report<O, E> for Error {
    fn report(self, cx: &mut E) -> TResult<()> {
        match self {
            Error::TypeCk(ty_ck_err) => {
                ty_ck_err.report(cx)
            }
            Error::Elaborator(elab_err) => {
                elab_err.report(cx)
            }
            Error::Parser(parser_err) => {
                parser_err.report(cx)
            }
            e => panic!("need to support better error printing for this {:?}", e),
        }
    }
}
<commit_msg>Add to repl help message<commit_after>use super::core;
use super::elaborate::{self, ElabCx, LocalElabCx};
use super::error_reporting::{ErrorContext, Report};
use super::parser;
use super::ast::{self, SourceMap};
use super::typeck;

use std::io::{self, Write};
use std::path::{PathBuf};
use readline;

use term::{self, Terminal, StdoutTerminal, Result as TResult};

const HELP_MESSAGE: &'static str = r#"
Commands:
    :help        Show this message
    :type <term> Infer the type of <term>
    :reload      Reload the session
    :quit        Exit
"#;

pub struct Repl {
    elab_cx: ElabCx,
    root_file: Option<PathBuf>,
    terminal: Box<StdoutTerminal>,
}

// impl From<parser::Error> for Error {
//     fn from(err: parser::Error) -> Error {
//         Error::Parser(err)
//     }
// }
//

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<elaborate::Error> for Error {
    fn from(err: elaborate::Error) -> Error {
        Error::Elaborator(err)
    }
}

impl From<typeck::Error> for Error {
    fn from(err: typeck::Error) -> Error {
        Error::TypeCk(err)
    }
}

impl From<term::Error> for Error {
    fn from(err: term::Error) -> Error {
        Error::Term(err)
    }
}

impl From<parser::Error> for Error {
    fn from(err: parser::Error) -> Error {
        Error::Parser(err)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Elaborator(elaborate::Error),
    UnknownCommand(String),
    TypeCk(typeck::Error),
    Parser(parser::Error),
    Term(term::Error),
}

#[derive(Debug)]
enum Command {
    Quit,
    Reload,
    Unknown(String),
    TypeOf(String),
    Help,
}

pub enum Cont {
    Quit,
    Done,
}

fn split_command(command_text: &str) -> (&str, &str) {

    for (i, c) in command_text.char_indices() {
        if c.is_whitespace() {
            return command_text.split_at(i);
        }
    }

    (command_text, "")
}

impl Repl {
    pub fn from_path(file: &Option<PathBuf>) -> Result<Repl, Error> {
        match file {
            &None => {
                let ecx = ElabCx::from_module(ast::Module::empty(), SourceMap::empty());
                Ok(Repl {
                    elab_cx: ecx,
                    root_file: None,
                    terminal: term::stdout().unwrap(),
                })
            }
            &Some(ref file_path) => {
                let parser = try!(parser::from_file(file_path));
                let module = try!(parser.parse());

                let mut ecx = ElabCx::from_module(module, parser.source_map.clone());

                // Ensure that if a type error occurs here we report it, ideally
                // the REPL should launch anyways.
                match ecx.elaborate_module(file_path) {
                    Err(e) => { try!(e.report(&mut ecx)) },
                    Ok(_) => {}
                }

                Ok(Repl {
                    elab_cx: ecx,
                    root_file: file.clone(),
                    terminal: term::stdout().unwrap(),
                })
            }
        }
    }

    /// Starts the read-eval-print-loop for querying the language.
    pub fn start(mut self) -> Result<(), Error> {
        readline::read_history(&PathBuf::from("~/.hubris_history"));

        loop {
            // First we grab a line ...
            let input = match readline::readline("hubris> ") {
                None => {
                    println!("");
                    break;
                }
                Some(input) => input,
            };

            // Add it to the history
            readline::add_history(input.as_ref());

            match self.repl_interation(input) {
                // please make me look better
                Err(e) => {
                    try!(e.report(&mut self));
                },
                Ok(cont) => {
                    match cont {
                        Cont::Quit => break,
                        Cont::Done => {}
                    }
                }
            }
        }

        readline::write_history(&PathBuf::from("~/.hubris_history"));

        Ok(())
    }

    pub fn repl_interation(&mut self, input: String) -> Result<Cont, Error> {
        if input.len() <= 0 {
            // do nothing
        } else if &input[0..1] == ":" {
            let cmd = self.parse_command(&input[1..]);
            match cmd {
                Command::Quit => return Ok(Cont::Quit),
                Command::Reload => {
                    let new_repl =
                        try!(Repl::from_path(&self.root_file));
                    *self = new_repl;
                }
                Command::Unknown(u) => return Err(Error::UnknownCommand(u)),
                Command::TypeOf(t) => {
                    let term = try!(self.preprocess_term(t));
                    println!("{}", try!(self.type_check_term(&term)));
                }
                Command::Help => println!("{}", HELP_MESSAGE),
            }
        } else {
            try!(self.handle_input(input.to_string()));
        }

        Ok(Cont::Done)
    }

    fn preprocess_term(&mut self, source: String) -> Result<core::Term, Error> {
        let parser = parser::from_string(source).unwrap();
        let term = try!(parser.parse_term());

        let mut lcx = LocalElabCx::from_elab_cx(&mut self.elab_cx);
        let term = try!(lcx.elaborate_term(term));

        Ok(term)
    }

    fn type_check_term(&mut self, term: &core::Term) -> Result<core::Term, Error> {
        let term = try!(self.elab_cx.ty_cx.type_infer_term(&term));
        let ty = try!(self.elab_cx.ty_cx.eval(&term));
        Ok(ty)
    }

    fn handle_input(&mut self, source: String) -> Result<(), Error> {
        let term = try!(self.preprocess_term(source));
        let ty = try!(self.type_check_term(&term));
        println!("{} : {}", term, ty);
        println!("{}", try!(self.elab_cx.ty_cx.eval(&term)));
        Ok(())
    }

    fn parse_command(&self, command_text: &str) -> Command {
        let (command, arg) = split_command(command_text);

        if command == "" {
            Command::Unknown(command_text.to_string())
        } else if "quit".starts_with(command) {
            Command::Quit
        } else if "reload".starts_with(command) {
            Command::Reload
        } else if "type".starts_with(command) {
            Command::TypeOf(arg.to_string())
        } else if "help".starts_with(command) {
            Command::Help
        } else {
            Command::Unknown(command_text.to_string())
        }
    }
}

impl ErrorContext<io::Stdout> for Repl {
    fn get_source_map(&self) -> &SourceMap {
        &self.elab_cx.ty_cx.source_map
    }

    fn get_terminal(&mut self) -> &mut Box<Terminal<Output=io::Stdout> + Send> {
        &mut self.elab_cx.ty_cx.terminal
    }
}

impl<O: Write, E: ErrorContext<O>> Report<O, E> for Error {
    fn report(self, cx: &mut E) -> TResult<()> {
        match self {
            Error::TypeCk(ty_ck_err) => {
                ty_ck_err.report(cx)
            }
            Error::Elaborator(elab_err) => {
                elab_err.report(cx)
            }
            Error::Parser(parser_err) => {
                parser_err.report(cx)
            }
            e => panic!("need to support better error printing for this {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>use std::os::windows::fs::OpenOptionsExt;
use libc::DWORD;
use ::util::tmpnam;

const ACCESS: DWORD     = libc::FILE_GENERIC_READ
                        | libc::FILE_GENERIC_WRITE;
const SHARE_MODE: DWORD = libc::FILE_SHARE_DELETE
                        | libc::FILE_SHARE_READ
                        | libc::FILE_SHARE_WRITE;
const FLAGS: DWORD      = libc::FILE_ATTRIBUTE_HIDDEN
                        | libc::FILE_ATTRIBUTE_TEMPORARY
                        | libc::FILE_FLAG_DELETE_ON_CLOSE;

pub fn create(dir: &Path) -> io::Result<File> {
    let opts = OpenOptions::new()
        .desired_access(ACCESS)
        .share_mode(SHARE)
        .creation_disposition(libc::CREATE_NEW)
        .flags_and_attributes(ATTRS);

    loop {
        return match opts.open(dir.join(tmpname())) {
            Ok(f) => Ok(f),
            Err(e) if e.kind() == io::Error::AlreadyExists => continue,
            Err(e) => Err(e),
        };
    }
}

pub fn reopen(f: &File) -> io::Result<File> {
    let h = f.as_raw_handle();
    match ReOpenFile(h, ACCESS, SHARE_MODE, FLAGS) {
        libc::INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
        h => Ok(FromRawHandle::from_raw_handle(h))
    }
}
<commit_msg>Fix import.<commit_after>use std::os::windows::fs::OpenOptionsExt;
use libc::DWORD;
use ::util::tmpname;

const ACCESS: DWORD     = libc::FILE_GENERIC_READ
                        | libc::FILE_GENERIC_WRITE;
const SHARE_MODE: DWORD = libc::FILE_SHARE_DELETE
                        | libc::FILE_SHARE_READ
                        | libc::FILE_SHARE_WRITE;
const FLAGS: DWORD      = libc::FILE_ATTRIBUTE_HIDDEN
                        | libc::FILE_ATTRIBUTE_TEMPORARY
                        | libc::FILE_FLAG_DELETE_ON_CLOSE;

pub fn create(dir: &Path) -> io::Result<File> {
    let opts = OpenOptions::new()
        .desired_access(ACCESS)
        .share_mode(SHARE)
        .creation_disposition(libc::CREATE_NEW)
        .flags_and_attributes(ATTRS);

    loop {
        return match opts.open(dir.join(tmpname())) {
            Ok(f) => Ok(f),
            Err(e) if e.kind() == io::Error::AlreadyExists => continue,
            Err(e) => Err(e),
        };
    }
}

pub fn reopen(f: &File) -> io::Result<File> {
    let h = f.as_raw_handle();
    match ReOpenFile(h, ACCESS, SHARE_MODE, FLAGS) {
        libc::INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
        h => Ok(FromRawHandle::from_raw_handle(h))
    }
}
<|endoftext|>


<commit_before>use header::*;
use constants::*;
use instructions::Instruction as Instr;
use num::FromPrimitive;
use std::fmt;

#[derive(Debug, Default)]
pub struct Runtime {
    interpreter: Interpreter,
    call_stack: Vec<StackFrame>,
}

impl Runtime {
    pub fn new(mut data: Vec<u8>) -> Runtime {
        let mut r = Runtime {
            interpreter: Interpreter::new(data),
            call_stack: Vec::new(),
        };
        r
    }
    pub fn run(&mut self, options: &::Options) {
        debug!("Running...");

        let debug = options.debug;

        loop {
            // Need to wrap this here to limit the scope of last_frame borrow
            let dispatch_result = {
                let ln = self.call_stack.len();
                let mut last_frame = &mut self.call_stack[ln-1];
                last_frame.dispatch(&mut self.interpreter, debug)
            };
            // Push the new StackFrame, if CALL was issued
            if let Some(frm) = dispatch_result {
                self.call_stack.push(frm);
            }
        }
    }
}

#[derive(Debug, Default)]
pub struct Interpreter {
    // File data
    header: RaptorHeader,
    const_table: ConstTable,

    // Rutime stuff
    op_stack: Vec<i32>,
    memory: Vec<i32>,
}

// Should this be here?

#[derive(Debug, Default, Clone)]
pub struct StackFrame {
    locals: Vec<i32>,
    // The index of the first op in the op_stack that should be kept
    return_addr: usize,
    bytecode: Vec<u8>,
    bc_counter: usize
}

impl Interpreter {
    pub fn new(mut data: Vec<u8>) -> Interpreter {
        debug!("Bytecode length: {} bytes", data.len());
        let header = read_header(&data);
        data.drain(..HEADER_SIZE);
        let const_table: ConstTable = read_const_table(data.as_slice());
        debug!("Constant table length: {} bytes", const_table.bc_counter);
        debug!("Bytecode length: {} bytes", data.len());
        data.drain(..const_table.bc_counter);
        let sf = StackFrame {
            bytecode: data,
            ..Default::default()
        };
        let mut i = Interpreter {
            header: header,
            const_table: const_table,
            op_stack: Vec::new(),
            memory: Vec::new(),
        };
        i.memory.resize(i.header.var_count as usize, 0);
        i
    }
}

impl StackFrame {

    fn get_next_4_bytes(&mut self) -> u32 {
        let val = (self.bytecode[self.bc_counter] as u32) << 24 |
        (self.bytecode[self.bc_counter + 1] as u32) << 16 |
        (self.bytecode[self.bc_counter + 2] as u32) << 8 |
        (self.bytecode[self.bc_counter + 3] as u32);
        self.bc_counter += 4;
        debug!("get_next_4_bytes: 0x{:04X}", val);
        val
    }

    fn dispatch(&mut self, inpr: &mut Interpreter, debug: bool) -> Option<StackFrame> {
        use std::ops::*;
        use std::cmp::*;

        // Main loop
        while self.bc_counter != self.bytecode.len() {
            // info!("PC: {}", bc_counter);

            // Use FromPrimitive trait to convert a value to its enum
            let instr = Instr::from_u8(self.bytecode[self.bc_counter]);
            self.bc_counter += 1;

            if instr.is_none() {
                warn!("Unimplemented instruction: {:04X}", self.bytecode[self.bc_counter]);
                continue;
            }

            let instr = instr.unwrap();   // We're sure it's Some here, so unpack it.

            if debug {
                debug!("{:?}", instr);
            }

            macro_rules! push {
                ( $x:expr ) => {
                    inpr.op_stack.push($x);
                };
            }
            macro_rules! pop {
                () => {
                    inpr.op_stack.pop();
                };
            }
            macro_rules! operation {
                ($op:ident) => ({
                    let final_length: usize = inpr.op_stack.len().saturating_sub(2);
                    let val = inpr.op_stack.drain(final_length..).fold(
                        0, |acc, x| acc.$op(x)
                    );
                    push!(val);
                })
            }
            macro_rules! reljump {
                ($op:ident) => ({
                    let top = pop!().unwrap();
                    if top.$op(&0) {
                        reljump!();
                    } else {
                        self.get_next_4_bytes();
                        if debug {debug!("Jump not taken"); }
                    }
                });
                () => ({
                    let offset = (self.get_next_4_bytes() - 1) as i32;
                    // Need this if because you can't have negative usizes
                    if offset > 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.bc_counter += offset as usize;
                        if offset == 1 {debug!("RELJUMP 1 is redundant. This is a compiler bug")}
                    } else if offset < 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.bc_counter -= (-offset) as usize;
                    } else {
                        warn!("Invalid reljump offset: 0");
                    }
                });
            }

            macro_rules! push_frame {
                ($id:expr) => ({
                    let func_const = &inpr.const_table.funcs[$id as usize];
                    let mut sf = StackFrame {
                        locals: Vec::new(),
                        ..Default::default()
                    };
                    for _ in 0..func_const.arg_count {
                        sf.locals.push(pop!().unwrap());
                    }
                    sf.return_addr = inpr.op_stack.len();
                    sf.locals.resize((func_const.arg_count + func_const.local_count) as usize, 0);
                    debug!("Pushed new frame: {}    {:?}", $id, sf);
                    debug!("Op stack: {:?}", inpr.op_stack);
                    return Some(sf);
                });
            }
            // TODO: More macros, less code

            match instr {
                Instr::NOP => {},
                Instr::HALT => {
                    println!("HALT issued, stopped execution.");
                    if debug {
                        debug!("Stack: {:?}", inpr.op_stack);
                        debug!("Memory: {:?}", inpr.memory);
                    }
                },
                Instr::ICONST => {
                    let b = self.get_next_4_bytes() as i32;
                    push!(b);
                },
                Instr::POP => { pop!(); },
                Instr::ADD =>       { operation!(add);    },
                Instr::SUB =>       { operation!(sub);    },
                Instr::MULTIPLY =>  { operation!(mul);    },
                Instr::DIVIDE =>    { operation!(div);    },
                Instr::MODULUS =>   { operation!(rem);    },
                Instr::RSHIFT =>    { operation!(shl);    },
                Instr::LSHIFT =>    { operation!(shr);    },
                Instr::AND =>       { operation!(bitand); },
                Instr::OR =>        { operation!(bitor);  },
                Instr::NOT =>       {
                    let val = pop!().unwrap();
                    push!(val.not());
                },
                Instr::COMP => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else if a < b {-1} else {0});
                },
                Instr::COMP_LT => {
                    let a = pop!(); let b = pop!();
                    push!(if a < b {1} else {0});
                },
                Instr::COMP_EQ => {
                    let a = pop!(); let b = pop!();
                    push!(if a == b {1} else {0});
                },
                Instr::COMP_GT => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else {0});
                },
                Instr::RELJUMP => {reljump!();},
                Instr::RELJUMP_GT => {reljump!(gt);},
                Instr::RELJUMP_LT => {reljump!(lt);},
                Instr::RELJUMP_EQ => {reljump!(eq);},
                Instr::STORE => {
                    let index = self.get_next_4_bytes() as usize;
                    self.locals[index] = pop!().unwrap();
                },
                Instr::LOAD => {
                    let index = self.get_next_4_bytes() as usize;
                    push!(self.locals[index]);
                },
                Instr::CALL => {
                    let id: u32 = self.get_next_4_bytes();
                    push_frame!(id);
                },
                Instr::RETURN => {
                    let val = pop!();
                    inpr.op_stack.resize(self.return_addr, 0)
                }
                Instr::PRINT => {
                    println!("PRINT: {}", pop!().unwrap());
                },
                Instr::DUMP_STACK => {
                    println!("{:?}", inpr.op_stack);
                },
                Instr::DUMP_GLOBALS => {
                    println!("{:?}", inpr.memory);},
            }
        }
        return None;    // Pop the current frame
    }
}

// TODO: Add tests
<commit_msg>Check debug flag when  debug printing<commit_after>use header::*;
use constants::*;
use instructions::Instruction as Instr;
use num::FromPrimitive;
use std::fmt;

#[derive(Debug, Default)]
pub struct Runtime {
    interpreter: Interpreter,
    call_stack: Vec<StackFrame>,
}

impl Runtime {
    pub fn new(mut data: Vec<u8>) -> Runtime {
        let mut r = Runtime {
            interpreter: Interpreter::new(data),
            call_stack: Vec::new(),
        };
        r
    }
    pub fn run(&mut self, options: &::Options) {
        debug!("Running...");

        let debug = options.debug;

        loop {
            // Need to wrap this here to limit the scope of last_frame borrow
            let dispatch_result = {
                let ln = self.call_stack.len();
                let mut last_frame = &mut self.call_stack[ln-1];
                last_frame.dispatch(&mut self.interpreter, debug)
            };
            // Push the new StackFrame, if CALL was issued
            if let Some(frm) = dispatch_result {
                self.call_stack.push(frm);
            }
        }
    }
}

#[derive(Debug, Default)]
pub struct Interpreter {
    // File data
    header: RaptorHeader,
    const_table: ConstTable,

    // Rutime stuff
    op_stack: Vec<i32>,
    memory: Vec<i32>,
}

// Should this be here?

#[derive(Debug, Default, Clone)]
pub struct StackFrame {
    locals: Vec<i32>,
    // The index of the first op in the op_stack that should be kept
    return_addr: usize,
    bytecode: Vec<u8>,
    bc_counter: usize
}

impl Interpreter {
    pub fn new(mut data: Vec<u8>) -> Interpreter {
        debug!("Bytecode length: {} bytes", data.len());
        let header = read_header(&data);
        data.drain(..HEADER_SIZE);
        let const_table: ConstTable = read_const_table(data.as_slice());
        debug!("Constant table length: {} bytes", const_table.bc_counter);
        debug!("Bytecode length: {} bytes", data.len());
        data.drain(..const_table.bc_counter);
        let sf = StackFrame {
            bytecode: data,
            ..Default::default()
        };
        let mut i = Interpreter {
            header: header,
            const_table: const_table,
            op_stack: Vec::new(),
            memory: Vec::new(),
        };
        i.memory.resize(i.header.var_count as usize, 0);
        i
    }
}

impl StackFrame {

    fn get_next_4_bytes(&mut self) -> u32 {
        let val = (self.bytecode[self.bc_counter] as u32) << 24 |
        (self.bytecode[self.bc_counter + 1] as u32) << 16 |
        (self.bytecode[self.bc_counter + 2] as u32) << 8 |
        (self.bytecode[self.bc_counter + 3] as u32);
        self.bc_counter += 4;
        debug!("get_next_4_bytes: 0x{:04X}", val);
        val
    }

    fn dispatch(&mut self, inpr: &mut Interpreter, debug: bool) -> Option<StackFrame> {
        use std::ops::*;
        use std::cmp::*;

        // Main loop
        while self.bc_counter != self.bytecode.len() {
            // info!("PC: {}", bc_counter);

            // Use FromPrimitive trait to convert a value to its enum
            let instr = Instr::from_u8(self.bytecode[self.bc_counter]);
            self.bc_counter += 1;

            if instr.is_none() {
                warn!("Unimplemented instruction: {:04X}", self.bytecode[self.bc_counter]);
                continue;
            }

            let instr = instr.unwrap();   // We're sure it's Some here, so unpack it.

            if debug {
                debug!("{:?}", instr);
            }

            macro_rules! push {
                ( $x:expr ) => {
                    inpr.op_stack.push($x);
                };
            }
            macro_rules! pop {
                () => {
                    inpr.op_stack.pop();
                };
            }
            macro_rules! operation {
                ($op:ident) => ({
                    let final_length: usize = inpr.op_stack.len().saturating_sub(2);
                    let val = inpr.op_stack.drain(final_length..).fold(
                        0, |acc, x| acc.$op(x)
                    );
                    push!(val);
                })
            }
            macro_rules! reljump {
                ($op:ident) => ({
                    let top = pop!().unwrap();
                    if top.$op(&0) {
                        reljump!();
                    } else {
                        self.get_next_4_bytes();
                        if debug {debug!("Jump not taken"); }
                    }
                });
                () => ({
                    let offset = (self.get_next_4_bytes() - 1) as i32;
                    // Need this if because you can't have negative usizes
                    if offset > 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.bc_counter += offset as usize;
                        if offset == 1 {debug!("RELJUMP 1 is redundant. This is a compiler bug")}
                    } else if offset < 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.bc_counter -= (-offset) as usize;
                    } else {
                        warn!("Invalid reljump offset: 0");
                    }
                });
            }

            macro_rules! push_frame {
                ($id:expr) => ({
                    let func_const = &inpr.const_table.funcs[$id as usize];
                    let mut sf = StackFrame {
                        locals: Vec::new(),
                        ..Default::default()
                    };
                    for _ in 0..func_const.arg_count {
                        sf.locals.push(pop!().unwrap());
                    }
                    sf.return_addr = inpr.op_stack.len();
                    sf.locals.resize((func_const.arg_count + func_const.local_count) as usize, 0);
                    if debug {
                        debug!("Pushed new frame: {}    {:?}", $id, sf);
                        debug!("Op stack: {:?}", inpr.op_stack);
                    }
                    return Some(sf);
                });
            }

            match instr {
                Instr::NOP => {},
                Instr::HALT => {
                    println!("HALT issued, stopped execution.");
                    if debug {
                        debug!("Stack: {:?}", inpr.op_stack);
                        debug!("Memory: {:?}", inpr.memory);
                    }
                },
                Instr::ICONST => {
                    let b = self.get_next_4_bytes() as i32;
                    push!(b);
                },
                Instr::POP => { pop!(); },
                Instr::ADD =>       { operation!(add);    },
                Instr::SUB =>       { operation!(sub);    },
                Instr::MULTIPLY =>  { operation!(mul);    },
                Instr::DIVIDE =>    { operation!(div);    },
                Instr::MODULUS =>   { operation!(rem);    },
                Instr::RSHIFT =>    { operation!(shl);    },
                Instr::LSHIFT =>    { operation!(shr);    },
                Instr::AND =>       { operation!(bitand); },
                Instr::OR =>        { operation!(bitor);  },
                Instr::NOT =>       {
                    let val = pop!().unwrap();
                    push!(val.not());
                },
                Instr::COMP => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else if a < b {-1} else {0});
                },
                Instr::COMP_LT => {
                    let a = pop!(); let b = pop!();
                    push!(if a < b {1} else {0});
                },
                Instr::COMP_EQ => {
                    let a = pop!(); let b = pop!();
                    push!(if a == b {1} else {0});
                },
                Instr::COMP_GT => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else {0});
                },
                Instr::RELJUMP => {reljump!();},
                Instr::RELJUMP_GT => {reljump!(gt);},
                Instr::RELJUMP_LT => {reljump!(lt);},
                Instr::RELJUMP_EQ => {reljump!(eq);},
                Instr::STORE => {
                    let index = self.get_next_4_bytes() as usize;
                    self.locals[index] = pop!().unwrap();
                },
                Instr::LOAD => {
                    let index = self.get_next_4_bytes() as usize;
                    push!(self.locals[index]);
                },
                Instr::CALL => {
                    let id: u32 = self.get_next_4_bytes();
                    push_frame!(id);
                },
                Instr::RETURN => {
                    let val = pop!();
                    inpr.op_stack.resize(self.return_addr, 0)
                }
                Instr::PRINT => {
                    println!("PRINT: {}", pop!().unwrap());
                },
                Instr::DUMP_STACK => {
                    println!("{:?}", inpr.op_stack);
                },
                Instr::DUMP_GLOBALS => {
                    println!("{:?}", inpr.memory);},
            }
        }
        return None;    // Pop the current frame
    }
}

// TODO: Add tests
<|endoftext|>


<commit_before>use ffi::{SockAddr, getaddrinfo, freeaddrinfo, addrinfo, sockaddr_storage, Timeout};
use core::{Protocol, AsIoContext, IoContext, Cancel, TimeoutLoc};
use handler::Handler;
use ip::{IpEndpoint, IpProtocol};

use std::io;
use std::marker::PhantomData;
use std::ffi::CString;

/// A query to be passed to a resolver.
pub trait ResolverQuery
 {
    fn iter(self) -> io::Result<ResolverIter
>;
}

impl
 ResolverQuery
 for (P, N, S)
where
    P: Protocol,
    N: AsRef<str>,
    S: AsRef<str>,
{
    fn iter(self) -> io::Result<ResolverIter
> {
        ResolverIter::new(&self.0, self.1.as_ref(), self.2.as_ref(), 0)
    }
}

/// A query of the resolver for the passive mode.
pub struct Passive;

/// An iterator over the entries produced by a resolver.
pub struct ResolverIter
 {
    ai: *mut addrinfo,
    base: *mut addrinfo,
    _marker: PhantomData
,
}

impl
 ResolverIter

where
    P: Protocol,
{
    pub fn new(pro: &P, host: &str, port: &str, flags: i32) -> io::Result<ResolverIter
> {
        let host = CString::new(host).unwrap();
        let port = CString::new(port).unwrap();
        let ai = getaddrinfo(pro, &host, &port, flags)?;
        Ok(ResolverIter {
            ai: ai,
            base: ai,
            _marker: PhantomData,
        })
    }
}

impl
 Drop for ResolverIter
 {
    fn drop(&mut self) {
        freeaddrinfo(self.base)
    }
}

impl
 Iterator for ResolverIter

where
    P: IpProtocol,
{
    type Item = IpEndpoint
;

    fn next(&mut self) -> Option<Self::Item> {
        if self.ai.is_null() {
            None
        } else {
            unsafe {
                let ep = IpEndpoint::from_ss(SockAddr::from(
                    (*self.ai).ai_addr as *const sockaddr_storage,
                    (*self.ai).ai_addrlen as u8,
                ));
                self.ai = (&*self.ai).ai_next;
                Some(ep)
            }
        }
    }
}

unsafe impl
 Send for ResolverIter
 {}

/// An entry produced by a resolver.
pub struct Resolver
 {
    ctx: IoContext,
    _marker: PhantomData
,
}

impl
 Resolver

where
    P: IpProtocol,
{
    pub fn new(ctx: &IoContext) -> Self {
        Resolver {
            ctx: ctx.clone(),
            _marker: PhantomData,
        }
    }

    pub fn async_connect<Q, F>(&self, query: Q, handler: F) -> F::Output
    where
        Q: ResolverQuery
,
        F: Handler<(P::Socket, IpEndpoint
), io::Error>,
    {
        async_resolve(self, self.resolve(query), handler)
    }

    pub fn connect<Q>(&self, query: Q) -> io::Result<(P::Socket, IpEndpoint
)>
    where
        Q: ResolverQuery
,
    {
        resolve(self, self.resolve(query))
    }

    pub fn resolve<Q>(&self, query: Q) -> io::Result<ResolverIter
>
    where
        Q: ResolverQuery
,
    {
        query.iter()
    }
}

impl
 Cancel for Resolver
 {
    fn cancel(&self) {
    }

    fn as_timeout(&self, loc: TimeoutLoc) -> &Timeout {
        unreachable!()
    }
}

unsafe impl
 AsIoContext for Resolver
 {
    fn as_ctx(&self) -> &IoContext {
        &self.ctx
    }
}

use self::ops::{async_resolve, resolve};
mod ops {
    use ffi::{SERVICE_NOT_FOUND, socket};
    use core::{Socket, AsIoContext, Exec, ThreadIoContext, Cancel};
    use ip::{IpProtocol, IpEndpoint, ResolverIter};
    use handler::{Handler, Complete, Yield, NoYield, Failure};

    use std::io;
    use std::marker::PhantomData;

    struct AsyncResolve<F, P, R>
    where
        P: IpProtocol,
    {
        re: *const R,
        it: ResolverIter
,
        handler: F,
        res: Option<(P::Socket, IpEndpoint
)>,
        _marker: PhantomData<(P, R)>,
    }

    unsafe impl<F, P, R> Send for AsyncResolve<F, P, R>
    where
        P: IpProtocol,
    {
    }

    impl<F, P, R> Handler<(), io::Error> for AsyncResolve<F, P, R>
    where
        F: Complete<
            (P::Socket, IpEndpoint
),
            io::Error,
        >,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        type Output = ();

        type Caller = Self;

        type Callee = NoYield;

        fn channel(self) -> (Self::Caller, Self::Callee) {
            (self, NoYield)
        }
    }

    impl<F, P, R> Complete<(), io::Error> for AsyncResolve<F, P, R>
    where
        F: Complete<
            (P::Socket, IpEndpoint
),
            io::Error,
        >,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        fn success(self, this: &mut ThreadIoContext, _: ()) {
            let AsyncResolve {
                re: _,
                it: _,
                res,
                handler,
                _marker,
            } = self;
            this.decrease_outstanding_work();
            handler.success(this, res.unwrap())
        }

        fn failure(self, this: &mut ThreadIoContext, err: io::Error) {
            this.decrease_outstanding_work();
            self.handler.failure(this, err)
        }
    }

    impl<F, P, R> Exec for AsyncResolve<F, P, R>
    where
        F: Complete<(P::Socket, IpEndpoint
), io::Error>,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        fn call(self, _: &mut ThreadIoContext) {
            unreachable!("");
        }

        fn call_box(mut self: Box<Self>, this: &mut ThreadIoContext) {
            if let Some(ep) = self.it.next() {
                let pro = ep.protocol().clone();
                match socket(&pro) {
                    Ok(soc) => {
                        self.res = Some((
                            unsafe { P::Socket::from_raw_fd(this.as_ctx(), soc, pro) },
                            ep,
                        ));
                        let &(ref soc, ref ep) =
                            unsafe { &*(self.res.as_ref().unwrap() as *const _) };
                        P::async_connect(soc, ep, *self);
                    }
                    Err(err) => self.failure(this, err.into()),
                }
            } else {
                self.failure(this, SERVICE_NOT_FOUND.into());
            }
        }
    }

    pub fn async_resolve<F, P, R>(
        re: &R,
        res: io::Result<ResolverIter
>,
        handler: F,
    ) -> F::Output
    where
        F: Handler<(P::Socket, IpEndpoint
), io::Error>,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        let (tx, rx) = handler.channel();
        match res {
            Ok(it) => {
                re.as_ctx().do_post(AsyncResolve {
                    re: re,
                    it: it,
                    handler: tx,
                    res: None,
                    _marker: PhantomData,
                })
            }
            Err(err) => re.as_ctx().do_dispatch(Failure::new(err, tx)),
        }
        rx.yield_wait(re)
    }

    pub fn resolve
(
        re: &R,
        res: io::Result<ResolverIter
>,
    ) -> io::Result<(P::Socket, IpEndpoint
)>
    where
        P: IpProtocol,
        R: Cancel,
    {
        for ep in res? {
            let pro = ep.protocol().clone();
            let soc = socket(&pro)?;
            let soc = unsafe { P::Socket::from_raw_fd(re.as_ctx(), soc, pro) };
            if let Ok(_) = P::connect(&soc, &ep) {
                return Ok((soc, ep));
            }
        }
        Err(SERVICE_NOT_FOUND.into())
    }
}
<commit_msg>fix segfault at async_resolve()<commit_after>use ffi::{SockAddr, getaddrinfo, freeaddrinfo, addrinfo, sockaddr_storage, Timeout};
use core::{Protocol, AsIoContext, IoContext, Cancel, TimeoutLoc};
use handler::Handler;
use ip::{IpEndpoint, IpProtocol};

use std::io;
use std::marker::PhantomData;
use std::ffi::CString;

/// A query to be passed to a resolver.
pub trait ResolverQuery
 {
    fn iter(self) -> io::Result<ResolverIter
>;
}

impl
 ResolverQuery
 for (P, N, S)
where
    P: Protocol,
    N: AsRef<str>,
    S: AsRef<str>,
{
    fn iter(self) -> io::Result<ResolverIter
> {
        ResolverIter::new(&self.0, self.1.as_ref(), self.2.as_ref(), 0)
    }
}

/// A query of the resolver for the passive mode.
pub struct Passive;

/// An iterator over the entries produced by a resolver.
pub struct ResolverIter
 {
    ai: *mut addrinfo,
    base: *mut addrinfo,
    _marker: PhantomData
,
}

impl
 ResolverIter

where
    P: Protocol,
{
    pub fn new(pro: &P, host: &str, port: &str, flags: i32) -> io::Result<ResolverIter
> {
        let host = CString::new(host).unwrap();
        let port = CString::new(port).unwrap();
        let ai = getaddrinfo(pro, &host, &port, flags)?;
        Ok(ResolverIter {
            ai: ai,
            base: ai,
            _marker: PhantomData,
        })
    }
}

impl
 Drop for ResolverIter
 {
    fn drop(&mut self) {
        freeaddrinfo(self.base)
    }
}

impl
 Iterator for ResolverIter

where
    P: IpProtocol,
{
    type Item = IpEndpoint
;

    fn next(&mut self) -> Option<Self::Item> {
        if self.ai.is_null() {
            None
        } else {
            unsafe {
                let ep = IpEndpoint::from_ss(SockAddr::from(
                    (*self.ai).ai_addr as *const sockaddr_storage,
                    (*self.ai).ai_addrlen as u8,
                ));
                self.ai = (&*self.ai).ai_next;
                Some(ep)
            }
        }
    }
}

unsafe impl
 Send for ResolverIter
 {}

/// An entry produced by a resolver.
pub struct Resolver
 {
    ctx: IoContext,
    _marker: PhantomData
,
}

impl
 Resolver

where
    P: IpProtocol,
{
    pub fn new(ctx: &IoContext) -> Self {
        Resolver {
            ctx: ctx.clone(),
            _marker: PhantomData,
        }
    }

    pub fn async_connect<Q, F>(&self, query: Q, handler: F) -> F::Output
    where
        Q: ResolverQuery
,
        F: Handler<(P::Socket, IpEndpoint
), io::Error>,
    {
        async_resolve(self, self.resolve(query), handler)
    }

    pub fn connect<Q>(&self, query: Q) -> io::Result<(P::Socket, IpEndpoint
)>
    where
        Q: ResolverQuery
,
    {
        resolve(self, self.resolve(query))
    }

    pub fn resolve<Q>(&self, query: Q) -> io::Result<ResolverIter
>
    where
        Q: ResolverQuery
,
    {
        query.iter()
    }
}

impl
 Cancel for Resolver
 {
    fn cancel(&self) {
    }

    fn as_timeout(&self, loc: TimeoutLoc) -> &Timeout {
        unreachable!()
    }
}

unsafe impl
 AsIoContext for Resolver
 {
    fn as_ctx(&self) -> &IoContext {
        &self.ctx
    }
}

use self::ops::{async_resolve, resolve};
mod ops {
    use ffi::{SERVICE_NOT_FOUND, socket};
    use core::{Socket, AsIoContext, Exec, ThreadIoContext, Cancel};
    use ip::{IpProtocol, IpEndpoint, ResolverIter};
    use handler::{Handler, Complete, Yield, NoYield, Failure};

    use std::io;
    use std::marker::PhantomData;

    struct AsyncResolve<F, P, R>
    where
        P: IpProtocol,
    {
        re: *const R,
        it: ResolverIter
,
        handler: F,
        res: Option<Box<(P::Socket, IpEndpoint
)>>,
        _marker: PhantomData<(P, R)>,
    }

    unsafe impl<F, P, R> Send for AsyncResolve<F, P, R>
    where
        P: IpProtocol,
    {
    }

    impl<F, P, R> Handler<(), io::Error> for AsyncResolve<F, P, R>
    where
        F: Complete<
            (P::Socket, IpEndpoint
),
            io::Error,
        >,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        type Output = ();

        type Caller = Self;

        type Callee = NoYield;

        fn channel(self) -> (Self::Caller, Self::Callee) {
            (self, NoYield)
        }
    }

    impl<F, P, R> Complete<(), io::Error> for AsyncResolve<F, P, R>
    where
        F: Complete<
            (P::Socket, IpEndpoint
),
            io::Error,
        >,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        fn success(self, this: &mut ThreadIoContext, _: ()) {
            let AsyncResolve {
                re: _,
                it: _,
                res,
                handler,
                _marker,
            } = self;
            this.decrease_outstanding_work();
            handler.success(this, *res.unwrap())
        }

        fn failure(self, this: &mut ThreadIoContext, err: io::Error) {
            this.decrease_outstanding_work();
            self.handler.failure(this, err)
        }
    }

    impl<F, P, R> Exec for AsyncResolve<F, P, R>
    where
        F: Complete<(P::Socket, IpEndpoint
), io::Error>,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        fn call(self, _: &mut ThreadIoContext) {
            unreachable!("");
        }

        fn call_box(mut self: Box<Self>, this: &mut ThreadIoContext) {
            if let Some(ep) = self.it.next() {
                let pro = ep.protocol().clone();
                match socket(&pro) {
                    Ok(soc) => {
                        self.res = Some(Box::new((
                            unsafe { P::Socket::from_raw_fd(this.as_ctx(), soc, pro) },
                            ep,
                        )));
                        // FIXME
                        let res = &**self.res.as_ref().unwrap() as *const (P::Socket, IpEndpoint
);
                        unsafe { P::async_connect(&(*res).0, &(*res).1, *self); }
                    }
                    Err(err) => self.failure(this, err.into()),
                }
            } else {
                self.failure(this, SERVICE_NOT_FOUND.into());
            }
        }
    }

    pub fn async_resolve<F, P, R>(
        re: &R,
        res: io::Result<ResolverIter
>,
        handler: F,
    ) -> F::Output
    where
        F: Handler<(P::Socket, IpEndpoint
), io::Error>,
        P: IpProtocol,
        R: Cancel + 'static,
    {
        let (tx, rx) = handler.channel();
        match res {
            Ok(it) => {
                re.as_ctx().do_post(AsyncResolve {
                    re: re,
                    it: it,
                    handler: tx,
                    res: None,
                    _marker: PhantomData,
                })
            }
            Err(err) => re.as_ctx().do_dispatch(Failure::new(err, tx)),
        }
        rx.yield_wait(re)
    }

    pub fn resolve
(
        re: &R,
        res: io::Result<ResolverIter
>,
    ) -> io::Result<(P::Socket, IpEndpoint
)>
    where
        P: IpProtocol,
        R: Cancel,
    {
        for ep in res? {
            let pro = ep.protocol().clone();
            let soc = socket(&pro)?;
            let soc = unsafe { P::Socket::from_raw_fd(re.as_ctx(), soc, pro) };
            if let Ok(_) = P::connect(&soc, &ep) {
                return Ok((soc, ep));
            }
        }
        Err(SERVICE_NOT_FOUND.into())
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::c_char;
use std::ffi::{CString,CStr};
use std::mem;
use std::ptr;
use std::hash::{Hash,Hasher,SipHasher};
use super::Name;

macro_rules! str_to_char_star {
    ($str:expr) => { {
        let s = CString::new($str).unwrap();
        s.into_raw()
    } }
}

macro_rules! option_str_to_char_star {
    ($opt:expr) => {
        match $opt {
            Some(string) => {
                let s = CString::new(string).unwrap();
                s.into_raw()
            }
            None => ptr::null()
        }
    }
}

#[no_mangle]
pub extern "C" fn human_name_parse(input: *const libc::c_char) -> Option<Box<Name>> {
    let s = unsafe {
        CStr::from_ptr(input).to_string_lossy()
    };
    Name::parse(&*s).map(|n| Box::new(n))
}

#[no_mangle]
pub extern "C" fn human_name_free_name(name_ptr: *mut Name) {
    unsafe {
        mem::drop(Box::from_raw(name_ptr));
    }
}

#[no_mangle]
pub extern "C" fn human_name_free_string(str_ptr: *mut c_char) {
    unsafe {
        mem::drop(CString::from_raw(str_ptr));
    }
}

#[no_mangle]
pub extern "C" fn human_name_consistent_with(a: &Name, b: &Name) -> bool {
    a.consistent_with(b)
}

#[no_mangle]
pub extern "C" fn human_name_hash(name: &Name) -> u64 {
    let mut s = SipHasher::new();
    name.hash(&mut s);
    s.finish()
}

#[no_mangle]
pub extern "C" fn human_name_surname(name: &Name) -> *const c_char {
    str_to_char_star!(name.surname().into_owned())
}

#[no_mangle]
pub extern "C" fn human_name_given_name(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.given_name())
}

#[no_mangle]
pub extern "C" fn human_name_initials(name: &Name) -> *const c_char {
    str_to_char_star!(name.initials())
}

#[no_mangle]
pub extern "C" fn human_name_first_initial(name: &Name) -> *const c_char {
    str_to_char_star!(name.first_initial().to_string())
}

#[no_mangle]
pub extern "C" fn human_name_middle_initials(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.middle_initials())
}

#[no_mangle]
pub extern "C" fn human_name_goes_by_middle_name(name: &Name) -> bool {
    name.goes_by_middle_name()
}

#[no_mangle]
pub extern "C" fn human_name_middle_names(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.middle_name().map(|n| n.into_owned()))
}

#[no_mangle]
pub extern "C" fn human_name_suffix(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.suffix())
}

#[no_mangle]
pub extern "C" fn human_name_display_short(name: &Name) -> *const c_char {
    str_to_char_star!(name.display_short())
}

#[no_mangle]
pub extern "C" fn human_name_display_full(name: &Name) -> *const c_char {
    str_to_char_star!(name.display_full())
}
<commit_msg>rustfmt external.rs<commit_after>extern crate libc;

use self::libc::c_char;
use std::ffi::{CString, CStr};
use std::mem;
use std::ptr;
use std::hash::{Hash, Hasher, SipHasher};
use super::Name;

macro_rules! str_to_char_star {
    ($str:expr) => { {
        let s = CString::new($str).unwrap();
        s.into_raw()
    } }
}

macro_rules! option_str_to_char_star {
    ($opt:expr) => {
        match $opt {
            Some(string) => {
                let s = CString::new(string).unwrap();
                s.into_raw()
            }
            None => ptr::null()
        }
    }
}

#[no_mangle]
pub extern "C" fn human_name_parse(input: *const libc::c_char) -> Option<Box<Name>> {
    let s = unsafe { CStr::from_ptr(input).to_string_lossy() };
    Name::parse(&*s).map(|n| Box::new(n))
}

#[no_mangle]
pub extern "C" fn human_name_free_name(name_ptr: *mut Name) {
    unsafe {
        mem::drop(Box::from_raw(name_ptr));
    }
}

#[no_mangle]
pub extern "C" fn human_name_free_string(str_ptr: *mut c_char) {
    unsafe {
        mem::drop(CString::from_raw(str_ptr));
    }
}

#[no_mangle]
pub extern "C" fn human_name_consistent_with(a: &Name, b: &Name) -> bool {
    a.consistent_with(b)
}

#[no_mangle]
pub extern "C" fn human_name_hash(name: &Name) -> u64 {
    let mut s = SipHasher::new();
    name.hash(&mut s);
    s.finish()
}

#[no_mangle]
pub extern "C" fn human_name_surname(name: &Name) -> *const c_char {
    str_to_char_star!(name.surname().into_owned())
}

#[no_mangle]
pub extern "C" fn human_name_given_name(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.given_name())
}

#[no_mangle]
pub extern "C" fn human_name_initials(name: &Name) -> *const c_char {
    str_to_char_star!(name.initials())
}

#[no_mangle]
pub extern "C" fn human_name_first_initial(name: &Name) -> *const c_char {
    str_to_char_star!(name.first_initial().to_string())
}

#[no_mangle]
pub extern "C" fn human_name_middle_initials(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.middle_initials())
}

#[no_mangle]
pub extern "C" fn human_name_goes_by_middle_name(name: &Name) -> bool {
    name.goes_by_middle_name()
}

#[no_mangle]
pub extern "C" fn human_name_middle_names(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.middle_name().map(|n| n.into_owned()))
}

#[no_mangle]
pub extern "C" fn human_name_suffix(name: &Name) -> *const c_char {
    option_str_to_char_star!(name.suffix())
}

#[no_mangle]
pub extern "C" fn human_name_display_short(name: &Name) -> *const c_char {
    str_to_char_star!(name.display_short())
}

#[no_mangle]
pub extern "C" fn human_name_display_full(name: &Name) -> *const c_char {
    str_to_char_star!(name.display_full())
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the Windows console api

extern crate libc;

use std::io::IoResult;

use attr;
use color;
use {Terminal,UnwrappableTerminal};

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    def_foreground: color::Color,
    def_background: color::Color,
    foreground: color::Color,
    background: color::Color,
}

#[allow(non_snake_case)]
#[repr(C)]
struct CONSOLE_SCREEN_BUFFER_INFO {
    dwSize: [libc::c_short, ..2],
    dwCursorPosition: [libc::c_short, ..2],
    wAttributes: libc::WORD,
    srWindow: [libc::c_short, ..4],
    dwMaximumWindowSize: [libc::c_short, ..2],
}

#[allow(non_snake_case)]
#[link(name = "kernel32")]
extern "system" {
    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
    fn GetConsoleScreenBufferInfo(handle: libc::HANDLE,
                                  info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> libc::BOOL;
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

fn bits_to_color(bits: u16) -> color::Color {
    let bits = bits & 0x7;
    let color = match bits {
        0 => color::BLACK,
        0x1 => color::BLUE,
        0x2 => color::GREEN,
        0x4 => color::RED,
        0x6 => color::YELLOW,
        0x5 => color::MAGENTA,
        0x3 => color::CYAN,
        0x7 => color::WHITE,
        _ => unreachable!()
    };

    if bits >= 8 {
        color | 0x8
    } else {
        color
    }
}

impl<T: Writer> WinConsole<T> {
    fn apply(&mut self) {
        let _unused = self.buf.flush();
        let mut accum: libc::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;

        unsafe {
            // Magic -11 means stdout, from
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
            //
            // You may be wondering, "but what about stderr?", and the answer
            // to that is that setting terminal attributes on the stdout
            // handle also sets them for stderr, since they go to the same
            // terminal! Admittedly, this is fragile, since stderr could be
            // redirected to a different console. This is good enough for
            // rustc though. See #13400.
            let out = GetStdHandle(-11);
            SetConsoleTextAttribute(out, accum);
        }
    }
}

impl<T: Writer> Writer for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        self.buf.flush()
    }
}

impl<T: Writer> Terminal<T> for WinConsole<T> {
    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
        self.foreground = color;
        self.apply();

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
        self.background = color;
        self.apply();

        Ok(true)
    }

    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
        match attr {
            attr::ForegroundColor(f) => {
                self.foreground = f;
                self.apply();
                Ok(true)
            },
            attr::BackgroundColor(b) => {
                self.background = b;
                self.apply();
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: attr::Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> IoResult<()> {
        self.foreground = self.def_foreground;
        self.background = self.def_background;
        self.apply();

        Ok(())
    }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
}

impl<T: Writer> WinConsole<T> {
     fn new(out: T) -> Option<Box<WinConsole<T>+Send+'static>> {
        let fg;
        let bg;
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 {
                fg = bits_to_color(buffer_info.wAttributes);
                bg = bits_to_color(buffer_info.wAttributes >> 4);
            } else {
                fg = color::WHITE;
                bg = color::BLACK;
            }
        }
        Some(box WinConsole { buf: out,
                              def_foreground: fg, def_background: bg,
                              foreground: fg, background: bg } )
    }
}

impl<T: Writer> UnwrappableTerminal<T> for WinConsole<T> {
    fn unwrap(self) -> T { self.buf }
}
<commit_msg>Try and fix Windows terminal<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the Windows console api

extern crate libc;

use std::io::IoResult;

use attr;
use color;
use {Terminal,UnwrappableTerminal};

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    def_foreground: color::Color,
    def_background: color::Color,
    foreground: color::Color,
    background: color::Color,
}

#[allow(non_snake_case)]
#[repr(C)]
struct CONSOLE_SCREEN_BUFFER_INFO {
    dwSize: [libc::c_short, ..2],
    dwCursorPosition: [libc::c_short, ..2],
    wAttributes: libc::WORD,
    srWindow: [libc::c_short, ..4],
    dwMaximumWindowSize: [libc::c_short, ..2],
}

#[allow(non_snake_case)]
#[link(name = "kernel32")]
extern "system" {
    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
    fn GetConsoleScreenBufferInfo(handle: libc::HANDLE,
                                  info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> libc::BOOL;
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

fn bits_to_color(bits: u16) -> color::Color {
    let bits = bits & 0x7;
    let color = match bits {
        0 => color::BLACK,
        0x1 => color::BLUE,
        0x2 => color::GREEN,
        0x4 => color::RED,
        0x6 => color::YELLOW,
        0x5 => color::MAGENTA,
        0x3 => color::CYAN,
        0x7 => color::WHITE,
        _ => unreachable!()
    };

    if bits >= 8 {
        color | 0x8
    } else {
        color
    }
}

impl<T: Writer+Send> WinConsole<T> {
    fn apply(&mut self) {
        let _unused = self.buf.flush();
        let mut accum: libc::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;

        unsafe {
            // Magic -11 means stdout, from
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
            //
            // You may be wondering, "but what about stderr?", and the answer
            // to that is that setting terminal attributes on the stdout
            // handle also sets them for stderr, since they go to the same
            // terminal! Admittedly, this is fragile, since stderr could be
            // redirected to a different console. This is good enough for
            // rustc though. See #13400.
            let out = GetStdHandle(-11);
            SetConsoleTextAttribute(out, accum);
        }
    }

    /// Returns `None` whenever the terminal cannot be created for some
    /// reason.
    pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
        let fg;
        let bg;
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 {
                fg = bits_to_color(buffer_info.wAttributes);
                bg = bits_to_color(buffer_info.wAttributes >> 4);
            } else {
                fg = color::WHITE;
                bg = color::BLACK;
            }
        }
        Some(box WinConsole { buf: out,
                              def_foreground: fg, def_background: bg,
                              foreground: fg, background: bg } as Box<Terminal<T>+Send>)
    }
}

impl<T: Writer> Writer for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        self.buf.flush()
    }
}

impl<T: Writer+Send> Terminal<T> for WinConsole<T> {
    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
        self.foreground = color;
        self.apply();

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
        self.background = color;
        self.apply();

        Ok(true)
    }

    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
        match attr {
            attr::ForegroundColor(f) => {
                self.foreground = f;
                self.apply();
                Ok(true)
            },
            attr::BackgroundColor(b) => {
                self.background = b;
                self.apply();
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: attr::Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> IoResult<()> {
        self.foreground = self.def_foreground;
        self.background = self.def_background;
        self.apply();

        Ok(())
    }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
}

impl<T: Writer+Send> UnwrappableTerminal<T> for WinConsole<T> {
    fn unwrap(self) -> T { self.buf }
}
<|endoftext|>