<commit_before>use std::cell::RefCell;

use buffer::Line;

pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn is_right(&self) -> bool {
        match *self {
            Direction::Right => true,
            _                => false
        }
    }
    pub fn is_left(&self) -> bool {
        match *self {
            Direction::Left => true,
            _               => false
        }
    }
}

#[deriving(Clone)]
pub struct Cursor<'c> {
    pub offset: uint,
    line: Option<&'c RefCell<Line>>,
}

impl<'c> Cursor<'c> {
    /// Create a new cursor instance
    pub fn new() -> Cursor<'c> {
        Cursor {
            offset: 0,
            line: None,
        }
    }

    pub fn get_position(&self) -> (uint, uint) {
        (self.offset, self.get_linenum())
    }

    pub fn get_linenum(&self) -> uint {
        self.line.unwrap().borrow().linenum
    }

    pub fn get_offset(&self) -> uint {
        self.offset
    }

    pub fn set_offset(&mut self, offset: uint) {
        self.offset = offset;
    }

    pub fn set_line(&mut self, line: Option<&'c RefCell<Line>>) {
        self.line = line;

        // check that the current offset is longer than the length of the line
        let offset = self.get_offset();
        let line_length = self.get_line().borrow().len();
        if offset > line_length {
            self.set_offset(line_length);
        }
    }

    pub fn get_line(&self) -> &'c RefCell<Line> {
        self.line.unwrap()
    }

    pub fn get_line_length(&self) -> uint {
        self.get_line().borrow().len()
    }

    pub fn delete_backward_char(&mut self) {
        let offset = self.get_offset();
        let line = self.get_line();
        line.borrow_mut().data.remove(offset-1);
        self.set_offset(offset-1);
    }

    pub fn delete_forward_char(&mut self) {
        let offset = self.get_offset();
        let line = self.get_line();
        line.borrow_mut().data.remove(offset);
        self.set_offset(offset);
    }

    pub fn insert_char(&mut self, ch: char) {
        let offset = self.get_offset();
        let line = self.get_line();
        line.borrow_mut().data.insert(offset, ch);
        self.set_offset(offset+1)
    }

    pub fn move_right(&mut self) {
        let line_len = self.get_line().borrow().len();
        let current_offset = self.get_offset();
        if line_len > current_offset {
            self.set_offset(current_offset + 1);
        }
    }

    pub fn move_left(&mut self) {
        let current_offset = self.get_offset();
        if current_offset > 0 {
            self.set_offset(current_offset - 1);
        }
    }

    pub fn get_status_text(&self) -> String {
        let (offset, line_num) = self.get_position();
        format!("({}, {})", offset, line_num)
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use cursor::Cursor;
    use buffer::Line;

    #[test]
    fn test_moving_right() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));

        assert_eq!(cursor.offset, 0);
        cursor.move_right();
        assert_eq!(cursor.offset, 1);
    }

    #[test]
    fn test_moving_left() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));
        cursor.set_offset(1);

        assert_eq!(cursor.offset, 1);
        cursor.move_left();
        assert_eq!(cursor.offset, 0);
    }

    #[test]
    fn test_get_position() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_position(), (0, 1));
    }

    #[test]
    fn test_get_linenum() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_linenum(), 1);
    }

    #[test]
    fn test_get_offset() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_offset(), 0)
    }

    #[test]
    fn test_set_offset() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));
        cursor.set_offset(3);

        assert_eq!(cursor.offset, 3);
    }

    #[test]
    fn test_moving_to_end_of_line_when_set() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_offset(10);
        cursor.set_line(Some(&line));

        assert_eq!(cursor.offset, 4);
    }

    #[test]
    fn test_get_line_length() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_line_length(), 4);
    }

    #[test]
    fn test_delete_backward_char() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));
        cursor.set_offset(1);
        cursor.delete_backward_char();

        assert_eq!(line.borrow().data, "est".to_string());
    }

    #[test]
    fn test_delete_forward_char() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));
        cursor.delete_forward_char();

        assert_eq!(line.borrow().data, "est".to_string());
    }

    #[test]
    fn test_insert_char() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));
        cursor.insert_char('x');

        assert_eq!(line.borrow().data, "xtest".to_string());
    }

    #[test]
    fn test_get_status_text() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_status_text(), "(0, 1)".to_string());
    }

}
<commit_msg>Refactored cursor tests<commit_after>use std::cell::RefCell;

use buffer::Line;

pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn is_right(&self) -> bool {
        match *self {
            Direction::Right => true,
            _                => false
        }
    }
    pub fn is_left(&self) -> bool {
        match *self {
            Direction::Left => true,
            _               => false
        }
    }
}

#[deriving(Clone)]
pub struct Cursor<'c> {
    pub offset: uint,
    line: Option<&'c RefCell<Line>>,
}

impl<'c> Cursor<'c> {
    /// Create a new cursor instance
    pub fn new() -> Cursor<'c> {
        Cursor {
            offset: 0,
            line: None,
        }
    }

    pub fn get_position(&self) -> (uint, uint) {
        (self.offset, self.get_linenum())
    }

    pub fn get_linenum(&self) -> uint {
        self.line.unwrap().borrow().linenum
    }

    pub fn get_offset(&self) -> uint {
        self.offset
    }

    pub fn set_offset(&mut self, offset: uint) {
        self.offset = offset;
    }

    pub fn set_line(&mut self, line: Option<&'c RefCell<Line>>) {
        self.line = line;

        // check that the current offset is longer than the length of the line
        let offset = self.get_offset();
        let line_length = self.get_line().borrow().len();
        if offset > line_length {
            self.set_offset(line_length);
        }
    }

    pub fn get_line(&self) -> &'c RefCell<Line> {
        self.line.unwrap()
    }

    pub fn get_line_length(&self) -> uint {
        self.get_line().borrow().len()
    }

    pub fn delete_backward_char(&mut self) {
        let offset = self.get_offset();
        let line = self.get_line();
        line.borrow_mut().data.remove(offset-1);
        self.set_offset(offset-1);
    }

    pub fn delete_forward_char(&mut self) {
        let offset = self.get_offset();
        let line = self.get_line();
        line.borrow_mut().data.remove(offset);
        self.set_offset(offset);
    }

    pub fn insert_char(&mut self, ch: char) {
        let offset = self.get_offset();
        let line = self.get_line();
        line.borrow_mut().data.insert(offset, ch);
        self.set_offset(offset+1)
    }

    pub fn move_right(&mut self) {
        let line_len = self.get_line().borrow().len();
        let current_offset = self.get_offset();
        if line_len > current_offset {
            self.set_offset(current_offset + 1);
        }
    }

    pub fn move_left(&mut self) {
        let current_offset = self.get_offset();
        if current_offset > 0 {
            self.set_offset(current_offset - 1);
        }
    }

    pub fn get_status_text(&self) -> String {
        let (offset, line_num) = self.get_position();
        format!("({}, {})", offset, line_num)
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use cursor::Cursor;
    use buffer::Line;

    fn setup_cursor<'c>() -> Cursor<'c> {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));
        return cursor
    }

    #[test]
    fn test_moving_right() {
        let mut cursor = setup_cursor();

        assert_eq!(cursor.offset, 0);
        cursor.move_right();
        assert_eq!(cursor.offset, 1);
    }

    #[test]
    fn test_moving_left() {
        let mut cursor = setup_cursor();
        cursor.set_offset(1);

        assert_eq!(cursor.offset, 1);
        cursor.move_left();
        assert_eq!(cursor.offset, 0);
    }

    #[test]
    fn test_get_position() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));
        assert_eq!(cursor.get_position(), (0, 1));
    }

    #[test]
    fn test_get_linenum() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));
        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_linenum(), 1);
    }

    #[test]
    fn test_get_offset() {
        let cursor = setup_cursor();
        assert_eq!(cursor.get_offset(), 0)
    }

    #[test]
    fn test_set_offset() {
        let mut cursor = setup_cursor();
        cursor.set_offset(3);

        assert_eq!(cursor.offset, 3);
    }

    #[test]
    fn test_moving_to_end_of_line_when_set() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_offset(10);
        cursor.set_line(Some(&line));

        assert_eq!(cursor.offset, 4);
    }

    #[test]
    fn test_get_line_length() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));

        assert_eq!(cursor.get_line_length(), 4);
    }

    #[test]
    fn test_delete_backward_char() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));
        cursor.set_offset(1);
        cursor.delete_backward_char();

        assert_eq!(line.borrow().data, "est".to_string());
    }

    #[test]
    fn test_delete_forward_char() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));
        cursor.delete_forward_char();

        assert_eq!(line.borrow().data, "est".to_string());
    }

    #[test]
    fn test_insert_char() {
        let mut cursor = Cursor::new();
        let line = RefCell::new(Line::new("test".to_string(), 1));

        cursor.set_line(Some(&line));
        cursor.insert_char('x');

        assert_eq!(line.borrow().data, "xtest".to_string());
    }

    #[test]
    fn test_get_status_text() {
        let cursor = setup_cursor();
        assert_eq!(cursor.get_status_text(), "(0, 1)".to_string());
    }

}
<|endoftext|>


<commit_before>//! Deserializing TOML into Rust structures.
//!
//! This module contains all the Serde support for deserializing TOML documents into Rust structures.

use itertools::Itertools;
use serde::de::DeserializeOwned;

mod array;
mod inline_table;
mod item;
mod table;
mod table_enum;
mod value;

use array::*;
use inline_table::*;
use item::*;
use table::*;
use table_enum::*;

/// Errors that can occur when deserializing a type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
    inner: Box<ErrorInner>,
}

#[derive(Debug, PartialEq, Eq, Clone)]
struct ErrorInner {
    message: String,
    reverse_key: Vec<crate::InternalString>,
}

impl Error {
    pub(crate) fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Error {
            inner: Box::new(ErrorInner {
                message: msg.to_string(),
                reverse_key: Default::default(),
            }),
        }
    }

    pub(crate) fn parent_key(&mut self, key: crate::InternalString) {
        self.inner.reverse_key.push(key);
    }
}

impl serde::de::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Error::custom(msg)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.inner.message.fmt(f)?;

        if !self.inner.reverse_key.is_empty() {
            write!(f, " for key `")?;
            for (i, k) in self.inner.reverse_key.iter().rev().enumerate() {
                if i > 0 {
                    write!(f, ".")?;
                }
                write!(f, "{}", k)?;
            }
            write!(f, "`")?;
        }

        Ok(())
    }
}

impl From<crate::TomlError> for Error {
    fn from(e: crate::TomlError) -> Error {
        Self::custom(e)
    }
}

impl From<Error> for crate::TomlError {
    fn from(e: Error) -> crate::TomlError {
        Self::custom(e.to_string())
    }
}

