<commit_before>use parser::{Expression, CallArgs, Identifier};
use memory::MemoryBlock;

use operations::{Error, OperationsResult};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{TypeId, ScopeStack, ScopeItem, FuncArgs};

/// Evaluates the arguments first, then supplies them to the given method
pub fn call_with_exprs(
    scope: &mut ScopeStack,
    method: Expression,
    arg_exprs: CallArgs,
    target_type: TypeId,
    target: MemoryBlock,
) -> OperationsResult {
    let (mut args, ops): (Vec<_>, Vec<_>) = arg_exprs.into_iter().map(|expr| match expr {
        Expression::ByteLiteral(bytes) => Ok((ScopeItem::ByteLiteral(bytes), Vec::new())),
        Expression::Number(bytes) => Ok((ScopeItem::NumericLiteral(bytes), Vec::new())),
        Expression::Identifier(name) => scope.lookup(&name).first().ok_or_else(|| {
            Error::UnresolvedName(name.clone())
        }).map(|item| ((**item).clone(), Vec::new())),
        Expression::Call {..} => unimplemented!(),
        Expression::Access {..} => unimplemented!(),
        Expression::Branch {..} => unimplemented!(),
    }).collect::<Result<Vec<_>, _>>()?.into_iter().unzip();

    let (target_instance, method_name): (Option<ScopeItem>, Identifier) = match method {
        Expression::Identifier(name) => (None, name),
        Expression::Access {target, field} => {
            let (target, method_name) = resolve_field_name(scope, *target, field)?;
            (Some(target), method_name)
        },
        // The grammar should prevent any other expressions from
        // ending up here
        //TODO: Instead of using unreachable here, maybe the type of method should not be expression
        _ => unreachable!(),
    };

    // If the method operates on some type, the instance of that type is the first argument
    if let Some(target_instance) = target_instance {
        args.insert(0, target_instance);
    }

    Ok(ops.into_iter().flat_map(|o| o.into_iter()).chain(
        call(scope, method_name, args, target_type, target)?
    ).collect())
}

/// Call the provided method with the given arguments
pub fn call(
    scope: &mut ScopeStack,
    method_name: Identifier,
    args: FuncArgs,
    target_type: TypeId,
    target: MemoryBlock,
) -> OperationsResult {
    // The first stage of calling a function is finding an implementation that matches the correct
    // function signature.
    let method_args_types = args.iter().map(|arg| match *arg {
        //TODO: Update this when more numeric types are added
        ScopeItem::NumericLiteral(..) => FuncArgType::Arg(scope.primitives().u8()),
        ScopeItem::ByteLiteral(..) => FuncArgType::Array {item: scope.primitives().u8(), size: None},
        ScopeItem::Array {item, ..} => FuncArgType::Array {item: item, size: None},
        ref arg => FuncArgType::Arg(arg.type_id()),
    }).collect();

    // TODO: Since we don't have proper generics, we just search through and try every function
    // with the given name to see if its arguments match. This is more similar to what C++ does
    // than Rust, but it works for the timebeing.
    // We keep searching until we find something that matches or we return the first error.
    scope.lookup(&method_name).into_iter().fold(Err(Error::UnresolvedName(method_name.clone())), |acc, item| acc.or_else(|err| match *item {
        ScopeItem::BuiltInFunction {type_id, ref operations} => {
            if scope.get_type(type_id).matches_signature(&method_args_types, target_type) {
                Ok(operations.clone())
            }
            else {
                Err(err)
            }
        },
        _ => Err(err),
    })).and_then(|operations| {
        unimplemented!();
    })
}

