<commit_before>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}

// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_long_branch() {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {panic!("tjoo")}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("tjoo")}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}<commit_msg>Add trivial register roundtrip test<commit_after>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}

// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {panic!("rb")}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {panic!("rw")}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {panic!("rl")}
#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {panic!("wb")}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {panic!("ww")}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {panic!("wl")}
#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {panic!("lb")}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {panic!("sf")}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}
#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn roundtrip_D0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}
}<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::ty::{TypeAndMut, TyRef};
use rustc::hir::*;
use utils::{in_external_macro, span_lint};

/// **What it does:** This lint checks for instances of `mut mut` references.
///
/// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the source.
///
/// **Known problems:** None
///
/// **Example:** `let x = &mut &mut y;`
declare_lint! {
    pub MUT_MUT,
    Allow,
    "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \
     or shows a fundamental misunderstanding of references)"
}

#[derive(Copy,Clone)]
pub struct MutMut;

impl LintPass for MutMut {
    fn get_lints(&self) -> LintArray {
        lint_array!(MUT_MUT)
    }
}

impl LateLintPass for MutMut {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        check_expr_mut(cx, expr)
    }

    fn check_ty(&mut self, cx: &LateContext, ty: &Ty) {
        unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| {
            span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible");
        });
    }
}

fn check_expr_mut(cx: &LateContext, expr: &Expr) {
    fn unwrap_addr(expr: &Expr) -> Option<&Expr> {
        match expr.node {
            ExprAddrOf(MutMutable, ref e) => Some(e),
            _ => None,
        }
    }

    if in_external_macro(cx, expr.span) {
        return;
    }

    unwrap_addr(expr).map_or((), |e| {
        unwrap_addr(e).map_or_else(|| {
                                       if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty {
                                           span_lint(cx,
                                                     MUT_MUT,
                                                     expr.span,
                                                     "this expression mutably borrows a mutable reference. Consider \
                                                      reborrowing");
                                       }
                                   },
                                   |_| {
                                       span_lint(cx,
                                                 MUT_MUT,
                                                 expr.span,
                                                 "generally you want to avoid `&mut &mut _` if possible");
                                   })
    })
}

fn unwrap_mut(ty: &Ty) -> Option<&Ty> {
    match ty.node {
        TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) => Some(pty),
        _ => None,
    }
}
<commit_msg>simplify `mut_mut` lint<commit_after>use rustc::lint::*;
use rustc::ty::{TypeAndMut, TyRef};
use rustc::hir::*;
use utils::{in_external_macro, span_lint};

/// **What it does:** This lint checks for instances of `mut mut` references.
///
/// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the source.
///
/// **Known problems:** None
///
/// **Example:** `let x = &mut &mut y;`
declare_lint! {
    pub MUT_MUT,
    Allow,
    "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \
     or shows a fundamental misunderstanding of references)"
}

#[derive(Copy,Clone)]
pub struct MutMut;

impl LintPass for MutMut {
    fn get_lints(&self) -> LintArray {
        lint_array!(MUT_MUT)
    }
}