impl std::error::Error for Error {}

/// Convert a value into `T`.
pub fn from_str<T>(s: &'_ str) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    let d = s.parse::<crate::Document>()?;
    from_document(d)
}

/// Convert a value into `T`.
pub fn from_slice<T>(s: &'_ [u8]) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    let s = std::str::from_utf8(s).map_err(Error::custom)?;
    from_str(s)
}

/// Convert a document into `T`.
pub fn from_document<T>(d: crate::Document) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    let deserializer = Deserializer::new(d);
    T::deserialize(deserializer)
}

/// Convert an item into `T`.
pub fn from_item<T>(d: crate::Item) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    T::deserialize(d)
}

/// Deserialization implementation for TOML.
pub struct Deserializer {
    input: crate::Document,
}

impl Deserializer {
    /// Deserialization implementation for TOML.
    pub fn new(input: crate::Document) -> Self {
        Self { input }
    }
}

impl<'de, 'a> serde::Deserializer<'de> for Deserializer {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.input.deserialize_any(visitor)
    }

    // `None` is interpreted as a missing field so be sure to implement `Some`
    // as a present field.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.input.deserialize_option(visitor)
    }

    // Called when the type to deserialize is an enum, as opposed to a field in the type.
    fn deserialize_enum<V>(
        self,
        name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.input.deserialize_enum(name, variants, visitor)
    }

    serde::forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
        bytes byte_buf map unit newtype_struct
        ignored_any unit_struct tuple_struct tuple identifier struct
    }
}

impl<'de, 'a> serde::Deserializer<'de> for crate::Document {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.root.deserialize_any(visitor)
    }

    // `None` is interpreted as a missing field so be sure to implement `Some`
    // as a present field.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.root.deserialize_option(visitor)
    }

    // Called when the type to deserialize is an enum, as opposed to a field in the type.
    fn deserialize_enum<V>(
        self,
        name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.root.deserialize_enum(name, variants, visitor)
    }

    serde::forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
        bytes byte_buf map unit newtype_struct
        ignored_any unit_struct tuple_struct tuple identifier struct
    }
}

impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::Document {
    type Deserializer = Self;

    fn into_deserializer(self) -> Self {
        self
    }
}

pub(crate) fn validate_struct_keys(
    table: &crate::table::KeyValuePairs,
    fields: &'static [&'static str],
) -> Result<(), Error> {
    let extra_fields = table
        .iter()
        .filter_map(|(key, _val)| {
            if !fields.contains(&key.as_str()) {
                Some(key.clone())
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    if extra_fields.is_empty() {
        Ok(())
    } else {
        Err(Error::custom(format!(
            "unexpected keys in table: {}, available keys: {}",
            extra_fields.iter().join(", "),
            fields.iter().join(", "),
        )))
    }
}
<commit_msg>feat(de): Expose line_col when available<commit_after>//! Deserializing TOML into Rust structures.
//!
//! This module contains all the Serde support for deserializing TOML documents into Rust structures.

use itertools::Itertools;
use serde::de::DeserializeOwned;

mod array;
mod inline_table;
mod item;
mod table;
mod table_enum;
mod value;

use array::*;
use inline_table::*;
use item::*;
use table::*;
use table_enum::*;

/// Errors that can occur when deserializing a type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
    inner: Box<ErrorInner>,
}

#[derive(Debug, PartialEq, Eq, Clone)]
struct ErrorInner {
    message: String,
    reverse_key: Vec<crate::InternalString>,
    line_col: Option<(usize, usize)>,
}

impl Error {
    pub(crate) fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Error {
            inner: Box::new(ErrorInner {
                message: msg.to_string(),
                reverse_key: Default::default(),
                line_col: None,
            }),
        }
    }

    pub(crate) fn parent_key(&mut self, key: crate::InternalString) {
        self.inner.reverse_key.push(key);
    }

    /// Produces a (line, column) pair of the position of the error if available
    ///
    /// All indexes are 0-based.
    pub fn line_col(&self) -> Option<(usize, usize)> {
        self.inner.line_col
    }
}

impl serde::de::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Error::custom(msg)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.inner.message.fmt(f)?;

        if !self.inner.reverse_key.is_empty() {
            write!(f, " for key `")?;
            for (i, k) in self.inner.reverse_key.iter().rev().enumerate() {
                if i > 0 {
                    write!(f, ".")?;
                }
                write!(f, "{}", k)?;
            }
            write!(f, "`")?;
        }

        Ok(())
    }
}

impl From<crate::TomlError> for Error {
    fn from(e: crate::TomlError) -> Error {
        let line_col = e.line_col();
        let mut err = Self::custom(e);
        err.inner.line_col = line_col;
        err
    }
}

impl From<Error> for crate::TomlError {
    fn from(e: Error) -> crate::TomlError {
        Self::custom(e.to_string())
    }
}

impl std::error::Error for Error {}

/// Convert a value into `T`.
pub fn from_str<T>(s: &'_ str) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    let d = s.parse::<crate::Document>()?;
    from_document(d)
}

/// Convert a value into `T`.
pub fn from_slice<T>(s: &'_ [u8]) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    let s = std::str::from_utf8(s).map_err(Error::custom)?;
    from_str(s)
}

/// Convert a document into `T`.
pub fn from_document<T>(d: crate::Document) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    let deserializer = Deserializer::new(d);
    T::deserialize(deserializer)
}

/// Convert an item into `T`.
pub fn from_item<T>(d: crate::Item) -> Result<T, Error>
where
    T: DeserializeOwned,
{
    T::deserialize(d)
}

/// Deserialization implementation for TOML.
pub struct Deserializer {
    input: crate::Document,
}

impl Deserializer {
    /// Deserialization implementation for TOML.
    pub fn new(input: crate::Document) -> Self {
        Self { input }
    }
}

impl<'de, 'a> serde::Deserializer<'de> for Deserializer {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.input.deserialize_any(visitor)
    }

    // `None` is interpreted as a missing field so be sure to implement `Some`
    // as a present field.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.input.deserialize_option(visitor)
    }

    // Called when the type to deserialize is an enum, as opposed to a field in the type.
    fn deserialize_enum<V>(
        self,
        name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.input.deserialize_enum(name, variants, visitor)
    }

    serde::forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
        bytes byte_buf map unit newtype_struct
        ignored_any unit_struct tuple_struct tuple identifier struct
    }
}

impl<'de, 'a> serde::Deserializer<'de> for crate::Document {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.root.deserialize_any(visitor)
    }

    // `None` is interpreted as a missing field so be sure to implement `Some`
    // as a present field.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.root.deserialize_option(visitor)
    }

    // Called when the type to deserialize is an enum, as opposed to a field in the type.
    fn deserialize_enum<V>(
        self,
        name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.root.deserialize_enum(name, variants, visitor)
    }

    serde::forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
        bytes byte_buf map unit newtype_struct
        ignored_any unit_struct tuple_struct tuple identifier struct
    }
}

impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::Document {
    type Deserializer = Self;

    fn into_deserializer(self) -> Self {
        self
    }
}