/// Returns the full path of the target type with the field appended to it
/// e.g. If target's type is `std::Foo` and field is `bar`, you get: `std::Foo::bar`
/// Also returns the target ScopeItem of this operation
/// Since this is a field access, it needs to operate on the target object that the `target`
/// expression refers to
fn resolve_field_name(scope: &ScopeStack, target: Expression, field: Identifier) -> Result<(ScopeItem, Identifier), Error> {
    // The full path of the target type
    // Something like `std::foo::Foo` or `u8` or `()`
    let (target_instance, target_type_path) = match target {
        Expression::Identifier(target_name) => scope.lookup(&target_name).first().ok_or_else(|| {
            Error::UnresolvedName(target_name.clone())
        }).and_then(|item| match **item {
            ScopeItem::Constant {type_id, ..} => Ok(((*item).clone(), type_id)),
            ScopeItem::TypedBlock {type_id, ..} => Ok(((*item).clone(), type_id)),
            ScopeItem::Array {..} => unimplemented!(),
            ScopeItem::BuiltInFunction {type_id, ..} => Err(Error::UnresolvedField {
                target_type: scope.get_type(type_id).clone(),
                field: field.clone(),
            }),
            // These are unreachable because numeric literals and byte literals are never stored
            // directly
            ScopeItem::NumericLiteral(..) | ScopeItem::ByteLiteral(..) => unreachable!(),
        }).map(|(item, type_id)| (item, scope.get_type_name(type_id).clone())),

        //TODO: It's likely that the below line will just not work at all
        // because the scope item returned in the tuple is not the target we should return.
        // I think we need to map on this result and return the field as the target...not sure.
        //Expression::Access {target, field} => resolve_field_name(scope, *target, field),
        Expression::Access {target, field} => unimplemented!(),

        //TODO: ByteLiterals are valid targets for field access
        // In this case, we need to return [u8; N] where N is the length of the byte literal
        // We also likely need to allocate and store this into a temporary variable
        Expression::ByteLiteral(..) => unimplemented!(),

        //TODO: Numbers are valid targets for field access
        // In this case, we need to return u8 or another valid type
        // We also likely need to allocate and store this into a temporary variable
        Expression::Number(..) => unimplemented!(),

        //TODO: Calls are valid targets for field access
        // In this case, we need to return the type name of the return type
        // Implementing this will be a bit more complicated since we need to do the call and return
        // the ops necessary for that
        Expression::Call {method, args} => unimplemented!(),
        Expression::Branch {..} => unreachable!(),
    }?;

    Ok((target_instance, target_type_path.concat(field)))
}
<commit_msg>Calling the produced operations function in call()<commit_after>use parser::{Expression, CallArgs, Identifier};
use memory::MemoryBlock;

use operations::{Error, OperationsResult};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{TypeId, ScopeStack, ScopeItem, FuncArgs};

/// Evaluates the arguments first, then supplies them to the given method
pub fn call_with_exprs(
    scope: &mut ScopeStack,
    method: Expression,
    arg_exprs: CallArgs,
    target_type: TypeId,
    target: MemoryBlock,
) -> OperationsResult {
    let (mut args, ops): (Vec<_>, Vec<_>) = arg_exprs.into_iter().map(|expr| match expr {
        Expression::ByteLiteral(bytes) => Ok((ScopeItem::ByteLiteral(bytes), Vec::new())),
        Expression::Number(bytes) => Ok((ScopeItem::NumericLiteral(bytes), Vec::new())),
        Expression::Identifier(name) => scope.lookup(&name).first().ok_or_else(|| {
            Error::UnresolvedName(name.clone())
        }).map(|item| ((**item).clone(), Vec::new())),
        Expression::Call {..} => unimplemented!(),
        Expression::Access {..} => unimplemented!(),
        Expression::Branch {..} => unimplemented!(),
    }).collect::<Result<Vec<_>, _>>()?.into_iter().unzip();

    let (target_instance, method_name): (Option<ScopeItem>, Identifier) = match method {
        Expression::Identifier(name) => (None, name),
        Expression::Access {target, field} => {
            let (target, method_name) = resolve_field_name(scope, *target, field)?;
            (Some(target), method_name)
        },
        // The grammar should prevent any other expressions from
        // ending up here
        //TODO: Instead of using unreachable here, maybe the type of method should not be expression
        _ => unreachable!(),
    };

    // If the method operates on some type, the instance of that type is the first argument
    if let Some(target_instance) = target_instance {
        args.insert(0, target_instance);
    }

    Ok(ops.into_iter().flat_map(|o| o.into_iter()).chain(
        call(scope, method_name, args, target_type, target)?
    ).collect())
}