impl LateLintPass for MutMut {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) {
            return;
        }

        if let ExprAddrOf(MutMutable, ref e) = expr.node {
            if let ExprAddrOf(MutMutable, _) = e.node {
                span_lint(cx,
                          MUT_MUT,
                          expr.span,
                          "generally you want to avoid `&mut &mut _` if possible");
            } else {
                if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty {
                    span_lint(cx,
                              MUT_MUT,
                              expr.span,
                              "this expression mutably borrows a mutable reference. Consider reborrowing");
                }
            }
        }
    }

    fn check_ty(&mut self, cx: &LateContext, ty: &Ty) {
        if let TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) = ty.node {
            if let TyRptr(_, MutTy { mutbl: MutMutable, .. }) = pty.node {
                span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible");
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Ordering and hashing for floating point data.
//!
//! This module provides tools to ease the creation of geometry data that can
//! be ordered and hashed. For Plexus, this is most useful for quickly
//! identifying unique geometry in an iterator expression or `Mesh`.
//!
//! This code is best used with the
//! [derivative](https://crates.io/crates/derivative) crate, which can be used
//! to specify a particular hashing function for a given field.
//!
//! # Examples
//!
//! Creating a basic vertex type that can be used for rendering and implements
//! `Hash`:
//!
//! ```no_run,rust
//! use plexus::ordered;
//!
//! #[derive(Derivative)]
//! #[derivative(Hash)]
//! pub struct Vertex {
//!     #[derivative(Hash(hash_with="ordered::hash_float_array"))]
//!     pub position: [f32; 3],
//! }
//! ```

use num::Float;
use ordered_float;
use std::hash::{Hash, Hasher};

// TODO: https://github.com/reem/rust-ordered-float/pull/28
pub type NotNan<T> = ordered_float::NotNaN<T>;
pub use ordered_float::OrderedFloat;

#[allow(non_camel_case_types)]
pub type r32 = NotNan<f32>;
#[allow(non_camel_case_types)]
pub type r64 = NotNan<f64>;

pub trait HashConjugate: Sized {
    type Hash: Eq + Hash;

    fn into_hash(self) -> Self::Hash;
    fn from_hash(hash: Self::Hash) -> Self;
}

#[inline(always)]
pub fn hash_float<F, H>(f: &F, state: &mut H)
where
    F: Float,
    H: Hasher,
{
    OrderedFloat::from(*f).hash(state)
}

pub fn hash_float_slice<F, H>(slice: &[F], state: &mut H)
where
    F: Float,
    H: Hasher,
{
    for f in slice {
        hash_float(f, state);
    }
}

pub trait HashFloatArray {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher;
}

pub fn hash_float_array<F, H>(array: &F, state: &mut H)
where
    F: HashFloatArray,
    H: Hasher,
{
    array.hash(state);
}

macro_rules! hash_float_array {
    (lengths => $($N:expr),*) => {$(
        impl HashFloatArray for [f32; $N] {
            fn hash<H>(&self, state: &mut H)
            where
                H: Hasher
            {
                for f in self.iter() {
                    hash_float(f, state)
                }
            }
        }
    )*};
}
hash_float_array!(lengths => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
<commit_msg>Comment out attributes that cannot build for doc tests (until it can be fixed).<commit_after>//! Ordering and hashing for floating point data.
//!
//! This module provides tools to ease the creation of geometry data that can
//! be ordered and hashed. For Plexus, this is most useful for quickly
//! identifying unique geometry in an iterator expression or `Mesh`.
//!
//! This code is best used with the
//! [derivative](https://crates.io/crates/derivative) crate, which can be used
//! to specify a particular hashing function for a given field.
//!
//! # Examples
//!
//! Creating a basic vertex type that can be used for rendering and implements
//! `Hash`:
//!
//! ```no_run,rust
//! use plexus::ordered;
//!
//! // TODO: The `derive` and `derivative` attributes are commented out to prevent
//! //       build errors when running doc tests.
//! //#[derive(Derivative)]
//! //#[derivative(Hash)]
//! pub struct Vertex {
//!     //#[derivative(Hash(hash_with="ordered::hash_float_array"))]
//!     pub position: [f32; 3],
//! }
//! ```

use num::Float;
use ordered_float;
use std::hash::{Hash, Hasher};

// TODO: https://github.com/reem/rust-ordered-float/pull/28
pub type NotNan<T> = ordered_float::NotNaN<T>;
pub use ordered_float::OrderedFloat;

#[allow(non_camel_case_types)]
pub type r32 = NotNan<f32>;
#[allow(non_camel_case_types)]
pub type r64 = NotNan<f64>;

pub trait HashConjugate: Sized {
    type Hash: Eq + Hash;

    fn into_hash(self) -> Self::Hash;
    fn from_hash(hash: Self::Hash) -> Self;
}

#[inline(always)]
pub fn hash_float<F, H>(f: &F, state: &mut H)
where
    F: Float,
    H: Hasher,
{
    OrderedFloat::from(*f).hash(state)
}

pub fn hash_float_slice<F, H>(slice: &[F], state: &mut H)
where
    F: Float,
    H: Hasher,
{
    for f in slice {
        hash_float(f, state);
    }
}

pub trait HashFloatArray {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher;
}

pub fn hash_float_array<F, H>(array: &F, state: &mut H)
where
    F: HashFloatArray,
    H: Hasher,
{
    array.hash(state);
}

macro_rules! hash_float_array {
    (lengths => $($N:expr),*) => {$(
        impl HashFloatArray for [f32; $N] {
            fn hash<H>(&self, state: &mut H)
            where
                H: Hasher
            {
                for f in self.iter() {
                    hash_float(f, state)
                }
            }
        }
    )*};
}
hash_float_array!(lengths => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
<|endoftext|>


<commit_before>use std::fmt;
use std::collections::BTreeMap;

use itertools::Itertools;
use image::{GenericImage, Pixel, Rgb, Rgba};
use color_quant::NeuQuant;

/// Palette of colors.
#[derive(Debug, Hash, PartialEq, Eq, Default)]
pub struct Palette {
    /// Palette of Colors represented in RGB
    pub palette: Vec<Rgb<u8>>,
    /// A map of indizes in the palette to a count of pixels in approximately that color in the original image.
    pub pixel_counts: BTreeMap<usize, usize>,
}

impl Palette {
    /// Create a new palett from an image
    ///
    /// Color count and quality are given straight to [color_quant], values should be between
    /// 8...512 and 1...30 respectively. (By the way: 10 is a good default quality.)
    ///
    /// [color_quant]: https://github.com/PistonDevelopers/color_quant
    pub fn new<P, G>(image: &G, color_count: usize, quality: i32) -> Palette
        where P: Sized + Pixel<Subpixel = u8>,
              G: Sized + GenericImage<Pixel = P>
    {
        let pixels: Vec<Rgba<u8>> = image.pixels()
                                         .map(|(_, _, pixel)| pixel.to_rgba())
                                         .collect();

        let mut flat_pixels: Vec<u8> = Vec::with_capacity(pixels.len());
        for rgba in &pixels {
            if is_boring_pixel(&rgba) {
                continue;
            }

            for subpixel in rgba.channels() {
                flat_pixels.push(*subpixel);
            }
        }

        let quant = NeuQuant::new(quality, color_count, &flat_pixels);

        let pixel_counts = pixels.iter()
                                 .map(|rgba| quant.index_of(&rgba.channels()))
                                 .fold(BTreeMap::new(),
                                       |mut acc, pixel| {
                                           *acc.entry(pixel).or_insert(0) += 1;
                                           acc
                                       });

        let palette: Vec<Rgb<u8>> = quant.color_map_rgba()
                                         .iter()
                                         .chunks_lazy(4)
                                         .into_iter()
                                         .map(|rgba_iter| {
                                             let rgba_slice: Vec<u8> = rgba_iter.cloned().collect();
                                             Rgba::from_slice(&rgba_slice).clone().to_rgb()
                                         })
                                         .unique()
                                         .collect();

        Palette { palette: palette, pixel_counts: pixel_counts }
    }

    fn frequency_of(&self, color: &Rgb<u8>) -> usize {
        let index = self.palette.iter().position(|x| x.channels() == color.channels());
        if let Some(index) = index {
            *self.pixel_counts.get(&index).unwrap_or(&0)
        } else {
            0
        }
    }

    /// Change ordering of colors in palette to be of frequency using the pixel count.
    pub fn sort_by_frequency(&self) -> Self {
        let mut colors = self.palette.clone();
        colors.sort_by(|a, b| self.frequency_of(&a).cmp(&self.frequency_of(&b)));

        Palette { palette: colors, pixel_counts: self.pixel_counts.clone() }
    }
}

fn is_boring_pixel(pixel: &Rgba<u8>) -> bool {
    let (r, g, b, a) = (pixel[0], pixel[1], pixel[2], pixel[3]);

    // If pixel is mostly opaque and not white
    const MIN_ALPHA: u8 = 125;
    const MAX_COLOR: u8 = 250;

    let interesting = (a >= MIN_ALPHA) && !(r > MAX_COLOR && g > MAX_COLOR && b > MAX_COLOR);

    !interesting
}

impl fmt::Display for Palette {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let color_list = self.palette
                             .iter()
                             .map(|rgb| format!("#{:02X}{:02X}{:02X}", rgb[0], rgb[1], rgb[2]))
                             .join(", ");

        write!(f, "Color Palette {{ {} }}", color_list)
    }
}
<commit_msg>Split Long Doc Comment<commit_after>use std::fmt;
use std::collections::BTreeMap;

use itertools::Itertools;
use image::{GenericImage, Pixel, Rgb, Rgba};
use color_quant::NeuQuant;

/// Palette of colors.
#[derive(Debug, Hash, PartialEq, Eq, Default)]
pub struct Palette {
    /// Palette of Colors represented in RGB
    pub palette: Vec<Rgb<u8>>,
    /// A map of indices in the palette to a count of pixels in approximately that color in the
    pub pixel_counts: BTreeMap<usize, usize>,
}

impl Palette {
    /// Create a new palett from an image
    ///
    /// Color count and quality are given straight to [color_quant], values should be between
    /// 8...512 and 1...30 respectively. (By the way: 10 is a good default quality.)
    ///
    /// [color_quant]: https://github.com/PistonDevelopers/color_quant
    pub fn new<P, G>(image: &G, color_count: usize, quality: i32) -> Palette
        where P: Sized + Pixel<Subpixel = u8>,
              G: Sized + GenericImage<Pixel = P>
    {
        let pixels: Vec<Rgba<u8>> = image.pixels()
                                         .map(|(_, _, pixel)| pixel.to_rgba())
                                         .collect();

        let mut flat_pixels: Vec<u8> = Vec::with_capacity(pixels.len());
        for rgba in &pixels {
            if is_boring_pixel(&rgba) {
                continue;
            }

            for subpixel in rgba.channels() {
                flat_pixels.push(*subpixel);
            }
        }

        let quant = NeuQuant::new(quality, color_count, &flat_pixels);

        let pixel_counts = pixels.iter()
                                 .map(|rgba| quant.index_of(&rgba.channels()))
                                 .fold(BTreeMap::new(),
                                       |mut acc, pixel| {
                                           *acc.entry(pixel).or_insert(0) += 1;
                                           acc
                                       });

        let palette: Vec<Rgb<u8>> = quant.color_map_rgba()
                                         .iter()
                                         .chunks_lazy(4)
                                         .into_iter()
                                         .map(|rgba_iter| {
                                             let rgba_slice: Vec<u8> = rgba_iter.cloned().collect();
                                             Rgba::from_slice(&rgba_slice).clone().to_rgb()
                                         })
                                         .unique()
                                         .collect();

        Palette { palette: palette, pixel_counts: pixel_counts }
    }

    fn frequency_of(&self, color: &Rgb<u8>) -> usize {
        let index = self.palette.iter().position(|x| x.channels() == color.channels());
        if let Some(index) = index {
            *self.pixel_counts.get(&index).unwrap_or(&0)
        } else {
            0
        }
    }

    /// Change ordering of colors in palette to be of frequency using the pixel count.
    pub fn sort_by_frequency(&self) -> Self {
        let mut colors = self.palette.clone();
        colors.sort_by(|a, b| self.frequency_of(&a).cmp(&self.frequency_of(&b)));

        Palette { palette: colors, pixel_counts: self.pixel_counts.clone() }
    }
}

fn is_boring_pixel(pixel: &Rgba<u8>) -> bool {
    let (r, g, b, a) = (pixel[0], pixel[1], pixel[2], pixel[3]);

    // If pixel is mostly opaque and not white
    const MIN_ALPHA: u8 = 125;
    const MAX_COLOR: u8 = 250;

    let interesting = (a >= MIN_ALPHA) && !(r > MAX_COLOR && g > MAX_COLOR && b > MAX_COLOR);

    !interesting
}

impl fmt::Display for Palette {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let color_list = self.palette
                             .iter()
                             .map(|rgb| format!("#{:02X}{:02X}{:02X}", rgb[0], rgb[1], rgb[2]))
                             .join(", ");

        write!(f, "Color Palette {{ {} }}", color_list)
    }
}
<|endoftext|>


<commit_before>use std;
use std::fs;
use variables::*;
use variables::LpExpression::*;
use variables::Constraint::*;
use std::rc::Rc;
use std::collections::HashMap;
use solvers::*;

//use variables::LpExpression::{AddExpr, MulExpr};
use std::ops::{AddAssign};

//use std::collections::HashMap;

/// Enum helping to specify the objective function of the linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// ```
#[derive(Debug, PartialEq)]
pub enum LpObjective {
    Minimize,
    Maximize
}

/// Structure used for creating the model and solving a linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::operations::{LpOperations};
/// use lp_modeler::variables::{LpVariable, LpType};
/// use lp_modeler::solvers::Solver;
///
/// let ref a = LpVariable::new("a", LpType::Integer);
/// let ref b = LpVariable::new("b", LpType::Integer);
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// problem += (a + b).le(100.0);
/// problem += a.ge(b);
/// problem += 2.0*a + 3.0*b;
///
/// problem.solve(Solver::Cbc);
/// ```
#[derive(Debug)]
pub struct LpProblem {
    name: &'static str,
    objective_type: LpObjective,
    obj_expr: Option<LpExpression>,
    constraints: Vec<LpConstraint>

}

impl LpProblem {

    /// Create a new problem
    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
        LpProblem { name: name, objective_type: objective, obj_expr: None, constraints: Vec::new() }
    }

    // TODO: Call once and pass into parameter
    // TODO: Check variables on the objective function
    fn variables(&self) -> HashMap<String, &LpExpression> {

        fn var<'a>(expr: &'a LpExpression, lst: &mut Vec<(String, &'a LpExpression)>) {
            match expr {
                &BinaryVariable {ref name, ..} | &IntegerVariable {ref name, ..} | &ContinuousVariable {ref name, ..} => { lst.push((name.clone(), expr)); },
                &MulExpr(_, ref e) => { var(&*e, lst); },
                &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
                    var(&*e1, lst);
                    var(&*e2, lst);
                },
                _ => ()
            }
        }

        let mut lst: Vec<_> = Vec::new();
        for e in &self.constraints {
            var(&e.0, &mut lst);
        }
        lst.iter().map(|&(ref n, ref x)| (n.clone(), *x)).collect::<HashMap<String, &LpExpression>>()
    }

    fn objective_string(&self) -> String {

        if let Some(ref expr) = self.obj_expr {
            expr.to_string()
        } else {
            String::new()
        }
    }

    fn constraints_string(&self) -> String {
        let mut res = String::new();
        let mut cstrs = self.constraints.iter();
        let mut index = 1;
        while let Some(&LpConstraint(ref e1, ref op, ref e2)) = cstrs.next() {
            res.push_str("  c");
            res.push_str(&index.to_string());
            res.push_str(": ");
            index += 1;
            res.push_str(&e1.to_string());
            match op {
                &GreaterOrEqual => res.push_str(" >= "),
                &LessOrEqual => res.push_str(" <= "),
                &Equal => res.push_str(" = "),
            }
            res.push_str(&e2.to_string());
            res.push_str("\n");
        }
        res
    }

    fn bounds_string(&self) -> String {
        let mut res = String::new();
        for (_,v) in self.variables() {
            match v {
                &IntegerVariable { ref name, lower_bound, upper_bound }
                    | &ContinuousVariable { ref name, lower_bound, upper_bound } => {
                    if let Some(l) = lower_bound {
                        res.push_str("  ");
                        res.push_str(&l.to_string());
                        res.push_str(" <= ");
                        res.push_str(&name);
                        if let Some(u) = upper_bound {
                            res.push_str(" <= ");
                            res.push_str(&u.to_string());
                        }
                        res.push_str("\n");
                    } else if let Some(u) = upper_bound {
                        res.push_str("  ");
                        res.push_str(&name);
                        res.push_str(" <= ");
                        res.push_str(&u.to_string());
                        res.push_str("\n");
                    } else {
                        match v {
                            &ContinuousVariable {..} => {
                                res.push_str("  ");
                                res.push_str(&name);
                                res.push_str(" free\n");
                            }, // TODO: IntegerVar => -INF to INF
                            _ => ()
                        }
                    }
                },
                _ => (),
            }
        }
        res
    }

    fn generals_string(&self) -> String {
        let mut res = String::new();
        for (_,v) in self.variables() {
            match v {
                &IntegerVariable { ref name, .. } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    fn binaries_string(&self) -> String {
        let mut res = String::new();
        for (_,v) in self.variables() {
            match v {
                &BinaryVariable { ref name } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    pub fn write_lp<T: Into<String>>(&self, file_name: T) -> std::io::Result<()> {
        use std::fs::File;
        use std::io::prelude::*;

        let mut buffer = try!(File::create(file_name.into()));

        try!(buffer.write("\\ ".as_bytes()));
        try!(buffer.write(self.name.as_bytes()));
        try!(buffer.write("\n\n".as_bytes()));

        // Write objectives
        match self.objective_type {
            LpObjective::Maximize => { try!(buffer.write(b"Maximize\n  ")); },
            LpObjective::Minimize => { try!(buffer.write(b"Minimize\n  ")); },
        }
        let obj_str = self.objective_string();
        try!(buffer.write(obj_str.as_bytes()));

        // Write constraints
        let cstr_str = self.constraints_string();
        if cstr_str.len() > 0 {
            try!(buffer.write(b"\n\nSubject To\n"));
            try!(buffer.write(cstr_str.as_bytes()));
        }

        // Write bounds for Integer and Continuous
        let bound_str = self.bounds_string();
        if bound_str.len() > 0 {
            try!(buffer.write(b"\nBounds\n"));
            try!(buffer.write(bound_str.as_bytes()));
        }

        // Write Integer vars
        let generals_str = self.generals_string();
        if generals_str.len() > 0 {
            try!(buffer.write(b"\nGenerals\n  "));
            try!(buffer.write(generals_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        // Write Binaries vars
        let binaries_str = self.binaries_string();
        if binaries_str.len() > 0 {
            try!(buffer.write(b"\nBinary\n  "));
            try!(buffer.write(binaries_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        try!(buffer.write(b"\nEnd"));

        Ok(())

    }

    /// Solve the LP model
    pub fn solve<T: SolverTrait>(&self, s: T) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";
        let file_solution = "sol.sol";

        match self.write_lp(file_model) {
            Ok(_) => {
                // Sometimes, we have to read on stdin to know the status
                let status = try!(s.run_solver(file_model, file_solution));

                // Otherwise, the status is written on the output file
                let (status_read, res) = try!(s.read_solution(file_solution));
                let _ = fs::remove_file(file_model);
                match status {
                    Some(s) => Ok((s, res)),
                    _ => Ok((status_read, res))
                }
            },
            Err(e) => Err(e.to_string())
        }
    }
}

/// Add constraints
impl AddAssign<LpConstraint> for LpProblem {
    fn add_assign(&mut self, _rhs: LpConstraint) {
        self.constraints.push(_rhs);
    }
}

/// Add an expression as an objective function
impl<T> AddAssign<T> for LpProblem where T: Into<LpExpression>{
    fn add_assign(&mut self, _rhs: T) {
        //TODO: improve without cloning
        if let Some(e) = self.obj_expr.clone() {
            self.obj_expr = Some(AddExpr(Rc::new(_rhs.into()), Rc::new(e.clone())));
        } else {
            self.obj_expr = Some(_rhs.into());
        }
    }
}

impl ToString for LpExpression {
    fn to_string(&self) -> String {

        fn dfs(expr: &LpExpression, acc: &String) -> String {
            match expr {
                &MulExpr(ref e1, ref e2) => {
                    e1.to_string() + " " + &e2.to_string()
                },
                &AddExpr(ref e1, ref e2) => {
                    e1.to_string() + " + " + &e2.to_string()
                },
                &SubExpr(ref e1, ref e2) => {
                    e1.to_string() + " - " + &e2.to_string()
                },
                &BinaryVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &IntegerVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &ContinuousVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &LitVal(n) => {
                    acc.clone() + &n.to_string()
                },
                _ => acc.clone()
            }
        }

        dfs(self, &String::new())
    }
}
<commit_msg>Fix doc example<commit_after>use std;
use std::fs;
use variables::*;
use variables::LpExpression::*;
use variables::Constraint::*;
use std::rc::Rc;
use std::collections::HashMap;
use solvers::*;

//use variables::LpExpression::{AddExpr, MulExpr};
use std::ops::{AddAssign};

//use std::collections::HashMap;

/// Enum helping to specify the objective function of the linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// ```
#[derive(Debug, PartialEq)]
pub enum LpObjective {
    Minimize,
    Maximize
}

/// Structure used for creating the model and solving a linear problem.
///
/// # Exemples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::operations::{LpOperations};
/// use lp_modeler::variables::{LpVariable, LpType};
/// use lp_modeler::solvers::CbcSolver;
///
/// let ref a = LpVariable::new("a", LpType::Integer);
/// let ref b = LpVariable::new("b", LpType::Integer);
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// problem += (a + b).le(100.0);
/// problem += a.ge(b);
/// problem += 2.0*a + 3.0*b;
///
/// problem.solve(CbcSolver);
/// ```
#[derive(Debug)]
pub struct LpProblem {
    name: &'static str,
    objective_type: LpObjective,
    obj_expr: Option<LpExpression>,
    constraints: Vec<LpConstraint>

}

impl LpProblem {

    /// Create a new problem
    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
        LpProblem { name: name, objective_type: objective, obj_expr: None, constraints: Vec::new() }
    }

    // TODO: Call once and pass into parameter
    // TODO: Check variables on the objective function
    fn variables(&self) -> HashMap<String, &LpExpression> {

        fn var<'a>(expr: &'a LpExpression, lst: &mut Vec<(String, &'a LpExpression)>) {
            match expr {
                &BinaryVariable {ref name, ..} | &IntegerVariable {ref name, ..} | &ContinuousVariable {ref name, ..} => { lst.push((name.clone(), expr)); },
                &MulExpr(_, ref e) => { var(&*e, lst); },
                &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
                    var(&*e1, lst);
                    var(&*e2, lst);
                },
                _ => ()
            }
        }

        let mut lst: Vec<_> = Vec::new();
        for e in &self.constraints {
            var(&e.0, &mut lst);
        }
        lst.iter().map(|&(ref n, ref x)| (n.clone(), *x)).collect::<HashMap<String, &LpExpression>>()
    }

    fn objective_string(&self) -> String {

        if let Some(ref expr) = self.obj_expr {
            expr.to_string()
        } else {
            String::new()
        }
    }

    fn constraints_string(&self) -> String {
        let mut res = String::new();
        let mut cstrs = self.constraints.iter();
        let mut index = 1;
        while let Some(&LpConstraint(ref e1, ref op, ref e2)) = cstrs.next() {
            res.push_str("  c");
            res.push_str(&index.to_string());
            res.push_str(": ");
            index += 1;
            res.push_str(&e1.to_string());
            match op {
                &GreaterOrEqual => res.push_str(" >= "),
                &LessOrEqual => res.push_str(" <= "),
                &Equal => res.push_str(" = "),
            }
            res.push_str(&e2.to_string());
            res.push_str("\n");
        }
        res
    }

    fn bounds_string(&self) -> String {
        let mut res = String::new();
        for (_,v) in self.variables() {
            match v {
                &IntegerVariable { ref name, lower_bound, upper_bound }
                    | &ContinuousVariable { ref name, lower_bound, upper_bound } => {
                    if let Some(l) = lower_bound {
                        res.push_str("  ");
                        res.push_str(&l.to_string());
                        res.push_str(" <= ");
                        res.push_str(&name);
                        if let Some(u) = upper_bound {
                            res.push_str(" <= ");
                            res.push_str(&u.to_string());
                        }
                        res.push_str("\n");
                    } else if let Some(u) = upper_bound {
                        res.push_str("  ");
                        res.push_str(&name);
                        res.push_str(" <= ");
                        res.push_str(&u.to_string());
                        res.push_str("\n");
                    } else {
                        match v {
                            &ContinuousVariable {..} => {
                                res.push_str("  ");
                                res.push_str(&name);
                                res.push_str(" free\n");
                            }, // TODO: IntegerVar => -INF to INF
                            _ => ()
                        }
                    }
                },
                _ => (),
            }
        }
        res
    }

    fn generals_string(&self) -> String {
        let mut res = String::new();
        for (_,v) in self.variables() {
            match v {
                &IntegerVariable { ref name, .. } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    fn binaries_string(&self) -> String {
        let mut res = String::new();
        for (_,v) in self.variables() {
            match v {
                &BinaryVariable { ref name } => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    pub fn write_lp<T: Into<String>>(&self, file_name: T) -> std::io::Result<()> {
        use std::fs::File;
        use std::io::prelude::*;

        let mut buffer = try!(File::create(file_name.into()));

        try!(buffer.write("\\ ".as_bytes()));
        try!(buffer.write(self.name.as_bytes()));
        try!(buffer.write("\n\n".as_bytes()));

        // Write objectives
        match self.objective_type {
            LpObjective::Maximize => { try!(buffer.write(b"Maximize\n  ")); },
            LpObjective::Minimize => { try!(buffer.write(b"Minimize\n  ")); },
        }
        let obj_str = self.objective_string();
        try!(buffer.write(obj_str.as_bytes()));

        // Write constraints
        let cstr_str = self.constraints_string();
        if cstr_str.len() > 0 {
            try!(buffer.write(b"\n\nSubject To\n"));
            try!(buffer.write(cstr_str.as_bytes()));
        }

        // Write bounds for Integer and Continuous
        let bound_str = self.bounds_string();
        if bound_str.len() > 0 {
            try!(buffer.write(b"\nBounds\n"));
            try!(buffer.write(bound_str.as_bytes()));
        }

        // Write Integer vars
        let generals_str = self.generals_string();
        if generals_str.len() > 0 {
            try!(buffer.write(b"\nGenerals\n  "));
            try!(buffer.write(generals_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        // Write Binaries vars
        let binaries_str = self.binaries_string();
        if binaries_str.len() > 0 {
            try!(buffer.write(b"\nBinary\n  "));
            try!(buffer.write(binaries_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        try!(buffer.write(b"\nEnd"));

        Ok(())

    }

    /// Solve the LP model
    pub fn solve<T: SolverTrait>(&self, s: T) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";
        let file_solution = "sol.sol";

        match self.write_lp(file_model) {
            Ok(_) => {
                // Sometimes, we have to read on stdin to know the status
                let status = try!(s.run_solver(file_model, file_solution));

                // Otherwise, the status is written on the output file
                let (status_read, res) = try!(s.read_solution(file_solution));
                let _ = fs::remove_file(file_model);
                match status {
                    Some(s) => Ok((s, res)),
                    _ => Ok((status_read, res))
                }
            },
            Err(e) => Err(e.to_string())
        }
    }
}

/// Add constraints
impl AddAssign<LpConstraint> for LpProblem {
    fn add_assign(&mut self, _rhs: LpConstraint) {
        self.constraints.push(_rhs);
    }
}

/// Add an expression as an objective function
impl<T> AddAssign<T> for LpProblem where T: Into<LpExpression>{
    fn add_assign(&mut self, _rhs: T) {
        //TODO: improve without cloning
        if let Some(e) = self.obj_expr.clone() {
            self.obj_expr = Some(AddExpr(Rc::new(_rhs.into()), Rc::new(e.clone())));
        } else {
            self.obj_expr = Some(_rhs.into());
        }
    }
}

impl ToString for LpExpression {
    fn to_string(&self) -> String {

        fn dfs(expr: &LpExpression, acc: &String) -> String {
            match expr {
                &MulExpr(ref e1, ref e2) => {
                    e1.to_string() + " " + &e2.to_string()
                },
                &AddExpr(ref e1, ref e2) => {
                    e1.to_string() + " + " + &e2.to_string()
                },
                &SubExpr(ref e1, ref e2) => {
                    e1.to_string() + " - " + &e2.to_string()
                },
                &BinaryVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &IntegerVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &ContinuousVariable {name: ref n, .. } => {
                    acc.clone() + n
                },
                &LitVal(n) => {
                    acc.clone() + &n.to_string()
                },
                _ => acc.clone()
            }
        }

        dfs(self, &String::new())
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            while index < self.instructions.len() {
                let current_cell = vm.cells[vm.data_pointer];
                let patch = match (self.instructions[index], self.status) {
                    (_, ProgramStatus::Seeking(goal)) => {
                        Program::attempt_forward_jump(
                            &self.instructions,
                            index,
                            goal,
                            self.current_depth,
                        )
                    }

                    (Command::JumpForward, _) => {
                        match current_cell {
                            0 => {
                                Program::attempt_forward_jump(
                                    &self.instructions,
                                    index,
                                    self.current_depth,
                                    self.current_depth,
                                )
                            }

                            _ => ProgramPatch {
                                instruction_pointer: index + 1,
                                status: ProgramStatus::Normal,
                                current_depth: self.current_depth + 1,
                            },
                        }
                    }

                    (Command::JumpBackward, _) => {
                        match current_cell {
                            0 => ProgramPatch {
                                instruction_pointer: index + 1,
                                status: ProgramStatus::Normal,
                                current_depth: self.current_depth - 1,
                            },

                            _ => {
                                Program::backward_jump(
                                    &self.instructions,
                                    index,
                                    self.current_depth,
                                )
                            }
                        }
                    }

                    (command, _) => {
                        vm.apply(command);
                        ProgramPatch {
                            status: ProgramStatus::Normal,
                            current_depth: self.current_depth,
                            instruction_pointer: index + 1,
                        }
                    }
                };

                self.update(patch);
                index = patch.instruction_pointer;
            }
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index + 1,
                    status: ProgramStatus::Normal,
                    current_depth: current_depth + 1,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(&commands[index..], Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![
            Command::JumpForward,
            Command::JumpForward,
            Command::JumpBackward,
        ];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(
            actual,
            ProgramPatch {
                instruction_pointer: 3,
                current_depth: 1,
                status: ProgramStatus::Seeking(0),
            }
        )
    }
}
<commit_msg>Fix spacing<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            while index < self.instructions.len() {
                let current_cell = vm.cells[vm.data_pointer];
                let patch = match (self.instructions[index], self.status) {
                    (_, ProgramStatus::Seeking(goal)) => {
                        Program::attempt_forward_jump(
                            &self.instructions,
                            index,
                            goal,
                            self.current_depth,
                        )
                    }

                    (Command::JumpForward, _) => {
                        match current_cell {
                            0 => {
                                Program::attempt_forward_jump(
                                    &self.instructions,
                                    index,
                                    self.current_depth,
                                    self.current_depth,
                                )
                            }

                            _ => ProgramPatch {
                                instruction_pointer: index + 1,
                                status: ProgramStatus::Normal,
                                current_depth: self.current_depth + 1,
                            },
                        }
                    }

                    (Command::JumpBackward, _) => {
                        match current_cell {
                            0 => ProgramPatch {
                                instruction_pointer: index + 1,
                                status: ProgramStatus::Normal,
                                current_depth: self.current_depth - 1,
                            },

                            _ => {
                                Program::backward_jump(
                                    &self.instructions,
                                    index,
                                    self.current_depth,
                                )
                            }
                        }
                    }

                    (command, _) => {
                        vm.apply(command);
                        ProgramPatch {
                            status: ProgramStatus::Normal,
                            current_depth: self.current_depth,
                            instruction_pointer: index + 1,
                        }
                    }
                };

                self.update(patch);
                index = patch.instruction_pointer;
            }
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index + 1,
                    status: ProgramStatus::Normal,
                    current_depth: current_depth + 1,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(&commands[index..], Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![
            Command::JumpForward,
            Command::JumpForward,
            Command::JumpBackward,
        ];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(
            actual,
            ProgramPatch {
                instruction_pointer: 3,
                current_depth: 1,
                status: ProgramStatus::Seeking(0),
            }
        )
    }
}
<|endoftext|>


<commit_before>use config::{Config, ConfigError};
use config::project::ProjectConf;
use language::Language;
use std::{env, fs, io};
use std::path::PathBuf;
use std::process::{Child, Command, ExitStatus, Stdio};

pub struct Project {
    pub name: String,
    pub language: &'static Language,
    pub artifact: String,
}

impl <'a>Project {
    pub fn new() -> Result<Project, ProjectError<'a>> {
        let mut current_dir = env::current_dir().unwrap();

        match Self::get_config(&mut current_dir) {
            Ok(conf) => {
                let project_name = current_dir.iter().last().unwrap().to_str().unwrap();

                let language: &Language;
                match Language::find(&conf.language) {
                    Some(l) => language = l,
                    None => return Err(ProjectError {
                        message: "Unsupported language",
                        root: RootError::None(()),
                    }),
                }

                Ok(Project {
                    name: project_name.to_string(),
                    language: language,
                    artifact: conf.artifact,
                })
            },
            Err(e) => {
                Err(ProjectError {
                    message: "Could not load project.json",
                    root: RootError::ConfigError(e),
                })
            }
        }
    }

    fn get_config(path: &mut PathBuf) -> Result<ProjectConf, ConfigError> {
        path.push("project.json");
        let conf = try!(ProjectConf::load(&path));
        Ok(conf)
    }

    pub fn create(name: &str, lang_name: &str, is_blank: bool) -> Result<(), ProjectError<'a>> {
        // Check that language is valid
        let language: &Language;
        match Language::find(lang_name) {
            Some(l) => language = l,
            None => return Err(ProjectError {
                message: "Unsupported language",
                root: RootError::None(()),
            }),
        }

        let mut project_path = PathBuf::from(name);

        // Make sure folder doesn't already exist
        if fs::metadata(&project_path).is_ok() {
            return Err(ProjectError {
                message: "Project already exists",
                root: RootError::None(()),
            });
        }

        // Clone example project or create empty project folder
        if is_blank {
            if let Some(e) = fs::create_dir(&project_path).err() {
                return Err(ProjectError {
                    message: "Could not create project directory",
                    root: RootError::IoError(e),
                });
            }
        } else {
            Command::new("git")
                .arg("clone")
                .arg(language.example_repo)
                .arg(name)
                .output()
                .unwrap();
        }

        // Create project.json
        let project_conf = ProjectConf::new(lang_name, language.artifact);
        project_path.push("project.json");
        if let Some(e) = ProjectConf::save(&project_conf, &project_path).err() {
            return Err(ProjectError {
                message: "Could not create project.json",
                root: RootError::ConfigError(e),
            });
        }

        Ok(())
    }

    pub fn run(&self, args: &Vec<String>) -> Result<ExitStatus, ProjectError> {
        let mut command: Child;
        let mut cmd: Command;

        if self.language.runtime.is_some() {
            cmd = Command::new(self.language.runtime.unwrap());
            cmd.arg(&self.artifact);
        } else {
            cmd = Command::new(&self.artifact);
        }

        let cmd_result = cmd.args(args)
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn();

        match cmd_result {
            Ok(cmd) => command = cmd,
            Err(e) => return Err(ProjectError {
                message: "Could not run project",
                root: RootError::IoError(e),
            }),
        }

        match command.wait() {
    	    Ok(s) => Ok(s),
    	    Err(e) => Err(ProjectError {
	            message: "Error while running project",
	            root: RootError::IoError(e),
            })
        }
    }
}

#[derive(Debug)]
pub struct ProjectError<'a> {
    pub message: &'a str,
    pub root: RootError,
}

#[derive(Debug)]
pub enum RootError {
    None(()),
    ConfigError(ConfigError),
    IoError(io::Error),
}<commit_msg>Git clone command now outputs status to console<commit_after>use config::{Config, ConfigError};
use config::project::ProjectConf;
use language::Language;
use std::{env, fs, io};
use std::path::PathBuf;
use std::process::{Child, Command, ExitStatus, Stdio};

pub struct Project {
    pub name: String,
    pub language: &'static Language,
    pub artifact: String,
}

impl <'a>Project {
    pub fn new() -> Result<Project, ProjectError<'a>> {
        let mut current_dir = env::current_dir().unwrap();

        match Self::get_config(&mut current_dir) {
            Ok(conf) => {
                let project_name = current_dir.iter().last().unwrap().to_str().unwrap();

                let language: &Language;
                match Language::find(&conf.language) {
                    Some(l) => language = l,
                    None => return Err(ProjectError {
                        message: "Unsupported language",
                        root: RootError::None(()),
                    }),
                }

                Ok(Project {
                    name: project_name.to_string(),
                    language: language,
                    artifact: conf.artifact,
                })
            },
            Err(e) => {
                Err(ProjectError {
                    message: "Could not load project.json",
                    root: RootError::ConfigError(e),
                })
            }
        }
    }

    fn get_config(path: &mut PathBuf) -> Result<ProjectConf, ConfigError> {
        path.push("project.json");
        let conf = try!(ProjectConf::load(&path));
        Ok(conf)
    }

    pub fn create(name: &str, lang_name: &str, is_blank: bool) -> Result<(), ProjectError<'a>> {
        // Check that language is valid
        let language: &Language;
        match Language::find(lang_name) {
            Some(l) => language = l,
            None => return Err(ProjectError {
                message: "Unsupported language",
                root: RootError::None(()),
            }),
        }

        let mut project_path = PathBuf::from(name);

        // Make sure folder doesn't already exist
        if fs::metadata(&project_path).is_ok() {
            return Err(ProjectError {
                message: "Project already exists",
                root: RootError::None(()),
            });
        }

        // Clone example project or create empty project folder
        if is_blank {
            if let Some(e) = fs::create_dir(&project_path).err() {
                return Err(ProjectError {
                    message: "Could not create project directory",
                    root: RootError::IoError(e),
                });
            }
        } else {
            Command::new("git")
                .arg("clone")
                .arg(language.example_repo)
                .arg(name)
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .output()
                .unwrap();
        }

        // Create project.json
        let project_conf = ProjectConf::new(lang_name, language.artifact);
        project_path.push("project.json");
        if let Some(e) = ProjectConf::save(&project_conf, &project_path).err() {
            return Err(ProjectError {
                message: "Could not create project.json",
                root: RootError::ConfigError(e),
            });
        }

        Ok(())
    }

    pub fn run(&self, args: &Vec<String>) -> Result<ExitStatus, ProjectError> {
        let mut command: Child;
        let mut cmd: Command;

        if self.language.runtime.is_some() {
            cmd = Command::new(self.language.runtime.unwrap());
            cmd.arg(&self.artifact);
        } else {
            cmd = Command::new(&self.artifact);
        }

        let cmd_result = cmd.args(args)
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn();

        match cmd_result {
            Ok(cmd) => command = cmd,
            Err(e) => return Err(ProjectError {
                message: "Could not run project",
                root: RootError::IoError(e),
            }),
        }

        match command.wait() {
    	    Ok(s) => Ok(s),
    	    Err(e) => Err(ProjectError {
	            message: "Error while running project",
	            root: RootError::IoError(e),
            })
        }
    }
}

#[derive(Debug)]
pub struct ProjectError<'a> {
    pub message: &'a str,
    pub root: RootError,
}

#[derive(Debug)]
pub enum RootError {
    None(()),
    ConfigError(ConfigError),
    IoError(io::Error),
}<|endoftext|>


<commit_before>
use ffi;
use super::c64;
use super::util::FFTW_MUTEX;

use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}
<commit_msg>Add impls to RawVec<commit_after>
use ffi;
use super::c64;
use super::util::FFTW_MUTEX;

use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<|endoftext|>


<commit_before>
use ffi;
use super::util::FFTW_MUTEX;

use num_complex::Complex64 as c64;
use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn len(&self) -> usize { self.n }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = 0.0;
        }
        vec
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = c64::new(0.0, 0.0);
        }
        vec
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<commit_msg>add c32, f32 RawVec<commit_after>
use ffi;
use super::util::FFTW_MUTEX;

use num_complex::Complex32 as c32;
use num_complex::Complex64 as c64;
use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn len(&self) -> usize { self.n }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f32> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftwf_alloc_real(n) };
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = 0.0;
        }
        vec
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = 0.0;
        }
        vec
    }
}

impl RawVec<c32> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftwf_alloc_complex(n) } as *mut c32;
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = c32::new(0.0, 0.0);
        }
        vec
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = c64::new(0.0, 0.0);
        }
        vec
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<|endoftext|>


<commit_before>use error::Error;
use pos::Pos;
use token::{Token, TokenType};

use std::str::Chars;
use std::iter::{Fuse, Peekable};

pub struct Scanner<'a> {
    data: Peekable<Fuse<Chars<'a>>>,
    start_pos: Pos,
    curr_pos: Pos,
}