pub(crate) fn validate_struct_keys(
    table: &crate::table::KeyValuePairs,
    fields: &'static [&'static str],
) -> Result<(), Error> {
    let extra_fields = table
        .iter()
        .filter_map(|(key, _val)| {
            if !fields.contains(&key.as_str()) {
                Some(key.clone())
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    if extra_fields.is_empty() {
        Ok(())
    } else {
        Err(Error::custom(format!(
            "unexpected keys in table: {}, available keys: {}",
            extra_fields.iter().join(", "),
            fields.iter().join(", "),
        )))
    }
}
<|endoftext|>


<commit_before>use cfg_if::cfg_if;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{binemit, ir};
use std::fmt::Write;

pub struct PrintRelocs {
    pub flag_print: bool,
    pub text: String,
}

impl PrintRelocs {
    pub fn new(flag_print: bool) -> PrintRelocs {
        Self {
            flag_print,
            text: String::new(),
        }
    }
}

impl binemit::RelocSink for PrintRelocs {
    fn reloc_ebb(
        &mut self,
        where_: binemit::CodeOffset,
        r: binemit::Reloc,
        offset: binemit::CodeOffset,
    ) {
        if self.flag_print {
            write!(
                &mut self.text,
                "reloc_ebb: {} {} at {}\n",
                r, offset, where_
            )
            .unwrap();
        }
    }

    fn reloc_external(
        &mut self,
        where_: binemit::CodeOffset,
        r: binemit::Reloc,
        name: &ir::ExternalName,
        addend: binemit::Addend,
    ) {
        if self.flag_print {
            write!(
                &mut self.text,
                "reloc_external: {} {} {} at {}\n",
                r, name, addend, where_
            )
            .unwrap();
        }
    }

    fn reloc_jt(&mut self, where_: binemit::CodeOffset, r: binemit::Reloc, jt: ir::JumpTable) {
        if self.flag_print {
            write!(&mut self.text, "reloc_jt: {} {} at {}\n", r, jt, where_).unwrap();
        }
    }
}

pub struct PrintTraps {
    pub flag_print: bool,
    pub text: String,
}

impl PrintTraps {
    pub fn new(flag_print: bool) -> PrintTraps {
        Self {
            flag_print,
            text: String::new(),
        }
    }
}

impl binemit::TrapSink for PrintTraps {
    fn trap(&mut self, offset: binemit::CodeOffset, _srcloc: ir::SourceLoc, code: ir::TrapCode) {
        if self.flag_print {
            write!(&mut self.text, "trap: {} at {}\n", code, offset).unwrap();
        }
    }
}

cfg_if! {
    if #[cfg(feature = "disas")] {
        use capstone::prelude::*;
        use target_lexicon::Architecture;

        fn get_disassembler(isa: &TargetIsa) -> Result<Capstone, String> {
            let cs = match isa.triple().architecture {
                Architecture::Riscv32 | Architecture::Riscv64 => {
                    return Err(String::from("No disassembler for RiscV"))
                }
                Architecture::I386 | Architecture::I586 | Architecture::I686 => Capstone::new()
                    .x86()
                    .mode(arch::x86::ArchMode::Mode32)
                    .build(),
                Architecture::X86_64 => Capstone::new()
                    .x86()
                    .mode(arch::x86::ArchMode::Mode64)
                    .build(),
                Architecture::Arm
                | Architecture::Armv4t
                | Architecture::Armv5te
                | Architecture::Armv7
                | Architecture::Armv7s => Capstone::new().arm().mode(arch::arm::ArchMode::Arm).build(),
                Architecture::Thumbv6m | Architecture::Thumbv7em | Architecture::Thumbv7m => Capstone::new(
                ).arm()
                    .mode(arch::arm::ArchMode::Thumb)
                    .build(),
                Architecture::Aarch64 => Capstone::new()
                    .arm64()
                    .mode(arch::arm64::ArchMode::Arm)
                    .build(),
                _ => return Err(String::from("Unknown ISA")),
            };

            cs.map_err(|err| err.to_string())
        }

        pub fn print_disassembly(isa: &TargetIsa, mem: &[u8]) -> Result<(), String> {
            let mut cs = get_disassembler(isa)?;

            println!("\nDisassembly of {} bytes:", mem.len());
            let insns = cs.disasm_all(&mem, 0x0).unwrap();
            for i in insns.iter() {
                let mut line = String::new();

                write!(&mut line, "{:4x}:\t", i.address()).unwrap();

                let mut bytes_str = String::new();
                let mut len = 0;
                let mut first = true;
                for b in i.bytes() {
                    write!(&mut bytes_str, "{:02x}", b).unwrap();
                    if !first {
                        write!(&mut bytes_str, " ").unwrap();
                    }
                    len += 1;
                    first = false;
                }
                write!(&mut line, "{:21}\t", bytes_str).unwrap();
                if len > 8 {
                    write!(&mut line, "\n\t\t\t\t").unwrap();
                }

                if let Some(s) = i.mnemonic() {
                    write!(&mut line, "{}\t", s).unwrap();
                }

                if let Some(s) = i.op_str() {
                    write!(&mut line, "{}", s).unwrap();
                }

                println!("{}", line);
            }
            Ok(())
        }
    } else {
        pub fn print_disassembly(_: &TargetIsa, _: &[u8]) -> Result<(), String> {
            println!("\nNo disassembly available.");
            Ok(())
        }
    }
}

pub fn print_all(
    isa: &TargetIsa,
    mem: &[u8],
    code_size: u32,
    rodata_size: u32,
    relocs: &PrintRelocs,
    traps: &PrintTraps,
) -> Result<(), String> {
    print_bytes(&mem);
    print_disassembly(isa, &mem[0..code_size as usize])?;
    print_readonly_data(&mem[code_size as usize..(code_size + rodata_size) as usize]);
    println!("\n{}\n{}", &relocs.text, &traps.text);
    Ok(())
}

pub fn print_bytes(mem: &[u8]) {
    print!(".byte ");
    let mut first = true;
    for byte in mem.iter() {
        if first {
            first = false;
        } else {
            print!(", ");
        }
        print!("{}", byte);
    }
    println!();
}

pub fn print_readonly_data(mem: &[u8]) {
    if mem.is_empty() {
        return;
    }

    println!("\nFollowed by {} bytes of read-only data:", mem.len());

    for (i, byte) in mem.iter().enumerate() {
        if i % 16 == 0 {
            if i != 0 {
                println!();
            }
            print!("{:4}: ", i);
        }
        if i % 4 == 0 {
            print!(" ");
        }
        print!("{:02x} ", byte);
    }
    println!();
}
<commit_msg>Fix a disasm formatting error<commit_after>use cfg_if::cfg_if;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{binemit, ir};
use std::fmt::Write;

pub struct PrintRelocs {
    pub flag_print: bool,
    pub text: String,
}

impl PrintRelocs {
    pub fn new(flag_print: bool) -> PrintRelocs {
        Self {
            flag_print,
            text: String::new(),
        }
    }
}

impl binemit::RelocSink for PrintRelocs {
    fn reloc_ebb(
        &mut self,
        where_: binemit::CodeOffset,
        r: binemit::Reloc,
        offset: binemit::CodeOffset,
    ) {
        if self.flag_print {
            write!(
                &mut self.text,
                "reloc_ebb: {} {} at {}\n",
                r, offset, where_
            )
            .unwrap();
        }
    }

    fn reloc_external(
        &mut self,
        where_: binemit::CodeOffset,
        r: binemit::Reloc,
        name: &ir::ExternalName,
        addend: binemit::Addend,
    ) {
        if self.flag_print {
            write!(
                &mut self.text,
                "reloc_external: {} {} {} at {}\n",
                r, name, addend, where_
            )
            .unwrap();
        }
    }

    fn reloc_jt(&mut self, where_: binemit::CodeOffset, r: binemit::Reloc, jt: ir::JumpTable) {
        if self.flag_print {
            write!(&mut self.text, "reloc_jt: {} {} at {}\n", r, jt, where_).unwrap();
        }
    }
}

pub struct PrintTraps {
    pub flag_print: bool,
    pub text: String,
}

impl PrintTraps {
    pub fn new(flag_print: bool) -> PrintTraps {
        Self {
            flag_print,
            text: String::new(),
        }
    }
}

impl binemit::TrapSink for PrintTraps {
    fn trap(&mut self, offset: binemit::CodeOffset, _srcloc: ir::SourceLoc, code: ir::TrapCode) {
        if self.flag_print {
            write!(&mut self.text, "trap: {} at {}\n", code, offset).unwrap();
        }
    }
}

cfg_if! {
    if #[cfg(feature = "disas")] {
        use capstone::prelude::*;
        use target_lexicon::Architecture;

        fn get_disassembler(isa: &TargetIsa) -> Result<Capstone, String> {
            let cs = match isa.triple().architecture {
                Architecture::Riscv32 | Architecture::Riscv64 => {
                    return Err(String::from("No disassembler for RiscV"))
                }
                Architecture::I386 | Architecture::I586 | Architecture::I686 => Capstone::new()
                    .x86()
                    .mode(arch::x86::ArchMode::Mode32)
                    .build(),
                Architecture::X86_64 => Capstone::new()
                    .x86()
                    .mode(arch::x86::ArchMode::Mode64)
                    .build(),
                Architecture::Arm
                | Architecture::Armv4t
                | Architecture::Armv5te
                | Architecture::Armv7
                | Architecture::Armv7s => Capstone::new().arm().mode(arch::arm::ArchMode::Arm).build(),
                Architecture::Thumbv6m | Architecture::Thumbv7em | Architecture::Thumbv7m => Capstone::new(
                ).arm()
                    .mode(arch::arm::ArchMode::Thumb)
                    .build(),
                Architecture::Aarch64 => Capstone::new()
                    .arm64()
                    .mode(arch::arm64::ArchMode::Arm)
                    .build(),
                _ => return Err(String::from("Unknown ISA")),
            };

            cs.map_err(|err| err.to_string())
        }

        pub fn print_disassembly(isa: &TargetIsa, mem: &[u8]) -> Result<(), String> {
            let mut cs = get_disassembler(isa)?;

            println!("\nDisassembly of {} bytes:", mem.len());
            let insns = cs.disasm_all(&mem, 0x0).unwrap();
            for i in insns.iter() {
                let mut line = String::new();

                write!(&mut line, "{:4x}:\t", i.address()).unwrap();

                let mut bytes_str = String::new();
                let mut len = 0;
                let mut first = true;
                for b in i.bytes() {
                    if !first {
                        write!(&mut bytes_str, " ").unwrap();
                    }
                    write!(&mut bytes_str, "{:02x}", b).unwrap();
                    len += 1;
                    first = false;
                }
                write!(&mut line, "{:21}\t", bytes_str).unwrap();
                if len > 8 {
                    write!(&mut line, "\n\t\t\t\t").unwrap();
                }

                if let Some(s) = i.mnemonic() {
                    write!(&mut line, "{}\t", s).unwrap();
                }

                if let Some(s) = i.op_str() {
                    write!(&mut line, "{}", s).unwrap();
                }

                println!("{}", line);
            }
            Ok(())
        }
    } else {
        pub fn print_disassembly(_: &TargetIsa, _: &[u8]) -> Result<(), String> {
            println!("\nNo disassembly available.");
            Ok(())
        }
    }
}

pub fn print_all(
    isa: &TargetIsa,
    mem: &[u8],
    code_size: u32,
    rodata_size: u32,
    relocs: &PrintRelocs,
    traps: &PrintTraps,
) -> Result<(), String> {
    print_bytes(&mem);
    print_disassembly(isa, &mem[0..code_size as usize])?;
    print_readonly_data(&mem[code_size as usize..(code_size + rodata_size) as usize]);
    println!("\n{}\n{}", &relocs.text, &traps.text);
    Ok(())
}

pub fn print_bytes(mem: &[u8]) {
    print!(".byte ");
    let mut first = true;
    for byte in mem.iter() {
        if first {
            first = false;
        } else {
            print!(", ");
        }
        print!("{}", byte);
    }
    println!();
}

pub fn print_readonly_data(mem: &[u8]) {
    if mem.is_empty() {
        return;
    }

    println!("\nFollowed by {} bytes of read-only data:", mem.len());

    for (i, byte) in mem.iter().enumerate() {
        if i % 16 == 0 {
            if i != 0 {
                println!();
            }
            print!("{:4}: ", i);
        }
        if i % 4 == 0 {
            print!(" ");
        }
        print!("{:02x} ", byte);
    }
    println!();
}
<|endoftext|>


<commit_before>use ast;
use ast::Ast;
use ast::Function;
use ast::Elem::ElemFunction;

use error::ErrorCode;
use error::ParseError;

use parser::Parser;

use sym;
use sym::SymTable;
use sym::Sym::SymFunction;
use sym::SymFunctionType;

macro_rules! err {
    ( $errs: expr, $x: expr ) => {
        {
            match $x {
                Ok(val) => val,
                Err(_) => { return Err($errs); }
            }
        }
    };
}

// Only do semantic analysis until some amount of
// errors found
static max_errors: usize = 5;

pub struct SemCheck<'a> {
    ast: &'a Ast,
    errors: Vec<ParseError>,
}

impl<'a> SemCheck<'a> {
    pub fn new(ast: &Ast) -> SemCheck {
        SemCheck {
            ast: ast,
            errors: Vec::new(),
        }
    }

    pub fn check(mut self) -> Result<SymTable, Vec<ParseError>> {
        let mut globals = SymTable::new();

        for elem in &self.ast.elements {
            match *elem {
                ElemFunction(ref fct) => {
                    err!(self.errors, self.add_function_header(&mut globals, fct));
                }

                _ => unreachable!()
            }
        }

        for fct in globals.functions_mut() {
            err!(self.errors, self.check_function_body(fct));
        }

        if self.errors.len() == 0 {
            Ok(globals)
        } else {
            Err(self.errors)
        }
    }

    fn add_function_header(&mut self, globals: &mut SymTable, fct: &Function) -> Result<(), ()> {
        let params = fct.params.iter().map(|p| param_header(p));
        let symfct = SymFunction(SymFunctionType {
            name: fct.name,
            return_type: fct.return_type.builtin,
            params: params.collect(),
            body: fct.block.id()
        });

        if let Err(_) = globals.insert(fct.name, symfct) {
            try!(self.error(ParseError {
                code: ErrorCode::IdentifierAlreadyExists,
                message: format!("identifier {} already exists", self.ast.str(fct.name)),
                position: fct.pos
            }));
        }

        Ok(())
    }