/// Call the provided method with the given arguments
pub fn call(
    scope: &mut ScopeStack,
    method_name: Identifier,
    args: FuncArgs,
    target_type: TypeId,
    target: MemoryBlock,
) -> OperationsResult {
    // The first stage of calling a function is finding an implementation that matches the correct
    // function signature.
    let method_args_types = args.iter().map(|arg| match *arg {
        //TODO: Update this when more numeric types are added
        ScopeItem::NumericLiteral(..) => FuncArgType::Arg(scope.primitives().u8()),
        ScopeItem::ByteLiteral(..) => FuncArgType::Array {item: scope.primitives().u8(), size: None},
        ScopeItem::Array {item, ..} => FuncArgType::Array {item: item, size: None},
        ref arg => FuncArgType::Arg(arg.type_id()),
    }).collect();

    // TODO: Since we don't have proper generics, we just search through and try every function
    // with the given name to see if its arguments match. This is more similar to what C++ does
    // than Rust, but it works for the timebeing.
    // We keep searching until we find something that matches or we return the first error.
    scope.lookup(&method_name).into_iter().fold(Err(Error::UnresolvedName(method_name.clone())), |acc, item| acc.or_else(|err| match *item {
        ScopeItem::BuiltInFunction {type_id, ref operations} => {
            if scope.get_type(type_id).matches_signature(&method_args_types, target_type) {
                Ok(operations.clone())
            }
            else {
                Err(err)
            }
        },
        _ => Err(err),
    })).and_then(|operations| (*operations)(scope, args, target))
}

/// Returns the full path of the target type with the field appended to it
/// e.g. If target's type is `std::Foo` and field is `bar`, you get: `std::Foo::bar`
/// Also returns the target ScopeItem of this operation
/// Since this is a field access, it needs to operate on the target object that the `target`
/// expression refers to
fn resolve_field_name(scope: &ScopeStack, target: Expression, field: Identifier) -> Result<(ScopeItem, Identifier), Error> {
    // The full path of the target type
    // Something like `std::foo::Foo` or `u8` or `()`
    let (target_instance, target_type_path) = match target {
        Expression::Identifier(target_name) => scope.lookup(&target_name).first().ok_or_else(|| {
            Error::UnresolvedName(target_name.clone())
        }).and_then(|item| match **item {
            ScopeItem::Constant {type_id, ..} => Ok(((*item).clone(), type_id)),
            ScopeItem::TypedBlock {type_id, ..} => Ok(((*item).clone(), type_id)),
            ScopeItem::Array {..} => unimplemented!(),
            ScopeItem::BuiltInFunction {type_id, ..} => Err(Error::UnresolvedField {
                target_type: scope.get_type(type_id).clone(),
                field: field.clone(),
            }),
            // These are unreachable because numeric literals and byte literals are never stored
            // directly
            ScopeItem::NumericLiteral(..) | ScopeItem::ByteLiteral(..) => unreachable!(),
        }).map(|(item, type_id)| (item, scope.get_type_name(type_id).clone())),

        //TODO: It's likely that the below line will just not work at all
        // because the scope item returned in the tuple is not the target we should return.
        // I think we need to map on this result and return the field as the target...not sure.
        //Expression::Access {target, field} => resolve_field_name(scope, *target, field),
        Expression::Access {target, field} => unimplemented!(),

        //TODO: ByteLiterals are valid targets for field access
        // In this case, we need to return [u8; N] where N is the length of the byte literal
        // We also likely need to allocate and store this into a temporary variable
        Expression::ByteLiteral(..) => unimplemented!(),

        //TODO: Numbers are valid targets for field access
        // In this case, we need to return u8 or another valid type
        // We also likely need to allocate and store this into a temporary variable
        Expression::Number(..) => unimplemented!(),

        //TODO: Calls are valid targets for field access
        // In this case, we need to return the type name of the return type
        // Implementing this will be a bit more complicated since we need to do the call and return
        // the ops necessary for that
        Expression::Call {method, args} => unimplemented!(),
        Expression::Branch {..} => unreachable!(),
    }?;

    Ok((target_instance, target_type_path.concat(field)))
}
<|endoftext|>