impl<'a> Scanner<'a> {
    // Create a new scanner from a given program represented as a
    // String.
    pub fn new<'b>(data: &'b str) -> Scanner<'b> {
        Scanner {
            data: data.chars().fuse().peekable(),
            start_pos: Pos { line: 1, col: 1 },
            curr_pos: Pos { line: 1, col: 1 },
        }
    }

    // Internal function: return the character at the current index.
    fn peek(&mut self) -> char {
		self.data.peek().map(|&c|c).unwrap_or('\x00')
    }

    // Internal function: return the character at the current index
    // and increment the index by one.
    fn advance(&mut self) -> char {
        let c = self.peek();
        if c == '\n' {
            self.curr_pos.line += 1;
            self.curr_pos.col = 1;
        } else {
            self.curr_pos.col += 1
        }
        c
    }

    // Internal function: verify if the end of the program has been
    // reached.
    fn is_eof(&mut self) -> bool {
        self.data.peek().is_some()
    }

    pub fn next_token(&mut self) -> Result<Token, Error> {
        // Discard blanks and comments.
        self.skip_comments_and_whitespace();

        // Set start_pos (starting position of the next token) to the
        // value of curr_pos (current position in the text stream).
        self.start_pos = self.curr_pos;

        // Return Eof if the end of the file has been reached.
        if self.is_eof() {
            return Ok(self.empty_tok(TokenType::Eof));
        }

        // Scanning dispatch.
        match self.peek() {
            '+' => { Ok(self.single_char_tok(TokenType::Plus)) }
            '-' => { Ok(self.single_char_tok(TokenType::Minus)) }
            '*' => { Ok(self.single_char_tok(TokenType::Star)) }
            '/' => { Ok(self.single_char_tok(TokenType::Slash)) }
            '=' => { Ok(self.single_char_tok(TokenType::Equal)) }
            '(' => { Ok(self.single_char_tok(TokenType::LParen)) }
            ')' => { Ok(self.single_char_tok(TokenType::RParen)) }
            ':' => { Ok(self.single_char_tok(TokenType::Colon)) }
            ';' => { Ok(self.single_char_tok(TokenType::Semicolon)) }
            c if c.is_digit(10) => { self.scan_int_or_float() }
            c if is_id_start(c) => { self.scan_id_or_keyword() }
            c   => { Err(Error::IllegalCharacter(self.curr_pos, c)) }
        }
    }

    // Scan digits into an Int or Float token.
    fn scan_int_or_float(&mut self) -> Result<Token, Error> {
        let mut val = String::new();
        while self.peek().is_digit(10) {
            val.push(self.advance());
        }

        if self.peek() != '.' {
            return Ok(self.lexeme_tok(TokenType::Int, val));
        }

        val.push(self.advance()); // Add decimal point.

        while self.peek().is_digit(10) {
            val.push(self.advance());
        }

        Ok(self.lexeme_tok(TokenType::Float, val))
    }

    // Scan alpha-numeric characters into an Id or a keyword token.
    fn scan_id_or_keyword(&mut self) -> Result<Token, Error> {
        let mut lexeme = String::new();
        while is_id_char(self.peek()) {
            lexeme.push(self.advance());
        }

        if lexeme == "if" { return Ok(self.empty_tok(TokenType::If)); }
        if lexeme == "then" { return Ok(self.empty_tok(TokenType::Then)); }
        if lexeme == "else" { return Ok(self.empty_tok(TokenType::Else)); }
        if lexeme == "end" { return Ok(self.empty_tok(TokenType::End)); }
        if lexeme == "while" { return Ok(self.empty_tok(TokenType::While)); }
        if lexeme == "do" { return Ok(self.empty_tok(TokenType::Do)); }
        if lexeme == "done" { return Ok(self.empty_tok(TokenType::Done)); }
        if lexeme == "read" { return Ok(self.empty_tok(TokenType::Read)); }
        if lexeme == "print" { return Ok(self.empty_tok(TokenType::Print)); }
        if lexeme == "var" { return Ok(self.empty_tok(TokenType::Var)); }
        if lexeme == "int" { return Ok(self.empty_tok(TokenType::TypeInt)); }
        if lexeme == "float" { return Ok(self.empty_tok(TokenType::TypeFloat)); }

        Ok(self.lexeme_tok(TokenType::Id, lexeme))
    }

    fn skip_comments_and_whitespace(&mut self) {
        loop {
            self.skip_whitespace();
            if self.peek() == '#' {
                self.skip_comment();
            } else {
                break;
            }
        }
    }

    fn skip_whitespace(&mut self) {
        while self.peek().is_whitespace() {
            self.advance();
        }
    }

    fn skip_comment(&mut self) {
        while self.peek() != '\n' {
            self.advance();
        }
    }

    fn empty_tok(&self, t: TokenType) -> Token {
        let t = Token {
            typ: t,
            lexeme: None,
            pos: self.start_pos,
        };
        t
    }

    fn lexeme_tok(&self, t: TokenType, lexeme: String) -> Token {
        let t = Token {
            typ: t,
            lexeme: Some(lexeme),
            pos: self.start_pos,
        };
        t
    }

    fn single_char_tok(&mut self, t: TokenType) -> Token {
        let t = self.empty_tok(t);
        self.advance();
        t
    }
}