    fn check_function_body(&mut self, fct: &SymFunctionType) -> Result<(), ()> {
        Ok(())
    }

    fn error(&mut self, error: ParseError) -> Result<(), ()> {
        self.errors.push(error);

        if self.errors.len() <= max_errors {
            Ok(())
        } else {
            Err(())
        }
    }

    fn check_function(&mut self, fct: &Function) {
        println!("check_function");
    }
}

fn param_header(param: &ast::Param) -> sym::Param {
    sym::Param {
        name: param.name,
        data_type: param.data_type.builtin
    }
}

#[test]
fn test_empty_file() {
    let prog = Parser::from_str("").parse().unwrap();

    SemCheck::new(&prog).check().unwrap();
}

#[test]
fn test_function_multiple_times() {
    let prog = Parser::from_str("fn main() {} fn main() {}").parse().unwrap();
    let errors = SemCheck::new(&prog).check().unwrap_err();

    assert_eq!(1, errors.len());
    assert_eq!(ErrorCode::IdentifierAlreadyExists, errors[0].code);
}

<commit_msg>semck: split check function<commit_after>use ast;
use ast::Ast;
use ast::Function;
use ast::Elem::ElemFunction;

use error::ErrorCode;
use error::ParseError;

use parser::Parser;

use sym;
use sym::SymTable;
use sym::Sym::SymFunction;
use sym::SymFunctionType;

macro_rules! err {
    ( $errs: expr, $x: expr ) => {
        {
            match $x {
                Ok(val) => val,
                Err(_) => { return Err($errs); }
            }
        }
    };
}

// Only do semantic analysis until some amount of
// errors found
static max_errors: usize = 5;

pub struct SemCheck<'a> {
    ast: &'a Ast,
    errors: Vec<ParseError>,
}

impl<'a> SemCheck<'a> {
    pub fn new(ast: &Ast) -> SemCheck {
        SemCheck {
            ast: ast,
            errors: Vec::new(),
        }
    }

    pub fn check(mut self) -> Result<SymTable, Vec<ParseError>> {
        let mut globals = SymTable::new();

        err!(self.errors, self.parse_function_headers(&mut globals));
        err!(self.errors, self.parse_function_bodies(&mut globals));

        if self.errors.len() == 0 {
            Ok(globals)
        } else {
            Err(self.errors)
        }
    }

    fn parse_function_headers(&mut self, globals: &mut SymTable) -> Result<(), ()> {
        for elem in &self.ast.elements {
            match *elem {
                ElemFunction(ref fct) => {
                    try!(self.add_function_header(globals, fct));
                }

                _ => unreachable!()
            }
        }

        Ok(())
    }

    fn parse_function_bodies(&mut self, globals: &mut SymTable) -> Result<(), ()> {
        for fct in globals.functions_mut() {
            try!(self.check_function_body(fct));
        }

        Ok(())
    }

    fn add_function_header(&mut self, globals: &mut SymTable, fct: &Function) -> Result<(), ()> {
        let params = fct.params.iter().map(|p| param_header(p));
        let symfct = SymFunction(SymFunctionType {
            name: fct.name,
            return_type: fct.return_type.builtin,
            params: params.collect(),
            body: fct.block.id()
        });

        if let Err(_) = globals.insert(fct.name, symfct) {
            try!(self.error(ParseError {
                code: ErrorCode::IdentifierAlreadyExists,
                message: format!("identifier {} already exists", self.ast.str(fct.name)),
                position: fct.pos
            }));
        }

        Ok(())
    }

    fn check_function_body(&mut self, fct: &SymFunctionType) -> Result<(), ()> {
        Ok(())
    }

    fn error(&mut self, error: ParseError) -> Result<(), ()> {
        self.errors.push(error);

        if self.errors.len() <= max_errors {
            Ok(())
        } else {
            Err(())
        }
    }

    fn check_function(&mut self, fct: &Function) {
        println!("check_function");
    }
}

fn param_header(param: &ast::Param) -> sym::Param {
    sym::Param {
        name: param.name,
        data_type: param.data_type.builtin
    }
}

#[test]
fn test_empty_file() {
    let prog = Parser::from_str("").parse().unwrap();

    SemCheck::new(&prog).check().unwrap();
}

#[test]
fn test_function_multiple_times() {
    let prog = Parser::from_str("fn main() {} fn main() {}").parse().unwrap();
    let errors = SemCheck::new(&prog).check().unwrap_err();

    assert_eq!(1, errors.len());
    assert_eq!(ErrorCode::IdentifierAlreadyExists, errors[0].code);
}

<|endoftext|>


<commit_before>use ast;
use ast::Ast;
use ast::Function;
use ast::Elem::ElemFunction;

use error::ErrorCode;
use error::ParseError;

use interner::Interner;

use parser::Parser;

use sym;
use sym::SymTable;
use sym::Sym::SymFunction;
use sym::SymFunctionType;

macro_rules! err {
    ( $errs: expr, $x: expr ) => {
        {
            match $x {
                Ok(val) => val,
                Err(_) => { return Err($errs); }
            }
        }
    };
}

// Only do semantic analysis until some amount of
// errors found
static MAX_ERRORS: usize = 5;

pub struct SemCheck<'a> {
    ast: &'a Ast,
    interner: &'a mut Interner,
    errors: Vec<ParseError>,
}

impl<'a> SemCheck<'a> {
    pub fn new<'b>(ast: &'b Ast, interner: &'b mut Interner) -> SemCheck<'b> {
        SemCheck {
            ast: ast,
            interner: interner,
            errors: Vec::new(),
        }
    }

    pub fn check(mut self) -> Result<SymTable, Vec<ParseError>> {
        let mut globals = SymTable::new();

        add_predefined_types(&mut globals);
        add_predefined_functions(&mut globals);

        err!(self.errors, self.parse_function_headers(&mut globals));
        err!(self.errors, self.parse_function_bodies(&mut globals));

        if self.errors.is_empty() {
            Ok(globals)
        } else {
            Err(self.errors)
        }
    }

    fn parse_function_headers(&mut self, globals: &mut SymTable) -> Result<(), ()> {
        for elem in &self.ast.elements {
            match *elem {
                ElemFunction(ref fct) => {
                    try!(self.add_function_header(globals, fct));
                }

                _ => unreachable!()
            }
        }

        Ok(())
    }

    fn parse_function_bodies(&mut self, globals: &mut SymTable) -> Result<(), ()> {
        for fct in globals.functions_mut() {
            try!(self.check_function_body(fct));
        }

        Ok(())
    }

    fn add_function_header(&mut self, globals: &mut SymTable, fct: &Function) -> Result<(), ()> {
        let params = fct.params.iter().map(|p| param_header(p));
        let symfct = SymFunction(SymFunctionType {
            name: fct.name,
            return_type: fct.return_type.builtin,
            params: params.collect(),
            body: fct.block.id()
        });

        if let Err(_) = globals.insert(fct.name, symfct) {
            let message = format!("identifier {} already exists", self.interner.str(fct.name));

            try!(self.error(ParseError {
                code: ErrorCode::IdentifierAlreadyExists,
                message: message,
                position: fct.pos
            }));
        }

        Ok(())
    }

    fn check_function_body(&mut self, fct: &SymFunctionType) -> Result<(), ()> {
        Ok(())
    }

    fn error(&mut self, error: ParseError) -> Result<(), ()> {
        self.errors.push(error);

        if self.errors.len() <= MAX_ERRORS {
            Ok(())
        } else {
            Err(())
        }
    }

    fn check_function(&mut self, fct: &Function) {
        println!("check_function");
    }
}

fn add_predefined_types(globals: &mut SymTable) {
    // TODO: add bool, int and str for now
}

fn add_predefined_functions(globals: &mut SymTable) {
    // TODO: add print(str), print_int(int)
}

fn param_header(param: &ast::Param) -> sym::Param {
    sym::Param {
        name: param.name,
        data_type: param.data_type.builtin
    }
}

#[test]
fn test_empty_file() {
    let (prog, mut interner) = Parser::from_str("").parse().unwrap();

    SemCheck::new(&prog, &mut interner).check().unwrap();
}

#[test]
fn test_function_multiple_times() {
    let (prog, mut interner) = Parser::from_str("fn main() {} fn main() {}").parse().unwrap();
    let errors = SemCheck::new(&prog, &mut interner).check().unwrap_err();

    assert_eq!(1, errors.len());
    assert_eq!(ErrorCode::IdentifierAlreadyExists, errors[0].code);
}

<commit_msg>semck: pass interner to functions<commit_after>use ast;
use ast::Ast;
use ast::Function;
use ast::Elem::ElemFunction;

use error::ErrorCode;
use error::ParseError;

use interner::Interner;

use parser::Parser;

use sym;
use sym::SymTable;
use sym::Sym::SymFunction;
use sym::SymFunctionType;

macro_rules! err {
    ( $errs: expr, $x: expr ) => {
        {
            match $x {
                Ok(val) => val,
                Err(_) => { return Err($errs); }
            }
        }
    };
}

// Only do semantic analysis until some amount of
// errors found
static MAX_ERRORS: usize = 5;

pub struct SemCheck<'a> {
    ast: &'a Ast,
    interner: &'a mut Interner,
    errors: Vec<ParseError>,
}

impl<'a> SemCheck<'a> {
    pub fn new<'b>(ast: &'b Ast, interner: &'b mut Interner) -> SemCheck<'b> {
        SemCheck {
            ast: ast,
            interner: interner,
            errors: Vec::new(),
        }
    }

    pub fn check(mut self) -> Result<SymTable, Vec<ParseError>> {
        let mut globals = SymTable::new();

        add_predefined_types(self.interner, &mut globals);
        add_predefined_functions(self.interner, &mut globals);

        err!(self.errors, self.parse_function_headers(&mut globals));
        err!(self.errors, self.parse_function_bodies(&mut globals));

        if self.errors.is_empty() {
            Ok(globals)
        } else {
            Err(self.errors)
        }
    }

    fn parse_function_headers(&mut self, globals: &mut SymTable) -> Result<(), ()> {
        for elem in &self.ast.elements {
            match *elem {
                ElemFunction(ref fct) => {
                    try!(self.add_function_header(globals, fct));
                }

                _ => unreachable!()
            }
        }

        Ok(())
    }

    fn parse_function_bodies(&mut self, globals: &mut SymTable) -> Result<(), ()> {
        for fct in globals.functions_mut() {
            try!(self.check_function_body(fct));
        }

        Ok(())
    }