<commit_before>// Module for reading sprides and saving them in a HashMap

use std::collections::HashMap;
use piston_window::*;
use io::sprite::Sprite;

/// HashMap for all given sprites
pub struct SpriteMap {
    pub map: HashMap<&'static str, Sprite>,
}

impl SpriteMap {
    /// Initialize the SpriteMap with given window, fills Map with all Sprites
    pub fn init(mut w: &mut PistonWindow) -> Self {
        let mut map2: HashMap<&'static str, Sprite> = HashMap::new();
        for i in SPRITES {
            map2.insert(i.image,
                        Sprite::fill_sprite(i.image, i.size_x as u32, i.size_y as u32,i.dur as u64, i.once, w));
        }

        SpriteMap { map: map2 }

    }

    /// creates empty SpriteMap
    pub fn new() -> Self {
        SpriteMap { map: HashMap::new() }
    }
    pub fn get_sprite(&self, file: String) -> Option<&Sprite> {
        self.map.get(file.as_str())
    }
}

/// Struct for representing Necessary information about sprites
struct SpriteModel {
    image: &'static str,
    size_x: usize,
    size_y: usize,
    dur: usize,
    once: bool,
}

/// const with all Sprites
const SPRITES: &'static [SpriteModel] = &[SpriteModel {
                                              image: "bowman.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_brown.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_pink.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_white.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "explosion.png",
                                              size_x: 59,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "knight.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "paladin.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "swipe_broadsword.png",
                                              size_x: 64,
                                              size_y: 192,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_longsword.png",
                                              size_x: 128,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "wizard.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_empty.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_full.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_half.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_10.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_20.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "swipe_enemy.png",
                                              size_x: 60,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          }];
<commit_msg>adjust size<commit_after>// Module for reading sprides and saving them in a HashMap

use std::collections::HashMap;
use piston_window::*;
use io::sprite::Sprite;

/// HashMap for all given sprites
pub struct SpriteMap {
    pub map: HashMap<&'static str, Sprite>,
}

impl SpriteMap {
    /// Initialize the SpriteMap with given window, fills Map with all Sprites
    pub fn init(mut w: &mut PistonWindow) -> Self {
        let mut map2: HashMap<&'static str, Sprite> = HashMap::new();
        for i in SPRITES {
            map2.insert(i.image,
                        Sprite::fill_sprite(i.image, i.size_x as u32, i.size_y as u32,i.dur as u64, i.once, w));
        }

        SpriteMap { map: map2 }

    }

    /// creates empty SpriteMap
    pub fn new() -> Self {
        SpriteMap { map: HashMap::new() }
    }
    pub fn get_sprite(&self, file: String) -> Option<&Sprite> {
        self.map.get(file.as_str())
    }
}

/// Struct for representing Necessary information about sprites
struct SpriteModel {
    image: &'static str,
    size_x: usize,
    size_y: usize,
    dur: usize,
    once: bool,
}

/// const with all Sprites
const SPRITES: &'static [SpriteModel] = &[SpriteModel {
                                              image: "bowman.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_brown.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_pink.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_white.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "explosion.png",
                                              size_x: 59,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "knight.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "paladin.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "swipe_broadsword.png",
                                              size_x: 64,
                                              size_y: 192,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_longsword.png",
                                              size_x: 128,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "wizard.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_empty.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_full.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_half.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_10.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_20.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "swipe_enemy.png",
                                              size_x: 72,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          }];
<|endoftext|>