fn is_id_start(c: char) -> bool {
    (c >= 'a' && c <= 'z') ||
    c == '_' ||
    (c >= 'A' && c <= 'Z')
}

fn is_id_char(c: char) -> bool {
    (c >= 'a' && c <= 'z') ||
    c == '_' ||
    c.is_digit(10) ||
    (c >= 'A' && c <= 'Z')
}
<commit_msg>Use  instead of a series of s in scanner.rs<commit_after>use error::Error;
use pos::Pos;
use token::{Token, TokenType};

use std::str::Chars;
use std::iter::{Fuse, Peekable};

pub struct Scanner<'a> {
    data: Peekable<Fuse<Chars<'a>>>,
    start_pos: Pos,
    curr_pos: Pos,
}

impl<'a> Scanner<'a> {
    // Create a new scanner from a given program represented as a
    // String.
    pub fn new<'b>(data: &'b str) -> Scanner<'b> {
        Scanner {
            data: data.chars().fuse().peekable(),
            start_pos: Pos { line: 1, col: 1 },
            curr_pos: Pos { line: 1, col: 1 },
        }
    }

    // Internal function: return the character at the current index.
    fn peek(&mut self) -> char {
        self.data.peek().map(|&c|c).unwrap_or('\x00')
    }

    // Internal function: return the character at the current index
    // and increment the index by one.
    fn advance(&mut self) -> char {
        let c = self.peek();
        if c == '\n' {
            self.curr_pos.line += 1;
            self.curr_pos.col = 1;
        } else {
            self.curr_pos.col += 1
        }
        c
    }

    // Internal function: verify if the end of the program has been
    // reached.
    fn is_eof(&mut self) -> bool {
        self.data.peek().is_some()
    }

    pub fn next_token(&mut self) -> Result<Token, Error> {
        // Discard blanks and comments.
        self.skip_comments_and_whitespace();

        // Set start_pos (starting position of the next token) to the
        // value of curr_pos (current position in the text stream).
        self.start_pos = self.curr_pos;

        // Return Eof if the end of the file has been reached.
        if self.is_eof() {
            return Ok(self.empty_tok(TokenType::Eof));
        }

        // Scanning dispatch.
        match self.peek() {
            '+' => { Ok(self.single_char_tok(TokenType::Plus)) }
            '-' => { Ok(self.single_char_tok(TokenType::Minus)) }
            '*' => { Ok(self.single_char_tok(TokenType::Star)) }
            '/' => { Ok(self.single_char_tok(TokenType::Slash)) }
            '=' => { Ok(self.single_char_tok(TokenType::Equal)) }
            '(' => { Ok(self.single_char_tok(TokenType::LParen)) }
            ')' => { Ok(self.single_char_tok(TokenType::RParen)) }
            ':' => { Ok(self.single_char_tok(TokenType::Colon)) }
            ';' => { Ok(self.single_char_tok(TokenType::Semicolon)) }
            c if c.is_digit(10) => { self.scan_int_or_float() }
            c if is_id_start(c) => { self.scan_id_or_keyword() }
            c   => { Err(Error::IllegalCharacter(self.curr_pos, c)) }
        }
    }

    // Scan digits into an Int or Float token.
    fn scan_int_or_float(&mut self) -> Result<Token, Error> {
        let mut val = String::new();
        while self.peek().is_digit(10) {
            val.push(self.advance());
        }

        if self.peek() != '.' {
            return Ok(self.lexeme_tok(TokenType::Int, val));
        }

        val.push(self.advance()); // Add decimal point.

        while self.peek().is_digit(10) {
            val.push(self.advance());
        }

        Ok(self.lexeme_tok(TokenType::Float, val))
    }

    // Scan alpha-numeric characters into an Id or a keyword token.
    fn scan_id_or_keyword(&mut self) -> Result<Token, Error> {
        let mut lexeme = String::new();
        while is_id_char(self.peek()) {
            lexeme.push(self.advance());
        }

        let token_type = match &*lexeme {
            "if" => TokenType::If,
            "then" => TokenType::Then,
            "else" => TokenType::Else,
            "end" => TokenType::End,
            "while" => TokenType::While,
            "do" => TokenType::Do,
            "done" => TokenType::Done,
            "read" => TokenType::Read,
            "print" => TokenType::Print,
            "var" => TokenType::Var,
            "int" => TokenType::TypeInt,
            "float" => TokenType::TypeFloat,
            _ => TokenType::Id,
        };

        let token = if token_type == TokenType::Id {
            self.lexeme_tok(token_type, lexeme)
        } else {
            self.empty_tok(token_type)
        };

        Ok(token)
    }

    fn skip_comments_and_whitespace(&mut self) {
        loop {
            self.skip_whitespace();
            if self.peek() == '#' {
                self.skip_comment();
            } else {
                break;
            }
        }
    }

    fn skip_whitespace(&mut self) {
        while self.peek().is_whitespace() {
            self.advance();
        }
    }

    fn skip_comment(&mut self) {
        while self.peek() != '\n' {
            self.advance();
        }
    }

    fn empty_tok(&self, t: TokenType) -> Token {
        let t = Token {
            typ: t,
            lexeme: None,
            pos: self.start_pos,
        };
        t
    }

    fn lexeme_tok(&self, t: TokenType, lexeme: String) -> Token {
        let t = Token {
            typ: t,
            lexeme: Some(lexeme),
            pos: self.start_pos,
        };
        t
    }

    fn single_char_tok(&mut self, t: TokenType) -> Token {
        let t = self.empty_tok(t);
        self.advance();
        t
    }
}

fn is_id_start(c: char) -> bool {
    (c >= 'a' && c <= 'z') ||
    c == '_' ||
    (c >= 'A' && c <= 'Z')
}

fn is_id_char(c: char) -> bool {
    (c >= 'a' && c <= 'z') ||
    c == '_' ||
    c.is_digit(10) ||
    (c >= 'A' && c <= 'Z')
}
<|endoftext|>