    fn add_function_header(&mut self, globals: &mut SymTable, fct: &Function) -> Result<(), ()> {
        let params = fct.params.iter().map(|p| param_header(p));
        let symfct = SymFunction(SymFunctionType {
            name: fct.name,
            return_type: fct.return_type.builtin,
            params: params.collect(),
            body: fct.block.id()
        });

        if let Err(_) = globals.insert(fct.name, symfct) {
            let message = format!("identifier {} already exists", self.interner.str(fct.name));

            try!(self.error(ParseError {
                code: ErrorCode::IdentifierAlreadyExists,
                message: message,
                position: fct.pos
            }));
        }

        Ok(())
    }

    fn check_function_body(&mut self, fct: &SymFunctionType) -> Result<(), ()> {
        Ok(())
    }

    fn error(&mut self, error: ParseError) -> Result<(), ()> {
        self.errors.push(error);

        if self.errors.len() <= MAX_ERRORS {
            Ok(())
        } else {
            Err(())
        }
    }

    fn check_function(&mut self, fct: &Function) {
        println!("check_function");
    }
}

fn add_predefined_types(interner: &mut Interner, globals: &mut SymTable) {
    // TODO: add bool, int and str for now
}

fn add_predefined_functions(interner: &mut Interner, globals: &mut SymTable) {
    // TODO: add print(str), print_int(int)
}

fn param_header(param: &ast::Param) -> sym::Param {
    sym::Param {
        name: param.name,
        data_type: param.data_type.builtin
    }
}

#[test]
fn test_empty_file() {
    let (prog, mut interner) = Parser::from_str("").parse().unwrap();

    SemCheck::new(&prog, &mut interner).check().unwrap();
}

#[test]
fn test_function_multiple_times() {
    let (prog, mut interner) = Parser::from_str("fn main() {} fn main() {}").parse().unwrap();
    let errors = SemCheck::new(&prog, &mut interner).check().unwrap_err();

    assert_eq!(1, errors.len());
    assert_eq!(ErrorCode::IdentifierAlreadyExists, errors[0].code);
}

<|endoftext|>


<commit_before>use std::cmp::{Ord, Ordering, PartialOrd};
use std::fmt;

use ctxt::SemContext;
use driver::cmd::{Args, CollectorName};
use gc::copy::CopyCollector;
use gc::swiper::Swiper;
use gc::space::{Space, SpaceConfig};
use gc::zero::ZeroCollector;

pub mod arena;
pub mod chunk;
pub mod copy;
pub mod root;
pub mod space;
pub mod swiper;
pub mod zero;

const INITIAL_SIZE: usize = 64 * 1024;
const LARGE_OBJECT_SIZE: usize = 64 * 1024;

const CHUNK_SIZE: usize = 8 * 1024;
const CODE_SPACE_LIMIT: usize = 128 * 1024;
const PERM_SPACE_LIMIT: usize = 64 * 1024;

pub struct Gc {
    collector: Box<Collector>,

    code_space: Space,
    perm_space: Space,
}

impl Gc {
    pub fn new(args: &Args) -> Gc {
        let code_config = SpaceConfig {
            executable: true,
            chunk: CHUNK_SIZE,
            limit: CODE_SPACE_LIMIT,
            align: 64,
        };

        let perm_config = SpaceConfig {
            executable: false,
            chunk: CHUNK_SIZE,
            limit: PERM_SPACE_LIMIT,
            align: 8,
        };

        let collector_name = args.flag_gc.unwrap_or(CollectorName::Copy);

        let collector: Box<Collector> = match collector_name {
            CollectorName::Zero => box ZeroCollector::new(args),
            CollectorName::Copy => box CopyCollector::new(args),
            CollectorName::Swiper => box Swiper::new(args),
        };

        Gc {
            collector: collector,

            code_space: Space::new(code_config, "code"),
            perm_space: Space::new(perm_config, "perm"),
        }
    }

    pub fn needs_write_barrier(&self) -> bool {
        self.collector.needs_write_barrier()
    }

    pub fn card_table_offset(&self) -> usize {
        self.collector.card_table_offset()
    }

    pub fn alloc_code(&self, size: usize) -> *mut u8 {
        self.code_space.alloc(size)
    }

    pub fn alloc_perm(&self, size: usize) -> *mut u8 {
        self.perm_space.alloc(size)
    }

    pub fn alloc_obj(&self, ctxt: &SemContext, size: usize) -> *const u8 {
        self.collector.alloc_obj(ctxt, size)
    }

    pub fn alloc_array(
        &self,
        ctxt: &SemContext,
        elements: usize,
        element_size: usize,
        is_ref: bool,
    ) -> *const u8 {
        self.collector.alloc_array(
            ctxt,
            elements,
            element_size,
            is_ref,
        )
    }

    pub fn collect(&self, ctxt: &SemContext) {
        self.collector.collect(ctxt);
    }
}

trait Collector {
    // allocate object of given size
    fn alloc_obj(&self, ctxt: &SemContext, size: usize) -> *const u8;

    // allocate array with a certain number of elements
    fn alloc_array(
        &self,
        ctxt: &SemContext,
        elements: usize,
        element_size: usize,
        is_ref: bool,
    ) -> *const u8;

    fn collect(&self, ctxt: &SemContext);

    // decides whether to emit write barriers needed for
    // generational GC to write into card table
    fn needs_write_barrier(&self) -> bool {
        false
    }

    // only need if write barriers needed
    fn card_table_offset(&self) -> usize {
        0
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Address(usize);

impl Address {
    #[inline(always)]
    pub fn from(val: usize) -> Address {
        Address(val)
    }

    #[inline(always)]
    pub fn offset_from(self, base: Address) -> usize {
        debug_assert!(self >= base);

        self.to_usize() - base.to_usize()
    }

    #[inline(always)]
    pub fn offset(self, offset: usize) -> Address {
        Address(self.0 + offset)
    }

    #[inline(always)]
    pub fn to_usize(self) -> usize {
        self.0
    }

    #[inline(always)]
    pub fn from_ptr<T>(ptr: *const T) -> Address {
        Address(ptr as usize)
    }

    #[inline(always)]
    pub fn to_ptr<T>(&self) -> *const T {
        self.0 as *const T
    }

    #[inline(always)]
    pub fn to_mut_ptr<T>(&self) -> *mut T {
        self.0 as *const T as *mut T
    }

    #[inline(always)]
    pub fn null() -> Address {
        Address(0)
    }

    #[inline(always)]
    pub fn is_null(self) -> bool {
        self.0 == 0
    }
}

impl fmt::Display for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:x}", self.to_usize())
    }
}

impl PartialOrd for Address {
    fn partial_cmp(&self, other: &Address) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Address {
    fn cmp(&self, other: &Address) -> Ordering {
        self.to_usize().cmp(&other.to_usize())
    }
}

impl From<usize> for Address {
    fn from(val: usize) -> Address {
        Address(val)
    }
}
<commit_msg>use swiper as default GC<commit_after>use std::cmp::{Ord, Ordering, PartialOrd};
use std::fmt;

use ctxt::SemContext;
use driver::cmd::{Args, CollectorName};
use gc::copy::CopyCollector;
use gc::swiper::Swiper;
use gc::space::{Space, SpaceConfig};
use gc::zero::ZeroCollector;

pub mod arena;
pub mod chunk;
pub mod copy;
pub mod root;
pub mod space;
pub mod swiper;
pub mod zero;

const INITIAL_SIZE: usize = 64 * 1024;
const LARGE_OBJECT_SIZE: usize = 64 * 1024;

const CHUNK_SIZE: usize = 8 * 1024;
const CODE_SPACE_LIMIT: usize = 128 * 1024;
const PERM_SPACE_LIMIT: usize = 64 * 1024;

pub struct Gc {
    collector: Box<Collector>,

    code_space: Space,
    perm_space: Space,
}

impl Gc {
    pub fn new(args: &Args) -> Gc {
        let code_config = SpaceConfig {
            executable: true,
            chunk: CHUNK_SIZE,
            limit: CODE_SPACE_LIMIT,
            align: 64,
        };

        let perm_config = SpaceConfig {
            executable: false,
            chunk: CHUNK_SIZE,
            limit: PERM_SPACE_LIMIT,
            align: 8,
        };

        let collector_name = args.flag_gc.unwrap_or(CollectorName::Swiper);

        let collector: Box<Collector> = match collector_name {
            CollectorName::Zero => box ZeroCollector::new(args),
            CollectorName::Copy => box CopyCollector::new(args),
            CollectorName::Swiper => box Swiper::new(args),
        };

        Gc {
            collector: collector,

            code_space: Space::new(code_config, "code"),
            perm_space: Space::new(perm_config, "perm"),
        }
    }

    pub fn needs_write_barrier(&self) -> bool {
        self.collector.needs_write_barrier()
    }

    pub fn card_table_offset(&self) -> usize {
        self.collector.card_table_offset()
    }

    pub fn alloc_code(&self, size: usize) -> *mut u8 {
        self.code_space.alloc(size)
    }

    pub fn alloc_perm(&self, size: usize) -> *mut u8 {
        self.perm_space.alloc(size)
    }

    pub fn alloc_obj(&self, ctxt: &SemContext, size: usize) -> *const u8 {
        self.collector.alloc_obj(ctxt, size)
    }

    pub fn alloc_array(
        &self,
        ctxt: &SemContext,
        elements: usize,
        element_size: usize,
        is_ref: bool,
    ) -> *const u8 {
        self.collector.alloc_array(
            ctxt,
            elements,
            element_size,
            is_ref,
        )
    }

    pub fn collect(&self, ctxt: &SemContext) {
        self.collector.collect(ctxt);
    }
}

trait Collector {
    // allocate object of given size
    fn alloc_obj(&self, ctxt: &SemContext, size: usize) -> *const u8;

    // allocate array with a certain number of elements
    fn alloc_array(
        &self,
        ctxt: &SemContext,
        elements: usize,
        element_size: usize,
        is_ref: bool,
    ) -> *const u8;

    fn collect(&self, ctxt: &SemContext);

    // decides whether to emit write barriers needed for
    // generational GC to write into card table
    fn needs_write_barrier(&self) -> bool {
        false
    }