<commit_before>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
    sent_initial_heartbeat: bool,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
            sent_initial_heartbeat: false,
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat * 500)); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                if event.is_readable() {
                    self.can_read = true;
                }
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.sent_initial_heartbeat = true;
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
            self.status = Status::Stop;
        }
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            // If we didn't send the first heartbeat, don't update last_write to trick us into sending it
            if self.sent_initial_heartbeat {
                self.last_write = Instant::now();
            }

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                self.send_continue()?;
            }
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            trace!("will write to buffer: {:?}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<commit_msg>IoLoop: convert heartbeat to u64 before multiplying it<commit_after>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
    sent_initial_heartbeat: bool,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
            sent_initial_heartbeat: false,
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                if event.is_readable() {
                    self.can_read = true;
                }
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.sent_initial_heartbeat = true;
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
            self.status = Status::Stop;
        }
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            // If we didn't send the first heartbeat, don't update last_write to trick us into sending it
            if self.sent_initial_heartbeat {
                self.last_write = Instant::now();
            }

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                self.send_continue()?;
            }
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            trace!("will write to buffer: {:?}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod test;

use std::fmt;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
    Array,
    Bool,
    Int,
    Str,
    Void,
}

impl Type {
    pub fn as_string_with_article(&self) -> &str {
        // Returns the name of the type with the correct English indefinite article prepended.
        match *self {
            Type::Array => "an array",
            Type::Bool => "a boolean",
            Type::Int => "an int",
            Type::Str => "a string",
            Type::Void => "nothing",
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Array => write!(fmt, "array"),
            Type::Bool => write!(fmt, "boolean"),
            Type::Int => write!(fmt, "int"),
            Type::Str => write!(fmt, "string"),
            Type::Void => write!(fmt, "void"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Value {
    Array(Vec<Value>),
    Bool(bool),
    Int(i64),
    Str(String),
}

impl Value {
    // Returns the value's type with the correct English indefinite article prepended.
    pub fn type_string_with_article(&self) -> &str {
        match *self {
            Value::Array(_) => "an array",
            Value::Bool(_) => "a boolean",
            Value::Int(_) => "an int",
            Value::Str(_) => "a string",
        }
    }

    // Checks whether the value is of a certain type.
    pub fn is_a(&self, t: &Type) -> bool {
        match (self, t) {
            (&Value::Array(_), &Type::Array) |
            (&Value::Bool(_), &Type::Bool) |
            (&Value::Int(_), &Type::Int) |
            (&Value::Str(_), &Type::Str) => true,
            _ => false
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Value::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, val) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", val));
                }

                write!(fmt, "]")
            }
            Value::Bool(b) => write!(fmt, "{}", b),
            Value::Int(i) => write!(fmt, "{}", i),
            Value::Str(ref s) => write!(fmt, "{}", s),
        }
    }
}

#[derive(Clone, Debug)]
pub enum BinOp {
    // Boolean
    And,
    Or,

    // Comparisons
    Equal,
    NotEqual,
    GreaterOrEqual,
    GreaterThan,
    LessOrEqual,
    LessThan,