    // only need if write barriers needed
    fn card_table_offset(&self) -> usize {
        0
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Address(usize);

impl Address {
    #[inline(always)]
    pub fn from(val: usize) -> Address {
        Address(val)
    }

    #[inline(always)]
    pub fn offset_from(self, base: Address) -> usize {
        debug_assert!(self >= base);

        self.to_usize() - base.to_usize()
    }

    #[inline(always)]
    pub fn offset(self, offset: usize) -> Address {
        Address(self.0 + offset)
    }

    #[inline(always)]
    pub fn to_usize(self) -> usize {
        self.0
    }

    #[inline(always)]
    pub fn from_ptr<T>(ptr: *const T) -> Address {
        Address(ptr as usize)
    }

    #[inline(always)]
    pub fn to_ptr<T>(&self) -> *const T {
        self.0 as *const T
    }

    #[inline(always)]
    pub fn to_mut_ptr<T>(&self) -> *mut T {
        self.0 as *const T as *mut T
    }

    #[inline(always)]
    pub fn null() -> Address {
        Address(0)
    }

    #[inline(always)]
    pub fn is_null(self) -> bool {
        self.0 == 0
    }
}

impl fmt::Display for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:x}", self.to_usize())
    }
}

impl PartialOrd for Address {
    fn partial_cmp(&self, other: &Address) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Address {
    fn cmp(&self, other: &Address) -> Ordering {
        self.to_usize().cmp(&other.to_usize())
    }
}

impl From<usize> for Address {
    fn from(val: usize) -> Address {
        Address(val)
    }
}
<|endoftext|>


<commit_before>mod debugger_command;
mod http_handlers;
mod breakpoint_map;
mod cpu_snapshot;

use asm6502::{Instruction, InstructionDecoder};
use chan::{self, Receiver, Sender};
use cpu::Cpu;
use cpu::byte_utils::from_lo_hi;
use cpu::debugger::breakpoint_map::BreakpointMap;
use cpu::debugger::cpu_snapshot::{CpuSnapshot, MemorySnapshot};
use cpu::debugger::debugger_command::{BreakReason, DebuggerCommand};
use cpu::debugger::http_handlers::*;
use errors::*;
use iron::prelude::*;
use memory::{ADDRESSABLE_MEMORY, Memory};
use router::Router;
use serde_json;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;
use websocket::{Message as WsMessage, Server as WsServer};

const DEBUGGER_HTTP_ADDR: &'static str = "127.0.0.1:9975";
const DEBUGGER_WS_ADDR: &'static str = "127.0.0.1:9976";

#[derive(Eq, PartialEq)]
pub enum InterruptHandler {
    None,
    Irq,
    Nmi,
}

pub struct HttpDebugger<Mem: Memory> {
    ws_tx: Sender<DebuggerCommand>,
    ws_rx: Receiver<DebuggerCommand>,
    cpu: Cpu<Mem>,
    breakpoints: Arc<Mutex<BreakpointMap>>,
    cpu_thread_handle: thread::Thread,
    cpu_paused: Arc<AtomicBool>,
    break_on_nmi: Arc<AtomicBool>,
    last_pc: u16,
    last_mem_hash: u64,
    instructions: Arc<Vec<Instruction>>, // TODO: https://github.com/bgourlie/rs-nes/issues/9
}

impl<Mem: Memory> HttpDebugger<Mem> {
    pub fn new(cpu: Cpu<Mem>) -> Self {
        let mut buf = Vec::new();
        cpu.memory.dump(&mut buf);
        let instructions = InstructionDecoder::new(&buf, cpu.registers.pc).collect();
        let (ws_sender, ws_receiver) = chan::sync(0);
        HttpDebugger {
            ws_tx: ws_sender,
            ws_rx: ws_receiver,
            cpu: cpu,
            breakpoints: Arc::new(Mutex::new(BreakpointMap::new())),
            cpu_thread_handle: thread::current(),
            cpu_paused: Arc::new(AtomicBool::new(true)),
            break_on_nmi: Arc::new(AtomicBool::new(false)),
            last_pc: 0,
            last_mem_hash: 0,
            instructions: Arc::new(instructions),
        }
    }

    pub fn start(&mut self) -> Result<()> {
        self.start_http_server_thread()?;
        self.start_websocket_thread()?;
        Ok(())
    }

    pub fn step(&mut self) -> Result<()> {
        if let Some(break_reason) = self.break_reason() {
            {
                let snapshot = self.cpu_snapshot();
                self.ws_tx.send(DebuggerCommand::Break(break_reason, snapshot));
            }
            thread::park();
        }
        self.last_pc = self.cpu.registers.pc;
        let result = self.cpu.step();

        if let Err(Error(ErrorKind::Crash(ref reason), _)) = result {
            let snapshot = self.cpu_snapshot();
            self.ws_tx.send(DebuggerCommand::Crash(reason.clone(), snapshot));

            // Give the web socket thread enough time to send the Crash message
            thread::sleep(Duration::from_millis(100));
        }

        result
    }

    fn break_reason(&self) -> Option<BreakReason> {
        if self.interrupt_handler() == InterruptHandler::Nmi &&
           self.break_on_nmi.load(Ordering::Relaxed) {
            debug!("Break on NMI. CPU thread paused.");
            Some(BreakReason::Nmi)
        } else if self.last_pc == self.cpu.registers.pc {
            debug!("Trap detected @ {:0>4X}. CPU thread paused.",
                   self.cpu.registers.pc);
            Some(BreakReason::Trap)
        } else if self.at_breakpoint(self.cpu.registers.pc) {
            debug!("Breakpoint hit @ {:0>4X}. CPU thread paused.",
                   self.cpu.registers.pc);
            Some(BreakReason::Breakpoint)
        } else if self.cpu_paused.load(Ordering::Relaxed) {
            // Stepping deliberately takes the least precedence when determining the break reason
            debug!("Stepping @ {:0>4X}. CPU thread paused.",
                   self.cpu.registers.pc);
            Some(BreakReason::Step)
        } else {
            None
        }
    }

    fn cpu_snapshot(&mut self) -> CpuSnapshot {
        let hash = self.cpu.memory.hash();
        let mem_snapshot = if hash != self.last_mem_hash {
            debug!("Memory altered");
            let mut buf = Vec::with_capacity(ADDRESSABLE_MEMORY);
            self.cpu.memory.dump(&mut buf);
            self.last_mem_hash = hash;
            MemorySnapshot::Updated(hash, buf)
        } else {
            MemorySnapshot::NoChange(hash)
        };

        CpuSnapshot::new(mem_snapshot, self.cpu.registers.clone(), self.cpu.cycles)
    }

    fn start_websocket_thread(&mut self) -> Result<()> {
        info!("Starting web socket server at {}", DEBUGGER_WS_ADDR);
        let mut ws_server = WsServer::bind(DEBUGGER_WS_ADDR).map_err(|e| e.to_string())?;
        info!("Waiting for debugger to attach");
        let connection = ws_server.accept();
        info!("Debugger attached!");
        let ws_rx = self.ws_rx.clone();
        thread::spawn(move || {
            let request = connection.unwrap().read_request().unwrap();
            request.validate().unwrap();
            let response = request.accept();
            let mut sender = response.send().unwrap();

            while let Some(debugger_msg) = ws_rx.recv() {
                let message: WsMessage = WsMessage::text(serde_json::to_string(&debugger_msg)
                    .unwrap());

                if sender.send_message(&message).is_err() {
                    break;
                }
            }

            info!("Websocket thread is terminating!")
        });

        Ok(())
    }

    fn start_http_server_thread(&self) -> Result<()> {
        info!("Starting http debugger at {}", DEBUGGER_HTTP_ADDR);
        let cpu_thread = self.cpu_thread_handle.clone();
        let breakpoints = self.breakpoints.clone();
        let cpu_paused = self.cpu_paused.clone();
        let break_on_nmi = self.break_on_nmi.clone();
        let instructions = self.instructions.clone();

        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/step", StepHandler::new(cpu_thread.clone()), "step");
            router.get("/instructions",
                       InstructionHandler::new(instructions),
                       "instructions");
            router.get("/continue",
                       ContinueHandler::new(cpu_thread, cpu_paused),
                       "continue");
            router.get("/toggle_breakpoint/:addr",
                       ToggleBreakpointHandler::new(breakpoints),
                       "toggle_breakpoint");

            router.get("/toggle_break_on_nmi",
                       ToggleBreakOnNmiHandler::new(break_on_nmi),
                       "toggle_break_on_nmi");
            Iron::new(router).http(DEBUGGER_HTTP_ADDR).unwrap();
        });

        Ok(())
    }

    fn at_breakpoint(&self, pc: u16) -> bool {
        let breakpoints = &(*self.breakpoints.lock().unwrap());
        if breakpoints.is_set(pc) {
            self.cpu_paused.compare_and_swap(false, true, Ordering::Relaxed);
            true
        } else {
            false
        }
    }

    fn interrupt_handler(&self) -> InterruptHandler {
        if self.cpu.registers.pc == self.peek_mem(super::NMI_VECTOR) {
            InterruptHandler::Nmi
        } else if self.cpu.registers.pc == self.peek_mem(super::BREAK_VECTOR) {
            InterruptHandler::Irq
        } else {
            InterruptHandler::None
        }
    }

    fn peek_mem(&self, addr: u16) -> u16 {
        let low_byte = self.cpu.memory.read(addr).unwrap();
        let high_byte = self.cpu.memory.read(addr + 1).unwrap();
        from_lo_hi(low_byte, high_byte)
    }
}
<commit_msg>Fix stepping after NMI breakpoint<commit_after>mod debugger_command;
mod http_handlers;
mod breakpoint_map;
mod cpu_snapshot;

use asm6502::{Instruction, InstructionDecoder};
use chan::{self, Receiver, Sender};
use cpu::Cpu;
use cpu::byte_utils::from_lo_hi;
use cpu::debugger::breakpoint_map::BreakpointMap;
use cpu::debugger::cpu_snapshot::{CpuSnapshot, MemorySnapshot};
use cpu::debugger::debugger_command::{BreakReason, DebuggerCommand};
use cpu::debugger::http_handlers::*;
use errors::*;
use iron::prelude::*;
use memory::{ADDRESSABLE_MEMORY, Memory};
use router::Router;
use serde_json;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;
use websocket::{Message as WsMessage, Server as WsServer};

const DEBUGGER_HTTP_ADDR: &'static str = "127.0.0.1:9975";
const DEBUGGER_WS_ADDR: &'static str = "127.0.0.1:9976";

#[derive(Eq, PartialEq)]
pub enum InterruptHandler {
    None,
    Irq,
    Nmi,
}

pub struct HttpDebugger<Mem: Memory> {
    ws_tx: Sender<DebuggerCommand>,
    ws_rx: Receiver<DebuggerCommand>,
    cpu: Cpu<Mem>,
    breakpoints: Arc<Mutex<BreakpointMap>>,
    cpu_thread_handle: thread::Thread,
    cpu_paused: Arc<AtomicBool>,
    break_on_nmi: Arc<AtomicBool>,
    last_pc: u16,
    last_mem_hash: u64,
    instructions: Arc<Vec<Instruction>>, // TODO: https://github.com/bgourlie/rs-nes/issues/9
}

impl<Mem: Memory> HttpDebugger<Mem> {
    pub fn new(cpu: Cpu<Mem>) -> Self {
        let mut buf = Vec::new();
        cpu.memory.dump(&mut buf);
        let instructions = InstructionDecoder::new(&buf, cpu.registers.pc).collect();
        let (ws_sender, ws_receiver) = chan::sync(0);
        HttpDebugger {
            ws_tx: ws_sender,
            ws_rx: ws_receiver,
            cpu: cpu,
            breakpoints: Arc::new(Mutex::new(BreakpointMap::new())),
            cpu_thread_handle: thread::current(),
            cpu_paused: Arc::new(AtomicBool::new(true)),
            break_on_nmi: Arc::new(AtomicBool::new(false)),
            last_pc: 0,
            last_mem_hash: 0,
            instructions: Arc::new(instructions),
        }
    }

    pub fn start(&mut self) -> Result<()> {
        self.start_http_server_thread()?;
        self.start_websocket_thread()?;
        Ok(())
    }

    pub fn step(&mut self) -> Result<()> {
        if let Some(break_reason) = self.break_reason() {
            {
                let snapshot = self.cpu_snapshot();
                self.ws_tx.send(DebuggerCommand::Break(break_reason, snapshot));
            }
            thread::park();
        }
        self.last_pc = self.cpu.registers.pc;
        let result = self.cpu.step();

        if let Err(Error(ErrorKind::Crash(ref reason), _)) = result {
            let snapshot = self.cpu_snapshot();
            self.ws_tx.send(DebuggerCommand::Crash(reason.clone(), snapshot));

            // Give the web socket thread enough time to send the Crash message
            thread::sleep(Duration::from_millis(100));
        }

        result
    }

    fn break_reason(&self) -> Option<BreakReason> {
        if self.interrupt_handler() == InterruptHandler::Nmi &&
           self.break_on_nmi.load(Ordering::Relaxed) {
            debug!("Break on NMI. CPU thread paused.");
            self.cpu_paused.compare_and_swap(false, true, Ordering::Relaxed);
            Some(BreakReason::Nmi)
        } else if self.last_pc == self.cpu.registers.pc {
            debug!("Trap detected @ {:0>4X}. CPU thread paused.",
                   self.cpu.registers.pc);
            Some(BreakReason::Trap)
        } else if self.at_breakpoint(self.cpu.registers.pc) {
            debug!("Breakpoint hit @ {:0>4X}. CPU thread paused.",
                   self.cpu.registers.pc);
            Some(BreakReason::Breakpoint)
        } else if self.cpu_paused.load(Ordering::Relaxed) {
            // Stepping deliberately takes the least precedence when determining the break reason
            debug!("Stepping @ {:0>4X}. CPU thread paused.",
                   self.cpu.registers.pc);
            Some(BreakReason::Step)
        } else {
            None
        }
    }

    fn cpu_snapshot(&mut self) -> CpuSnapshot {
        let hash = self.cpu.memory.hash();
        let mem_snapshot = if hash != self.last_mem_hash {
            debug!("Memory altered");
            let mut buf = Vec::with_capacity(ADDRESSABLE_MEMORY);
            self.cpu.memory.dump(&mut buf);
            self.last_mem_hash = hash;
            MemorySnapshot::Updated(hash, buf)
        } else {
            MemorySnapshot::NoChange(hash)
        };

        CpuSnapshot::new(mem_snapshot, self.cpu.registers.clone(), self.cpu.cycles)
    }

    fn start_websocket_thread(&mut self) -> Result<()> {
        info!("Starting web socket server at {}", DEBUGGER_WS_ADDR);
        let mut ws_server = WsServer::bind(DEBUGGER_WS_ADDR).map_err(|e| e.to_string())?;
        info!("Waiting for debugger to attach");
        let connection = ws_server.accept();
        info!("Debugger attached!");
        let ws_rx = self.ws_rx.clone();
        thread::spawn(move || {
            let request = connection.unwrap().read_request().unwrap();
            request.validate().unwrap();
            let response = request.accept();
            let mut sender = response.send().unwrap();

            while let Some(debugger_msg) = ws_rx.recv() {
                let message: WsMessage = WsMessage::text(serde_json::to_string(&debugger_msg)
                    .unwrap());

                if sender.send_message(&message).is_err() {
                    break;
                }
            }

            info!("Websocket thread is terminating!")
        });

        Ok(())
    }