    // Arithmetic
    Plus,
    Minus,
    Times,
    Divide,
    Modulus,
}

impl BinOp {
    // Gets the precedence of an operator.
    fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Or => Precedence::Or,
            BinOp::Equal | BinOp::NotEqual => Precedence::Equality,
            BinOp::GreaterOrEqual | BinOp::GreaterThan | BinOp::LessOrEqual | BinOp::LessThan =>
                Precedence::Inequality,
            BinOp::Plus | BinOp::Minus => Precedence::Addition,
            BinOp::Times | BinOp::Divide | BinOp::Modulus => Precedence::Multiplication,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Precedence {
    // Ordered correctly for derivation to be sound; each variant has higher precedence than the previous
    Or,
    And,
    Equality,
    Inequality,
    Addition,
    Multiplication,
    Constant,
}

impl fmt::Display for BinOp {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Equal => write!(fmt, "=="),
            BinOp::NotEqual => write!(fmt, "!="),
            BinOp::GreaterOrEqual => write!(fmt, ">="),
            BinOp::GreaterThan => write!(fmt, ">"),
            BinOp::LessOrEqual => write!(fmt, "<="),
            BinOp::LessThan => write!(fmt, "<"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Times => write!(fmt, "*"),
            BinOp::Divide => write!(fmt, "/"),
            BinOp::Modulus => write!(fmt, "%"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Expr {
    Array(Vec<Expr>),
    ArrayElement(String, Box<Expr>, Vec<Expr>),
    BinExp(Box<Expr>, BinOp, Box<Expr>),
    Call(String, Vec<Expr>),
    Not(Box<Expr>),
    Value(Value),
    Var(String),
}

impl Expr {
    // Returns the precedence level of the expression.
    fn precedence(&self) -> Precedence {
        match *self {
            Expr::BinExp(_, ref o, _) => o.precedence(),
            _ => Precedence::Constant,
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, val) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", val));
                }

                write!(fmt, "]")
            }
            Expr::ArrayElement(ref var, ref index, ref indexes) => {
                try!(write!(fmt, "{}[{}]", var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                Ok(())
            }
            Expr::BinExp(ref exp1, ref op, ref exp2) => {
                let op_precendence = op.precedence();

                // Wrap the left-hand side in parentheses if its precedence is lower than the operator
                if exp1.precedence() < op_precendence {
                    try!(write!(fmt, "({})", exp1));
                } else {
                    try!(write!(fmt, "{}", exp1));
                }

                try!(write!(fmt, " {} ", op));

                // Wrap the left-hand side in parentheses if its precedence is not greater than the operator
                if exp2.precedence() <= op_precendence {
                    write!(fmt, "({})", exp2)
                } else {
                    write!(fmt, "{}", exp2)
                }
            }
            Expr::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Expr::Not(ref exp) => write!(fmt, "!{}", exp),
            Expr::Value(ref val) => write!(fmt, "{}", val),
            Expr::Var(ref var) => write!(fmt, "{}", var),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Statement {
    ArrayElemAssign(String, Expr, Vec<Expr>, Expr),
    VarAssign(String, Expr),
    Defun(Type, String, Vec<String>, Vec<Statement>),
    If(Expr, Vec<Statement>, Vec<Statement>),
    Let(String, Expr),
    Print(Expr),
    Return(Expr),
    VoidCall(String, Vec<Expr>),
    While(Expr, Vec<Statement>),
}

impl Statement {
    // Formats the expression with indentation before it.
    fn fmt_with_indent(&self, mut fmt: &mut fmt::Formatter, indent_level: u32) -> fmt::Result {
        // Creates a new string that is as many spaces as `indent level * 4`.
        let indentation : String = (0..indent_level * 4).map(|_| " ").collect();

        match *self {
            Statement::ArrayElemAssign(ref var, ref index, ref indexes, ref exp) => {
                try!(write!(fmt, "{}{}[{}]", indentation, var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                writeln!(fmt, " = {};", exp)
            }
            Statement::Defun(ref return_type, ref name, ref params, ref body) => {
                try!(write!(fmt, "{}{} {}(", indentation, return_type, name));

                // Write the parameters, separated by commas
                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(writeln!(fmt, ") {{"));

                // Write the function body statements with one more level of indentation
                for stmt in body.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::If(ref clause, ref true_block, ref false_block) => {
                try!(writeln!(fmt, "{}if ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in true_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                // Don't write the "else" clause/block unless there is something in the block.
                if false_block.is_empty() {
                    return Ok(());
                }

                try!(writeln!(fmt, "{}}} else {{", indentation));

                // Write the block statements with one more level of indentation
                for stmt in false_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::Let(ref var, ref exp) => writeln!(fmt, "{}let {} = {};", indentation, var, exp),
            Statement::Print(ref exp) => writeln!(fmt, "{}print {};", indentation, exp),
            Statement::Return(ref exp) => writeln!(fmt, "{}return {};", indentation, exp),
            Statement::VarAssign(ref var, ref exp) => writeln!(fmt, "{}{} = {};", indentation, var, exp),
            Statement::VoidCall(ref name, ref args) => {
                try!(write!(fmt, "{}{}(", indentation, name));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ");")
            }
            Statement::While(ref clause, ref block) => {
                try!(writeln!(fmt, "{}while ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
        }
    }
}

impl fmt::Display for Statement {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.fmt_with_indent(fmt, 0)
    }
}
<commit_msg>reorder statements<commit_after>#[cfg(test)]
mod test;

use std::fmt;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
    Array,
    Bool,
    Int,
    Str,
    Void,
}

impl Type {
    pub fn as_string_with_article(&self) -> &str {
        // Returns the name of the type with the correct English indefinite article prepended.
        match *self {
            Type::Array => "an array",
            Type::Bool => "a boolean",
            Type::Int => "an int",
            Type::Str => "a string",
            Type::Void => "nothing",
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Array => write!(fmt, "array"),
            Type::Bool => write!(fmt, "boolean"),
            Type::Int => write!(fmt, "int"),
            Type::Str => write!(fmt, "string"),
            Type::Void => write!(fmt, "void"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Value {
    Array(Vec<Value>),
    Bool(bool),
    Int(i64),
    Str(String),
}

impl Value {
    // Returns the value's type with the correct English indefinite article prepended.
    pub fn type_string_with_article(&self) -> &str {
        match *self {
            Value::Array(_) => "an array",
            Value::Bool(_) => "a boolean",
            Value::Int(_) => "an int",
            Value::Str(_) => "a string",
        }
    }

    // Checks whether the value is of a certain type.
    pub fn is_a(&self, t: &Type) -> bool {
        match (self, t) {
            (&Value::Array(_), &Type::Array) |
            (&Value::Bool(_), &Type::Bool) |
            (&Value::Int(_), &Type::Int) |
            (&Value::Str(_), &Type::Str) => true,
            _ => false
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Value::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, val) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", val));
                }

                write!(fmt, "]")
            }
            Value::Bool(b) => write!(fmt, "{}", b),
            Value::Int(i) => write!(fmt, "{}", i),
            Value::Str(ref s) => write!(fmt, "{}", s),
        }
    }
}

#[derive(Clone, Debug)]
pub enum BinOp {
    // Boolean
    And,
    Or,

    // Comparisons
    Equal,
    NotEqual,
    GreaterOrEqual,
    GreaterThan,
    LessOrEqual,
    LessThan,

    // Arithmetic
    Plus,
    Minus,
    Times,
    Divide,
    Modulus,
}

impl BinOp {
    // Gets the precedence of an operator.
    fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Or => Precedence::Or,
            BinOp::Equal | BinOp::NotEqual => Precedence::Equality,
            BinOp::GreaterOrEqual | BinOp::GreaterThan | BinOp::LessOrEqual | BinOp::LessThan =>
                Precedence::Inequality,
            BinOp::Plus | BinOp::Minus => Precedence::Addition,
            BinOp::Times | BinOp::Divide | BinOp::Modulus => Precedence::Multiplication,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Precedence {
    // Ordered correctly for derivation to be sound; each variant has higher precedence than the previous
    Or,
    And,
    Equality,
    Inequality,
    Addition,
    Multiplication,
    Constant,
}

impl fmt::Display for BinOp {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Equal => write!(fmt, "=="),
            BinOp::NotEqual => write!(fmt, "!="),
            BinOp::GreaterOrEqual => write!(fmt, ">="),
            BinOp::GreaterThan => write!(fmt, ">"),
            BinOp::LessOrEqual => write!(fmt, "<="),
            BinOp::LessThan => write!(fmt, "<"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Times => write!(fmt, "*"),
            BinOp::Divide => write!(fmt, "/"),
            BinOp::Modulus => write!(fmt, "%"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Expr {
    Array(Vec<Expr>),
    ArrayElement(String, Box<Expr>, Vec<Expr>),
    BinExp(Box<Expr>, BinOp, Box<Expr>),
    Call(String, Vec<Expr>),
    Not(Box<Expr>),
    Value(Value),
    Var(String),
}

impl Expr {
    // Returns the precedence level of the expression.
    fn precedence(&self) -> Precedence {
        match *self {
            Expr::BinExp(_, ref o, _) => o.precedence(),
            _ => Precedence::Constant,
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, val) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", val));
                }

                write!(fmt, "]")
            }
            Expr::ArrayElement(ref var, ref index, ref indexes) => {
                try!(write!(fmt, "{}[{}]", var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                Ok(())
            }
            Expr::BinExp(ref exp1, ref op, ref exp2) => {
                let op_precendence = op.precedence();

                // Wrap the left-hand side in parentheses if its precedence is lower than the operator
                if exp1.precedence() < op_precendence {
                    try!(write!(fmt, "({})", exp1));
                } else {
                    try!(write!(fmt, "{}", exp1));
                }

                try!(write!(fmt, " {} ", op));

                // Wrap the left-hand side in parentheses if its precedence is not greater than the operator
                if exp2.precedence() <= op_precendence {
                    write!(fmt, "({})", exp2)
                } else {
                    write!(fmt, "{}", exp2)
                }
            }
            Expr::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Expr::Not(ref exp) => write!(fmt, "!{}", exp),
            Expr::Value(ref val) => write!(fmt, "{}", val),
            Expr::Var(ref var) => write!(fmt, "{}", var),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Statement {
    ArrayElemAssign(String, Expr, Vec<Expr>, Expr),
    Defun(Type, String, Vec<String>, Vec<Statement>),
    If(Expr, Vec<Statement>, Vec<Statement>),
    Let(String, Expr),
    Print(Expr),
    Return(Expr),
    VoidCall(String, Vec<Expr>),
    While(Expr, Vec<Statement>),
    VarAssign(String, Expr),
}

impl Statement {
    // Formats the expression with indentation before it.
    fn fmt_with_indent(&self, mut fmt: &mut fmt::Formatter, indent_level: u32) -> fmt::Result {
        // Creates a new string that is as many spaces as `indent level * 4`.
        let indentation : String = (0..indent_level * 4).map(|_| " ").collect();

        match *self {
            Statement::ArrayElemAssign(ref var, ref index, ref indexes, ref exp) => {
                try!(write!(fmt, "{}{}[{}]", indentation, var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                writeln!(fmt, " = {};", exp)
            }
            Statement::Defun(ref return_type, ref name, ref params, ref body) => {
                try!(write!(fmt, "{}{} {}(", indentation, return_type, name));

                // Write the parameters, separated by commas
                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(writeln!(fmt, ") {{"));

                // Write the function body statements with one more level of indentation
                for stmt in body.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::If(ref clause, ref true_block, ref false_block) => {
                try!(writeln!(fmt, "{}if ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in true_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                // Don't write the "else" clause/block unless there is something in the block.
                if false_block.is_empty() {
                    return Ok(());
                }

                try!(writeln!(fmt, "{}}} else {{", indentation));

                // Write the block statements with one more level of indentation
                for stmt in false_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::Let(ref var, ref exp) => writeln!(fmt, "{}let {} = {};", indentation, var, exp),
            Statement::Print(ref exp) => writeln!(fmt, "{}print {};", indentation, exp),
            Statement::Return(ref exp) => writeln!(fmt, "{}return {};", indentation, exp),
            Statement::VarAssign(ref var, ref exp) => writeln!(fmt, "{}{} = {};", indentation, var, exp),
            Statement::VoidCall(ref name, ref args) => {
                try!(write!(fmt, "{}{}(", indentation, name));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ");")
            }
            Statement::While(ref clause, ref block) => {
                try!(writeln!(fmt, "{}while ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
        }
    }
}

impl fmt::Display for Statement {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.fmt_with_indent(fmt, 0)
    }
}
<|endoftext|>