    fn start_http_server_thread(&self) -> Result<()> {
        info!("Starting http debugger at {}", DEBUGGER_HTTP_ADDR);
        let cpu_thread = self.cpu_thread_handle.clone();
        let breakpoints = self.breakpoints.clone();
        let cpu_paused = self.cpu_paused.clone();
        let break_on_nmi = self.break_on_nmi.clone();
        let instructions = self.instructions.clone();

        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/step", StepHandler::new(cpu_thread.clone()), "step");
            router.get("/instructions",
                       InstructionHandler::new(instructions),
                       "instructions");
            router.get("/continue",
                       ContinueHandler::new(cpu_thread, cpu_paused),
                       "continue");
            router.get("/toggle_breakpoint/:addr",
                       ToggleBreakpointHandler::new(breakpoints),
                       "toggle_breakpoint");

            router.get("/toggle_break_on_nmi",
                       ToggleBreakOnNmiHandler::new(break_on_nmi),
                       "toggle_break_on_nmi");
            Iron::new(router).http(DEBUGGER_HTTP_ADDR).unwrap();
        });

        Ok(())
    }

    fn at_breakpoint(&self, pc: u16) -> bool {
        let breakpoints = &(*self.breakpoints.lock().unwrap());
        if breakpoints.is_set(pc) {
            self.cpu_paused.compare_and_swap(false, true, Ordering::Relaxed);
            true
        } else {
            false
        }
    }

    fn interrupt_handler(&self) -> InterruptHandler {
        if self.cpu.registers.pc == self.peek_mem(super::NMI_VECTOR) {
            InterruptHandler::Nmi
        } else if self.cpu.registers.pc == self.peek_mem(super::BREAK_VECTOR) {
            InterruptHandler::Irq
        } else {
            InterruptHandler::None
        }
    }

    fn peek_mem(&self, addr: u16) -> u16 {
        let low_byte = self.cpu.memory.read(addr).unwrap();
        let high_byte = self.cpu.memory.read(addr + 1).unwrap();
        from_lo_hi(low_byte, high_byte)
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::mq_agent::{MqAgentClient, PubMessage};
use crate::node_manager::{BroadcastReq, GetPeerCountReq, NodesManagerClient, SingleTxReq};
use crate::synchronizer::{SynchronizerClient, SynchronizerMessage};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::routing_key;
use libproto::snapshot::{Cmd, Resp, SnapshotResp};
use libproto::{Message as ProtoMessage, OperateType, Response};
use libproto::{TryFrom, TryInto};
use logger::{error, info, trace, warn};
use pubsub::channel::{unbounded, Receiver, Sender};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

pub struct Network {
    is_pause: Arc<AtomicBool>,
    mq_client: MqAgentClient,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
    sync_client: SynchronizerClient,
    msg_receiver: Receiver<NetworkMessage>,
}

impl Network {
    pub fn new(
        mq_client: MqAgentClient,
        nodes_mgr_client: NodesManagerClient,
        sync_client: SynchronizerClient,
    ) -> Self {
        let (tx, rx) = unbounded();
        let client = NetworkClient { sender: tx };
        Network {
            is_pause: Arc::new(AtomicBool::new(false)),
            mq_client,
            network_client: client,
            nodes_mgr_client,
            sync_client,
            msg_receiver: rx,
        }
    }

    pub fn client(&self) -> NetworkClient {
        self.network_client.clone()
    }

    pub fn run(&mut self) {
        loop {
            if let Ok(msg) = self.msg_receiver.recv() {
                msg.handle(self);
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct NetworkClient {
    sender: Sender<NetworkMessage>,
}

impl NetworkClient {
    pub fn new(sender: Sender<NetworkMessage>) -> Self {
        NetworkClient { sender }
    }

    pub fn handle_local_message(&self, msg: LocalMessage) {
        self.send_message(NetworkMessage::LocalMessage(msg));
    }

    pub fn handle_remote_message(&self, msg: RemoteMessage) {
        self.send_message(NetworkMessage::RemoteMessage(msg));
    }

    fn send_message(&self, msg: NetworkMessage) {
        self.sender.try_send(msg).unwrap_or_else(|err| {
            warn!("[Network] Send message to network failed : {:?}", err);
        });
    }
}

pub enum NetworkMessage {
    LocalMessage(LocalMessage),
    RemoteMessage(RemoteMessage),
}

impl NetworkMessage {
    pub fn handle(self, service: &mut Network) {
        match self {
            NetworkMessage::LocalMessage(msg) => msg.handle(service),
            NetworkMessage::RemoteMessage(msg) => msg.handle(service),
        }
    }
}
pub struct LocalMessage {
    key: String,
    data: Vec<u8>,
}

impl LocalMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        LocalMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Local/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Chain >> Status) => {
                service
                    .sync_client
                    .handle_local_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Chain >> SyncResponse) => {
                let msg = ProtoMessage::try_from(&self.data).unwrap();
                send_message(
                    &service.nodes_mgr_client,
                    routing_key!(Synchronizer >> SyncResponse).into(),
                    msg,
                );
            }
            routing_key!(Jsonrpc >> RequestNet) => {
                self.reply_rpc(&self.data, service);
            }
            routing_key!(Snapshot >> SnapshotReq) => {
                info!("[Network] Set disconnect and response");
                self.snapshot_req(&self.data, service);
            }
            _ => {
                error!("[Network] Unexpected key {} from Local", self.key);
            }
        }
    }

    fn reply_rpc(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();

        let req_opt = msg.take_request();
        {
            if let Some(mut req) = req_opt {
                // Get peer count and send back to JsonRpc from MQ
                if req.has_peercount() {
                    let mut response = Response::new();
                    response.set_request_id(req.take_request_id());

                    let (tx, rx) = unbounded();
                    service
                        .nodes_mgr_client
                        .get_peer_count(GetPeerCountReq::new(tx));

                    // Get peer count from rx channel
                    // FIXME: This is a block receive, double check about this
                    let peer_count = rx.recv().unwrap();
                    response.set_peercount(peer_count as u32);
                    let msg: ProtoMessage = response.into();
                    service.mq_client.send_peer_count(PubMessage::new(
                        routing_key!(Net >> Response).into(),
                        msg.try_into().unwrap(),
                    ));
                }
            } else {
                warn!("[Network] Receive unexpected rpc data");
            }
        }
    }

    fn snapshot_req(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();
        let req = msg.take_snapshot_req().unwrap();
        let mut resp = SnapshotResp::new();

        match req.cmd {
            Cmd::Snapshot => {
                info!("[Network] Snapshot receive cmd::Snapshot: {:?}", req);
                resp.set_resp(Resp::SnapshotAck);
                resp.set_flag(true);
            }
            Cmd::Begin => {
                info!("[Network] Snapshot receive cmd::Begin: {:?}", req);
                service.is_pause.store(true, Ordering::SeqCst);
                resp.set_resp(Resp::BeginAck);
                resp.set_flag(true);
            }
            Cmd::Restore => {
                info!("[Network] Snapshot receive cmd::Restore: {:?}", req);
                resp.set_resp(Resp::RestoreAck);
                resp.set_flag(true);
            }
            Cmd::Clear => {
                info!("[Network] Snapshot receive cmd::Clear: {:?}", req);
                resp.set_resp(Resp::ClearAck);
                resp.set_flag(true);
            }
            Cmd::End => {
                info!("[Network] Snapshot receive cmd::End: {:?}", req);
                service.is_pause.store(false, Ordering::SeqCst);
                resp.set_resp(Resp::EndAck);
                resp.set_flag(true);
            }
        }

        let msg: ProtoMessage = resp.into();
        service.mq_client.send_snapshot_resp(PubMessage::new(
            routing_key!(Net >> SnapshotResp).into(),
            (&msg).try_into().unwrap(),
        ));
    }
}

pub struct RemoteMessage {
    key: String,
    data: Vec<u8>,
}

impl RemoteMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        RemoteMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Remote/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Synchronizer >> Status) => {
                service
                    .sync_client
                    .handle_remote_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                service
                    .sync_client
                    .handle_remote_response(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncRequest) => {
                service.mq_client.pub_sync_request(PubMessage::new(
                    routing_key!(Net >> SyncRequest).into(),
                    self.data,
                ));
            }
            routing_key!(Consensus >> CompactSignedProposal) => {
                let msg =
                    PubMessage::new(routing_key!(Net >> CompactSignedProposal).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Consensus >> RawBytes) => {
                let msg = PubMessage::new(routing_key!(Net >> RawBytes).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Auth >> Request) => {
                let msg = PubMessage::new(routing_key!(Net >> Request).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> GetBlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> GetBlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> BlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> BlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            _ => {
                error!("[Network] Unexpected key {} from Remote", self.key);
            }
        }
    }
}

pub fn send_message(nodes_mgr_client: &NodesManagerClient, key: String, msg: ProtoMessage) {
    let operate = msg.get_operate();

    match operate {
        OperateType::Broadcast => {
            nodes_mgr_client.broadcast(BroadcastReq::new(key, msg));
        }
        OperateType::Single => {
            let dst = msg.get_origin();
            nodes_mgr_client.send_message(SingleTxReq::new(dst as usize, key, msg));
        }
        OperateType::Subtract => {
            // FIXME: Support subtract broadcast if necessary.
            warn!("[MqAgent] Subtract broadcast does not support yet!");
        }
    }
}
<commit_msg>Use broadcast for subtract broadcast<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::mq_agent::{MqAgentClient, PubMessage};
use crate::node_manager::{BroadcastReq, GetPeerCountReq, NodesManagerClient, SingleTxReq};
use crate::synchronizer::{SynchronizerClient, SynchronizerMessage};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::routing_key;
use libproto::snapshot::{Cmd, Resp, SnapshotResp};
use libproto::{Message as ProtoMessage, OperateType, Response};
use libproto::{TryFrom, TryInto};
use logger::{error, info, trace, warn};
use pubsub::channel::{unbounded, Receiver, Sender};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

pub struct Network {
    is_pause: Arc<AtomicBool>,
    mq_client: MqAgentClient,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
    sync_client: SynchronizerClient,
    msg_receiver: Receiver<NetworkMessage>,
}

impl Network {
    pub fn new(
        mq_client: MqAgentClient,
        nodes_mgr_client: NodesManagerClient,
        sync_client: SynchronizerClient,
    ) -> Self {
        let (tx, rx) = unbounded();
        let client = NetworkClient { sender: tx };
        Network {
            is_pause: Arc::new(AtomicBool::new(false)),
            mq_client,
            network_client: client,
            nodes_mgr_client,
            sync_client,
            msg_receiver: rx,
        }
    }

    pub fn client(&self) -> NetworkClient {
        self.network_client.clone()
    }

    pub fn run(&mut self) {
        loop {
            if let Ok(msg) = self.msg_receiver.recv() {
                msg.handle(self);
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct NetworkClient {
    sender: Sender<NetworkMessage>,
}

impl NetworkClient {
    pub fn new(sender: Sender<NetworkMessage>) -> Self {
        NetworkClient { sender }
    }

    pub fn handle_local_message(&self, msg: LocalMessage) {
        self.send_message(NetworkMessage::LocalMessage(msg));
    }

    pub fn handle_remote_message(&self, msg: RemoteMessage) {
        self.send_message(NetworkMessage::RemoteMessage(msg));
    }

    fn send_message(&self, msg: NetworkMessage) {
        self.sender.try_send(msg).unwrap_or_else(|err| {
            warn!("[Network] Send message to network failed : {:?}", err);
        });
    }
}

pub enum NetworkMessage {
    LocalMessage(LocalMessage),
    RemoteMessage(RemoteMessage),
}

impl NetworkMessage {
    pub fn handle(self, service: &mut Network) {
        match self {
            NetworkMessage::LocalMessage(msg) => msg.handle(service),
            NetworkMessage::RemoteMessage(msg) => msg.handle(service),
        }
    }
}
pub struct LocalMessage {
    key: String,
    data: Vec<u8>,
}

impl LocalMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        LocalMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Local/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Chain >> Status) => {
                service
                    .sync_client
                    .handle_local_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Chain >> SyncResponse) => {
                let msg = ProtoMessage::try_from(&self.data).unwrap();
                send_message(
                    &service.nodes_mgr_client,
                    routing_key!(Synchronizer >> SyncResponse).into(),
                    msg,
                );
            }
            routing_key!(Jsonrpc >> RequestNet) => {
                self.reply_rpc(&self.data, service);
            }
            routing_key!(Snapshot >> SnapshotReq) => {
                info!("[Network] Set disconnect and response");
                self.snapshot_req(&self.data, service);
            }
            _ => {
                error!("[Network] Unexpected key {} from Local", self.key);
            }
        }
    }

    fn reply_rpc(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();

        let req_opt = msg.take_request();
        {
            if let Some(mut req) = req_opt {
                // Get peer count and send back to JsonRpc from MQ
                if req.has_peercount() {
                    let mut response = Response::new();
                    response.set_request_id(req.take_request_id());

                    let (tx, rx) = unbounded();
                    service
                        .nodes_mgr_client
                        .get_peer_count(GetPeerCountReq::new(tx));

                    // Get peer count from rx channel
                    // FIXME: This is a block receive, double check about this
                    let peer_count = rx.recv().unwrap();
                    response.set_peercount(peer_count as u32);
                    let msg: ProtoMessage = response.into();
                    service.mq_client.send_peer_count(PubMessage::new(
                        routing_key!(Net >> Response).into(),
                        msg.try_into().unwrap(),
                    ));
                }
            } else {
                warn!("[Network] Receive unexpected rpc data");
            }
        }
    }

    fn snapshot_req(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();
        let req = msg.take_snapshot_req().unwrap();
        let mut resp = SnapshotResp::new();

        match req.cmd {
            Cmd::Snapshot => {
                info!("[Network] Snapshot receive cmd::Snapshot: {:?}", req);
                resp.set_resp(Resp::SnapshotAck);
                resp.set_flag(true);
            }
            Cmd::Begin => {
                info!("[Network] Snapshot receive cmd::Begin: {:?}", req);
                service.is_pause.store(true, Ordering::SeqCst);
                resp.set_resp(Resp::BeginAck);
                resp.set_flag(true);
            }
            Cmd::Restore => {
                info!("[Network] Snapshot receive cmd::Restore: {:?}", req);
                resp.set_resp(Resp::RestoreAck);
                resp.set_flag(true);
            }
            Cmd::Clear => {
                info!("[Network] Snapshot receive cmd::Clear: {:?}", req);
                resp.set_resp(Resp::ClearAck);
                resp.set_flag(true);
            }
            Cmd::End => {
                info!("[Network] Snapshot receive cmd::End: {:?}", req);
                service.is_pause.store(false, Ordering::SeqCst);
                resp.set_resp(Resp::EndAck);
                resp.set_flag(true);
            }
        }

        let msg: ProtoMessage = resp.into();
        service.mq_client.send_snapshot_resp(PubMessage::new(
            routing_key!(Net >> SnapshotResp).into(),
            (&msg).try_into().unwrap(),
        ));
    }
}

pub struct RemoteMessage {
    key: String,
    data: Vec<u8>,
}

impl RemoteMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        RemoteMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Remote/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Synchronizer >> Status) => {
                service
                    .sync_client
                    .handle_remote_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                service
                    .sync_client
                    .handle_remote_response(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncRequest) => {
                service.mq_client.pub_sync_request(PubMessage::new(
                    routing_key!(Net >> SyncRequest).into(),
                    self.data,
                ));
            }
            routing_key!(Consensus >> CompactSignedProposal) => {
                let msg =
                    PubMessage::new(routing_key!(Net >> CompactSignedProposal).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Consensus >> RawBytes) => {
                let msg = PubMessage::new(routing_key!(Net >> RawBytes).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Auth >> Request) => {
                let msg = PubMessage::new(routing_key!(Net >> Request).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> GetBlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> GetBlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> BlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> BlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            _ => {
                error!("[Network] Unexpected key {} from Remote", self.key);
            }
        }
    }
}

pub fn send_message(nodes_mgr_client: &NodesManagerClient, key: String, msg: ProtoMessage) {
    let operate = msg.get_operate();

    match operate {
        OperateType::Broadcast => {
            nodes_mgr_client.broadcast(BroadcastReq::new(key, msg));
        }
        OperateType::Single => {
            let dst = msg.get_origin();
            nodes_mgr_client.send_message(SingleTxReq::new(dst as usize, key, msg));
        }
        OperateType::Subtract => {
            // FIXME: Support subtract broadcast if necessary, just use broadcast instead.
            warn!("[MqAgent] Subtract broadcast does not support yet, use broadcast instead!");
            nodes_mgr_client.broadcast(BroadcastReq::new(key, msg));
        }
    }
}
<|endoftext|>