<commit_before>/*! Hex map display demo */

extern crate num;
extern crate rustc_serialize;
extern crate image;
extern crate tiled;

#[macro_use] extern crate calx_ecs;
extern crate calx;

mod cmd;
mod render;
mod spr;
mod world;

use std::convert::{Into};
use std::collections::{HashSet};
use calx_ecs::{Entity};
use calx::backend::{CanvasBuilder, CanvasUtil, Event, MouseButton, Key};
use calx::{V2, Rect, Rgba, color, Dir6};
use calx::{Projection, Kernel, KernelTerrain};

use spr::Spr;
use render::RenderTerrain;
use world::World;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum Terrain {
    Floor,
    Grass,
    Water,
    Tree,
    Wall,
    Door,
    Window,
    Magma,
    Rock,
    Void,
}

impl Terrain {
    pub fn new(id: u8) -> Terrain {
        // Tiled indexes start from 1.
        let id = id - 1;
        assert!(id <= Terrain::Rock as u8);
        unsafe {
            std::mem::transmute(id)
        }
    }

    pub fn can_walk(self) -> bool {
        use Terrain::*;
        match self {
            Floor | Grass | Door => true,
            _ => false,
        }
    }
}

impl KernelTerrain for Terrain {
    fn is_wall(&self) -> bool {
        use Terrain::*;
        match *self {
            Wall | Door | Window => true,
            _ => false
        }
    }

    fn is_block(&self) -> bool { *self == Terrain::Rock }
}

pub struct Sprite {
    pub spr: Spr,
    pub fore: Rgba,
    pub back: Rgba,
    pub pos: V2<f32>,

    sort_key: (i8, i32),
}

impl Sprite {
    pub fn new<A: Into<Rgba>, B: Into<Rgba>>(spr: Spr, pos: V2<f32>, layer: i8, fore: A, back: B) -> Sprite {
        Sprite {
            spr: spr,
            fore: fore.into(),
            back: back.into(),
            pos: pos,
            sort_key: (layer, -pos.1 as i32)
        }
    }

    #[inline]
    pub fn cmp(&self, other: &Sprite) -> std::cmp::Ordering {
        // Cmp backwards, draw order is from large (far away) to small (close by) values.
        other.sort_key.cmp(&self.sort_key)
    }
}

fn unit_focus_sprites(screen_pos: V2<f32>) -> Vec<Sprite> {
    let mut ret = Vec::new();
    let color = color::LIME;
    for idx in 0..6 {
        ret.push(Sprite::new(Spr::EdgeNW + idx, screen_pos, 0, color, color::BLACK));
    }
    ret
}

fn main() {
    let scroll_speed = 8f32;
    let mut screen_offset = V2(320.0f32, 0.0f32);
    let mut scroll_delta = V2(0.0f32, 0.0f32);
    let mut mouse_cell = V2(-1, -1);
    let mut mouse_pos = V2(-1.0f32, -1.0f32);
    let mut rect1 = V2(-1.0f32, -1.0f32);

    let mut world = World::new();
    let mut active: HashSet<Entity> = HashSet::new();
    let mut rect_drag = None;

    let mut paused = false;

    let tmx = include_str!("../assets/hexworld.tmx");
    world.load(&tiled::parse(tmx.as_bytes()).unwrap());

    let screen_rect = Rect(V2(-32.0f32, -32.0f32), V2(640.0f32 + 64.0, 360.0f32 + 64.0));
    let mut builder = CanvasBuilder::new()
        .set_size(640, 360)
        .set_frame_interval(0.033f64)
        ;
    Spr::init(&mut builder);
    let mut ctx = builder.build();

    let mut proj = Projection::new(V2(16.0, 8.0), V2(-16.0, 8.0)).unwrap()
        .view_offset(screen_offset);
    loop {
        match ctx.next_event() {
            Event::RenderFrame => {
                screen_offset = screen_offset - scroll_delta;

                let mut sprites = Vec::new();

                proj = Projection::new(V2(16.0, 8.0), V2(-16.0, 8.0)).unwrap()
                    .view_offset(screen_offset);

                for pt in proj.inv_project_rectangle(&screen_rect).iter() {
                    let pos = proj.project(pt);
                    Kernel::new(|p| world.terrain_at(p), pt.map(|x| x as i32)).render(
                        |layer, spr, fore, back| {
                            sprites.push(Sprite::new(spr, pos, layer, fore, back));
                        });
                }

                for &e in world.ecs.iter() {
                    if let Some(spr) = cmd::sprite(&world, e, &proj) {
                        // Highlight reticle on focused unit.
                        if active.contains(&e) {
                            for s in unit_focus_sprites(spr.pos).into_iter() {
                                sprites.push(s);
                            }
                        }
                        sprites.push(spr);
                    }
                }

                sprites.sort_by(|a, b| a.cmp(&b));
                for spr in sprites.iter() {
                    ctx.draw_image(spr.spr.get(), spr.pos, 0.5, spr.fore, spr.back);
                }

                if rect_drag == Some(Drag::Moving) {
                    let rect = Rect::from_points(mouse_pos, rect1);
                    ctx.draw_rect(&rect, 0.2, color::CYAN);
                }

                if paused {
                    world.update_standby();
                } else {
                    world.update_active();
                }
            }

            Event::Quit => { return; }

            Event::KeyPressed(Key::Escape) => { return; }

            Event::KeyPressed(Key::F12) => {
                ctx.save_screenshot(&"azag");
            }

            Event::KeyPressed(k) => {
                match k {
                    Key::J => { scroll_delta.0 = -1.0 * scroll_speed; }
                    Key::L => { scroll_delta.0 =  1.0 * scroll_speed; }
                    Key::I => { scroll_delta.1 = -1.0 * scroll_speed; }
                    Key::K => { scroll_delta.1 =  1.0 * scroll_speed; }

                    // XXX: Okay, we need a state object here.
                    Key::W => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::North);
                        }
                    }

                    Key::E => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::NorthEast);
                        }
                    }
                    Key::D => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::SouthEast);
                        }
                    }
                    Key::S => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::South);
                        }
                    }
                    Key::A => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::SouthWest);
                        }
                    }
                    Key::Q => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::NorthWest);
                        }
                    }
                    Key::Space => { paused = !paused; }
                    _ => {}
                }
            }

            Event::KeyReleased(k) => {
                match k {
                    Key::J => { scroll_delta.0 = 0.0; }
                    Key::L => { scroll_delta.0 = 0.0; }
                    Key::I => { scroll_delta.1 = 0.0; }
                    Key::K => { scroll_delta.1 = 0.0; }
                    _ => {}
                }
            }
            Event::MouseMoved((x, y)) => {
                mouse_pos = V2(x, y).map(|x| x as f32);
                mouse_cell = proj.inv_project(mouse_pos).map(|x| x.floor() as i32);
                if rect_drag == Some(Drag::Click) {
                    let dist = rect1 - mouse_pos;
                    // Need to move past a threshold distance before we switch
                    // from click-selecting to rect-selecting.
                    if dist.dot(dist) > 16.0 {
                        rect_drag = Some(Drag::Moving);
                    }
                }
            }

            Event::MousePressed(MouseButton::Left) => {
                rect_drag = Some(Drag::Click);
                rect1 = mouse_pos;
            }

            Event::MouseReleased(MouseButton::Left) => {
                // Insert player units in select rectangle into selection.
                active.clear();
                match rect_drag {
                    Some(Drag::Moving) => {
                        let cell_rect = Rect(V2(-8f32, -8f32), V2(16f32, 8f32));
                        let select_rect = Rect::from_points(mouse_pos, rect1);

                        for pt in proj.inv_project_rectangle(&select_rect).iter() {
                            if !select_rect.intersects(&(cell_rect + proj.project(pt))) { continue; }

                            let pos = pt.map(|x| x.floor() as i32);

                            match cmd::mob_at(&world, pos) {
                                Some(e) if cmd::is_player(&world, e) => {
                                    active.insert(e);
                                }
                                _ => {}
                            }
                        }
                    }
                    _ => {
                        if let Some(p) = cmd::mob_at(&world, mouse_cell) {
                            active.insert(p);
                        }
                    }
                }
                rect_drag = None;
            }

            Event::MousePressed(MouseButton::Right) => {
                for &p in active.iter() {
                    if cmd::is_player(&world, p) {
                        cmd::move_to(&mut world, p, mouse_cell);
                    }
                }
            }

            _ => {}
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
enum Drag {
    Click,
    Moving,
}

fn activate_rogue(active: &mut HashSet<Entity>) -> Entity {
    let &player = active.iter().next().unwrap();
    active.clear();
    active.insert(player);
    player
}
<commit_msg>Fix some movement jitter from sprite pos inaccuracy<commit_after>/*! Hex map display demo */

extern crate num;
extern crate rustc_serialize;
extern crate image;
extern crate tiled;

#[macro_use] extern crate calx_ecs;
extern crate calx;

mod cmd;
mod render;
mod spr;
mod world;

use std::convert::{Into};
use std::collections::{HashSet};
use calx_ecs::{Entity};
use calx::backend::{CanvasBuilder, CanvasUtil, Event, MouseButton, Key};
use calx::{V2, Rect, Rgba, color, Dir6};
use calx::{Projection, Kernel, KernelTerrain};

use spr::Spr;
use render::RenderTerrain;
use world::World;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum Terrain {
    Floor,
    Grass,
    Water,
    Tree,
    Wall,
    Door,
    Window,
    Magma,
    Rock,
    Void,
}

impl Terrain {
    pub fn new(id: u8) -> Terrain {
        // Tiled indexes start from 1.
        let id = id - 1;
        assert!(id <= Terrain::Rock as u8);
        unsafe {
            std::mem::transmute(id)
        }
    }

    pub fn can_walk(self) -> bool {
        use Terrain::*;
        match self {
            Floor | Grass | Door => true,
            _ => false,
        }
    }
}

impl KernelTerrain for Terrain {
    fn is_wall(&self) -> bool {
        use Terrain::*;
        match *self {
            Wall | Door | Window => true,
            _ => false
        }
    }

    fn is_block(&self) -> bool { *self == Terrain::Rock }
}

pub struct Sprite {
    pub spr: Spr,
    pub fore: Rgba,
    pub back: Rgba,
    pub pos: V2<f32>,

    sort_key: (i8, i32),
}

impl Sprite {
    pub fn new<A: Into<Rgba>, B: Into<Rgba>>(spr: Spr, pos: V2<f32>, layer: i8, fore: A, back: B) -> Sprite {
        // Fix some numerical inaccuracy noise.
        let pos = pos.map(|x| x.round());
        Sprite {
            spr: spr,
            fore: fore.into(),
            back: back.into(),
            pos: pos,
            sort_key: (layer, -pos.1 as i32)
        }
    }

    #[inline]
    pub fn cmp(&self, other: &Sprite) -> std::cmp::Ordering {
        // Cmp backwards, draw order is from large (far away) to small (close by) values.
        other.sort_key.cmp(&self.sort_key)
    }
}

fn unit_focus_sprites(screen_pos: V2<f32>) -> Vec<Sprite> {
    let mut ret = Vec::new();
    let color = color::LIME;
    for idx in 0..6 {
        ret.push(Sprite::new(Spr::EdgeNW + idx, screen_pos, 0, color, color::BLACK));
    }
    ret
}

fn main() {
    let scroll_speed = 8f32;
    let mut screen_offset = V2(320.0f32, 0.0f32);
    let mut scroll_delta = V2(0.0f32, 0.0f32);
    let mut mouse_cell = V2(-1, -1);
    let mut mouse_pos = V2(-1.0f32, -1.0f32);
    let mut rect1 = V2(-1.0f32, -1.0f32);

    let mut world = World::new();
    let mut active: HashSet<Entity> = HashSet::new();
    let mut rect_drag = None;

    let mut paused = false;

    let tmx = include_str!("../assets/hexworld.tmx");
    world.load(&tiled::parse(tmx.as_bytes()).unwrap());

    let screen_rect = Rect(V2(-32.0f32, -32.0f32), V2(640.0f32 + 64.0, 360.0f32 + 64.0));
    let mut builder = CanvasBuilder::new()
        .set_size(640, 360)
        .set_frame_interval(0.033f64)
        ;
    Spr::init(&mut builder);
    let mut ctx = builder.build();

    let mut proj = Projection::new(V2(16.0, 8.0), V2(-16.0, 8.0)).unwrap()
        .view_offset(screen_offset);
    loop {
        match ctx.next_event() {
            Event::RenderFrame => {
                screen_offset = screen_offset - scroll_delta;

                let mut sprites = Vec::new();

                proj = Projection::new(V2(16.0, 8.0), V2(-16.0, 8.0)).unwrap()
                    .view_offset(screen_offset);

                for pt in proj.inv_project_rectangle(&screen_rect).iter() {
                    let pos = proj.project(pt);
                    Kernel::new(|p| world.terrain_at(p), pt.map(|x| x as i32)).render(
                        |layer, spr, fore, back| {
                            sprites.push(Sprite::new(spr, pos, layer, fore, back));
                        });
                }

                for &e in world.ecs.iter() {
                    if let Some(spr) = cmd::sprite(&world, e, &proj) {
                        // Highlight reticle on focused unit.
                        if active.contains(&e) {
                            for s in unit_focus_sprites(spr.pos).into_iter() {
                                sprites.push(s);
                            }
                        }
                        sprites.push(spr);
                    }
                }

                sprites.sort_by(|a, b| a.cmp(&b));
                for spr in sprites.iter() {
                    ctx.draw_image(spr.spr.get(), spr.pos, 0.5, spr.fore, spr.back);
                }

                if rect_drag == Some(Drag::Moving) {
                    let rect = Rect::from_points(mouse_pos, rect1);
                    ctx.draw_rect(&rect, 0.2, color::CYAN);
                }

                if paused {
                    world.update_standby();
                } else {
                    world.update_active();
                }
            }

            Event::Quit => { return; }

            Event::KeyPressed(Key::Escape) => { return; }

            Event::KeyPressed(Key::F12) => {
                ctx.save_screenshot(&"azag");
            }

            Event::KeyPressed(k) => {
                match k {
                    Key::J => { scroll_delta.0 = -1.0 * scroll_speed; }
                    Key::L => { scroll_delta.0 =  1.0 * scroll_speed; }
                    Key::I => { scroll_delta.1 = -1.0 * scroll_speed; }
                    Key::K => { scroll_delta.1 =  1.0 * scroll_speed; }

                    // XXX: Okay, we need a state object here.
                    Key::W => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::North);
                        }
                    }

                    Key::E => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::NorthEast);
                        }
                    }
                    Key::D => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::SouthEast);
                        }
                    }
                    Key::S => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::South);
                        }
                    }
                    Key::A => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::SouthWest);
                        }
                    }
                    Key::Q => {
                        if !active.is_empty() {
                            paused = true;
                            let rogue = activate_rogue(&mut active);
                            while !cmd::ready_to_act(&world, rogue) { world.update_active(); }
                            cmd::step(&mut world, rogue, Dir6::NorthWest);
                        }
                    }
                    Key::Space => { paused = !paused; }
                    _ => {}
                }
            }

            Event::KeyReleased(k) => {
                match k {
                    Key::J => { scroll_delta.0 = 0.0; }
                    Key::L => { scroll_delta.0 = 0.0; }
                    Key::I => { scroll_delta.1 = 0.0; }
                    Key::K => { scroll_delta.1 = 0.0; }
                    _ => {}
                }
            }
            Event::MouseMoved((x, y)) => {
                mouse_pos = V2(x, y).map(|x| x as f32);
                mouse_cell = proj.inv_project(mouse_pos).map(|x| x.floor() as i32);
                if rect_drag == Some(Drag::Click) {
                    let dist = rect1 - mouse_pos;
                    // Need to move past a threshold distance before we switch
                    // from click-selecting to rect-selecting.
                    if dist.dot(dist) > 16.0 {
                        rect_drag = Some(Drag::Moving);
                    }
                }
            }

            Event::MousePressed(MouseButton::Left) => {
                rect_drag = Some(Drag::Click);
                rect1 = mouse_pos;
            }

            Event::MouseReleased(MouseButton::Left) => {
                // Insert player units in select rectangle into selection.
                active.clear();
                match rect_drag {
                    Some(Drag::Moving) => {
                        let cell_rect = Rect(V2(-8f32, -8f32), V2(16f32, 8f32));
                        let select_rect = Rect::from_points(mouse_pos, rect1);

                        for pt in proj.inv_project_rectangle(&select_rect).iter() {
                            if !select_rect.intersects(&(cell_rect + proj.project(pt))) { continue; }

                            let pos = pt.map(|x| x.floor() as i32);

                            match cmd::mob_at(&world, pos) {
                                Some(e) if cmd::is_player(&world, e) => {
                                    active.insert(e);
                                }
                                _ => {}
                            }
                        }
                    }
                    _ => {
                        if let Some(p) = cmd::mob_at(&world, mouse_cell) {
                            active.insert(p);
                        }
                    }
                }
                rect_drag = None;
            }

            Event::MousePressed(MouseButton::Right) => {
                for &p in active.iter() {
                    if cmd::is_player(&world, p) {
                        cmd::move_to(&mut world, p, mouse_cell);
                    }
                }
            }

            _ => {}
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
enum Drag {
    Click,
    Moving,
}

fn activate_rogue(active: &mut HashSet<Entity>) -> Entity {
    let &player = active.iter().next().unwrap();
    active.clear();
    active.insert(player);
    player
}
<|endoftext|>


<commit_before>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection
    NoIntersection
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Origin {
    pub fn new(x: c_int, y: c_int) -> Self {
        Origin { x, y }
    }
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

impl Into<Area> for Origin {
    fn into(self) -> Area {
        Area::new(self, Size::default())
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Size {
    pub fn new(width: c_int, height: c_int) -> Self {
        Size { width, height }
    }
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

impl Into<Area> for Size {
    fn into(self) -> Area {
        Area::new(Origin::default(), self)
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty = wlr_box_intersection(&self.0, &other_box.0, &mut res.0);
            if is_empty {
                IntersectionResult::NoIntersection
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self,
                     transform: wl_output_transform,
                     width: c_int,
                     height: c_int)
                     -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, width, height, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<commit_msg>Added with_{origin,size} to Area<commit_after>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection
    NoIntersection
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Origin {
    pub fn new(x: c_int, y: c_int) -> Self {
        Origin { x, y }
    }
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

impl Into<Area> for Origin {
    fn into(self) -> Area {
        Area::new(self, Size::default())
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Size {
    pub fn new(width: c_int, height: c_int) -> Self {
        Size { width, height }
    }
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

impl Into<Area> for Size {
    fn into(self) -> Area {
        Area::new(Origin::default(), self)
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Makes a new `Area` with width and height set to the values in the given
    /// `Size`.
    pub fn with_size(self, size: Size) -> Self {
        Area(wlr_box { width: size.width,
                       height: size.height,
                       ..self.0 })
    }

    /// Makes a new `Area` with x and y set to the value in the given `Origin`.
    pub fn with_origin(self, origin: Origin) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       ..self.0 })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty = wlr_box_intersection(&self.0, &other_box.0, &mut res.0);
            if is_empty {
                IntersectionResult::NoIntersection
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self,
                     transform: wl_output_transform,
                     width: c_int,
                     height: c_int)
                     -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, width, height, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_ends(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            match level[(x,y)] {
                Some(n) => {
                    match n {
                        Tile::Floor => {
                            if is_deadend(level, x, y) {
                                deadends.push((x,y));
                            }
                        },
                        _ => {},
                    }
                },
                None => {},
            }
        }
    }

    for (x,y) in deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Floor;
        }
    }
    deadends.is_empty()
}

pub fn is_deadend(level: &mut Level, x: usize, y: usize) -> bool {
    use util::Direction;
    use std::num;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        match level[coord] {
            Some(tile) => {
                match tile {
                    Tile::Floor => paths+=1,
                    _ => {},
                }
            }
            None => {}
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<commit_msg>replaced bunch of matches with if lets<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_ends(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }

    for (x,y) in deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Floor;
        }
    }
    deadends.is_empty()
}

pub fn is_deadend(level: &Level, x: usize, y: usize) -> bool {
    use util::Direction;
    use std::num;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor) = level[coord] {
            paths += 1;
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use common::Atom;

enum LexerErrorCode {
    InvalidSyntax,
    TrailingCharacters,
    EOFWhileReadingToken,
}

enum LexerError {
    SyntaxError {
        code: LexerErrorCode,
        line: usize,
        col: usize,
    }
}

#[derive(Debug, PartialEq)]
enum ParseAtomError {
    IncorrectSymbolName
}

impl FromStr for Atom {
    type Err = ParseAtomError;

    fn from_str(s: &str) -> Result<Atom, ParseAtomError> {
        match s.parse::<f64>() {
            Ok(f) => {
                Ok(Atom::Number(f))
            },
            _ => {
                match s.chars().next() {
                    Some(c) if !c.is_numeric() => {
                        Ok(Atom::Symbol(s.to_string()))
                    },
                    _ => {
                        Err(ParseAtomError::IncorrectSymbolName)
                    }
                }
            }
        }
    }
}

enum Token {
    Nil,
    Number(f64),
    String(String),
    Error(LexerError),
}

enum LexerState {
    Start,
    BeforeFinish,
    Finish,
}

pub struct Lexer<T> {
    reader: T,
    cur_char: Option<char>,
    line: usize,
    col: usize,
    state: LexerState
}

impl<T: Iterator<Item=char>> Iterator for Lexer<T> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.state {
            LexerState::Finish => {
                None
            },
            LexerState::BeforeFinish => {
                self.read_whitespaces();
                self.cur_char
                    .and(Some(self.error_token(LexerErrorCode::TrailingCharacters)))
                    .or_else(|| { self.state = LexerState::Finish; None })
            },
            _ => {
                Some(self.read())
            }
        }
    }
}

impl<T: Iterator<Item=char>> Lexer<T> {
    fn new(reader: T) -> Lexer<T> {
        let mut l = Lexer {
            reader: reader,
            cur_char: None,
            line: 1,
            col: 0,
            state: LexerState::Start
        };
        l.bump();
        l
    }

    fn read(&mut self) -> Token {
        loop {
            self.read_whitespaces();
            match self.state {
                LexerState::Start => {
                    return self.read_start()
                },
                _ => {
                    return self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        }
    }

    fn read_start(&mut self) -> Token {
        let token = self.read_token();
        self.state = match token {
            Token::Error(_) => {
                LexerState::Finish
            },
            _ => LexerState::BeforeFinish,
        };
        token
    }

    fn read_token(&mut self) -> Token {
        if let Some(c) = self.cur_char {
            match c {
                'n' => {
                    self.read_ident("il", Token::Nil)
                },
                '0' ... '9' | '-' => {
                    self.read_number()
                },
                '"' => {
                    self.read_string()
                },
                _ => {
                    self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        } else {
            self.error_token(LexerErrorCode::EOFWhileReadingToken)
        }
    }

    fn read_ident(&mut self, ident: &str, token: Token) -> Token {
        if ident.chars().all(|c| { self.bump(); Some(c) == self.cur_char }) {
            self.bump();
            token
        } else {
            self.error_token(LexerErrorCode::InvalidSyntax)
        }
    }

    fn read_number(&mut self) -> Token {
        Token::Number(0.)
    }

        Ok(Token::String("".to_string()))
    fn read_string(&mut self) -> Token {
    }

    fn read_whitespaces(&mut self) {
        while let Some(ch) = self.cur_char {
            if [' ', '\n', '\r', '\t'].contains(&ch) {
                self.bump()
            } else {
                break
            }
        }
    }

    fn bump(&mut self) {
        self.cur_char = self.reader.next();
        if Some('\n') == self.cur_char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn error_token(&mut self, ec: LexerErrorCode) -> Token {
        self.state = LexerState::Finish;
        Token::Error(LexerError::SyntaxError {
            code: ec,
            line: self.line,
            col: self.col
        })
    }
}

fn tokenize(s: &str) -> Vec<String> {
    s.replace("("," ( ")
        .replace(")", " ) ")
        .replace("\n", " ")
        .split(' ')
        .filter(|s| { !s.is_empty() })
        .map(|s| { s.to_string() })
        .collect()
}

#[cfg(test)]
mod tests {
    use common::Atom::{self, Symbol, Number};
    use super::Lexer;
    use super::ParseAtomError::IncorrectSymbolName;
    use super::tokenize;

    #[test]
    fn test_read_integer() {
        assert_eq!(Number(64f64), "64".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_read_float() {
        assert_eq!(Number(64.5), "64.5".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_read_symbol() {
        assert_eq!(Symbol("name".to_string()), "name".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_read_incorrect_symbol_starting_with_digit() {
        assert_eq!(IncorrectSymbolName, "6name".parse::<Atom>().err().unwrap())
    }

    #[test]
    fn test_read_dense_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize("(def a 1)"))
    }

    #[test]
    fn test_read_sparse_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize(" ( \n def a\n1)   \n"))
    }
}
<commit_msg>Implement tokenizing for integer part of number and strings without error handling<commit_after>use std::str::FromStr;
use common::Atom;

#[derive(Debug, PartialEq)]
enum LexerErrorCode {
    InvalidSyntax,
    TrailingCharacters,
    EOFWhileReadingToken,
}

#[derive(Debug, PartialEq)]
enum LexerError {
    SyntaxError {
        code: LexerErrorCode,
        line: usize,
        col: usize,
    }
}

#[derive(Debug, PartialEq)]
enum ParseAtomError {
    IncorrectSymbolName
}

impl FromStr for Atom {
    type Err = ParseAtomError;

    fn from_str(s: &str) -> Result<Atom, ParseAtomError> {
        match s.parse::<f64>() {
            Ok(f) => {
                Ok(Atom::Number(f))
            },
            _ => {
                match s.chars().next() {
                    Some(c) if !c.is_numeric() => {
                        Ok(Atom::Symbol(s.to_string()))
                    },
                    _ => {
                        Err(ParseAtomError::IncorrectSymbolName)
                    }
                }
            }
        }
    }
}

#[derive(Debug, PartialEq)]
enum Token {
    Nil,
    Number(f64),
    String(String),
    Error(LexerError),
}

enum LexerState {
    Start,
    BeforeFinish,
    Finish,
}

pub struct Lexer<T> {
    reader: T,
    cur_char: Option<char>,
    line: usize,
    col: usize,
    state: LexerState
}

impl<T: Iterator<Item=char>> Iterator for Lexer<T> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.state {
            LexerState::Finish => {
                None
            },
            LexerState::BeforeFinish => {
                self.read_whitespaces();
                self.cur_char
                    .and(Some(self.error_token(LexerErrorCode::TrailingCharacters)))
                    .or_else(|| { self.state = LexerState::Finish; None })
            },
            _ => {
                Some(self.read())
            }
        }
    }
}

impl<T: Iterator<Item=char>> Lexer<T> {
    fn new(reader: T) -> Lexer<T> {
        let mut l = Lexer {
            reader: reader,
            cur_char: None,
            line: 1,
            col: 0,
            state: LexerState::Start
        };
        l.bump();
        l
    }

    fn read(&mut self) -> Token {
        loop {
            self.read_whitespaces();
            match self.state {
                LexerState::Start => {
                    return self.read_start()
                },
                _ => {
                    return self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        }
    }

    fn read_start(&mut self) -> Token {
        let token = self.read_token();
        self.state = match token {
            Token::Error(_) => {
                LexerState::Finish
            },
            _ => LexerState::BeforeFinish,
        };
        token
    }

    fn read_token(&mut self) -> Token {
        if let Some(c) = self.cur_char {
            match c {
                'n' => {
                    self.read_ident("il", Token::Nil)
                },
                '0' ... '9' | '-' => {
                    self.read_number()
                },
                '"' => {
                    self.read_string()
                },
                _ => {
                    self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        } else {
            self.error_token(LexerErrorCode::EOFWhileReadingToken)
        }
    }

    fn read_ident(&mut self, ident: &str, token: Token) -> Token {
        if ident.chars().all(|c| { self.bump(); Some(c) == self.cur_char }) {
            self.bump();
            token
        } else {
            self.error_token(LexerErrorCode::InvalidSyntax)
        }
    }

    fn read_number(&mut self) -> Token {
        let mut neg = false;

        if let Some('-') = self.cur_char {
            self.bump();
            neg = true;
        }

        let mut accum = 0_f64;

        while let Some(c) = self.cur_char {
            match c {
                '0' ... '9' => {
                    let c_as_usize = (c as usize) - ('0' as usize);
                    accum *= 10_f64;
                    accum += c_as_usize as f64;
                    self.bump()
                },
                _ => {
                    break
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        Token::Number(accum)
    }

    fn read_string(&mut self) -> Token {
        let mut res = String::new();

        self.bump();

        while let Some(c) = self.cur_char {
            match c {
                '"' => {
                    break
                },
                _ => {
                    res.push(c);
                }
            }
            self.bump();
        }

        self.bump();

        Token::String(res)
    }

    fn read_whitespaces(&mut self) {
        while let Some(ch) = self.cur_char {
            if [' ', '\n', '\r', '\t'].contains(&ch) {
                self.bump()
            } else {
                break
            }
        }
    }

    fn bump(&mut self) {
        self.cur_char = self.reader.next();
        if Some('\n') == self.cur_char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn error_token(&mut self, ec: LexerErrorCode) -> Token {
        self.state = LexerState::Finish;
        Token::Error(LexerError::SyntaxError {
            code: ec,
            line: self.line,
            col: self.col
        })
    }
}

fn tokenize(s: &str) -> Vec<String> {
    s.replace("("," ( ")
        .replace(")", " ) ")
        .replace("\n", " ")
        .split(' ')
        .filter(|s| { !s.is_empty() })
        .map(|s| { s.to_string() })
        .collect()
}

#[cfg(test)]
mod tests {
    use common::Atom::{self, Symbol, Number};
    use super::{Lexer, Token};
    use super::ParseAtomError::IncorrectSymbolName;
    use super::tokenize;

    #[test]
    fn test_read_integer_as_f64() {
        let mut lexer = Lexer::new("64".chars());
        assert_eq!(Some(Token::Number(64_f64)), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_string() {
        let s = "rust is beautiful".to_string();
        let actual_input = format!(r#""{}""#, s);
        let mut lexer = Lexer::new(actual_input.chars());
        assert_eq!(Some(Token::String(s)), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_float() {
        assert_eq!(Number(64.5), "64.5".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_read_symbol() {
        assert_eq!(Symbol("name".to_string()), "name".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_read_incorrect_symbol_starting_with_digit() {
        assert_eq!(IncorrectSymbolName, "6name".parse::<Atom>().err().unwrap())
    }

    #[test]
    fn test_read_dense_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize("(def a 1)"))
    }

    #[test]
    fn test_read_sparse_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize(" ( \n def a\n1)   \n"))
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq, Copy)]
enum LexerErrorCode {
    InvalidSyntax,
    TrailingCharacters,
    EOFWhileReadingToken,
}

#[derive(Debug, PartialEq, Copy)]
pub enum LexerError {
    SyntaxError {
        code: LexerErrorCode,
        line: usize,
        col: usize,
    }
}

#[derive(Debug, PartialEq)]
pub enum Token {
    Number(f64),
    String(String),
    Symbol(String),
    ListStart,
    ListEnd,
}

#[derive(Debug, PartialEq)]
pub enum LexerEvent {
    Token(Token),
    Error(LexerError),
}

#[derive(Debug, PartialEq)]
enum LexerState {
    Start,
    ReadList,
    BeforeFinish,
    Finish,
}

pub struct Lexer<T> {
    reader: T,
    cur_char: Option<char>,
    line: usize,
    col: usize,
    state: LexerState,
    lvl: isize,
}

impl<T: Iterator<Item=char>> Iterator for Lexer<T> {
    type Item = LexerEvent;

    fn next(&mut self) -> Option<LexerEvent> {
        match self.state {
            LexerState::BeforeFinish => {
                self.consume_whitespaces();
                match self.cur_char {
                    Some(_) => {
                        Some(self.emit_syntax_error(LexerErrorCode::TrailingCharacters))
                    },
                    None => {
                        self.state = LexerState::Finish;
                        None
                    }
                }
            },
            LexerState::Finish => {
                None
            },
            _ => {
                Some(self.emit())
            }
        }
    }
}

impl<T: Iterator<Item=char>> Lexer<T> {
    pub fn new(reader: T) -> Lexer<T> {
        let mut l = Lexer {
            reader: reader,
            cur_char: None,
            line: 1,
            col: 0,
            state: LexerState::Start,
            lvl: 0,
        };
        l.bump();
        l
    }

    fn bump(&mut self) {
        self.cur_char = self.reader.next();
        if Some('\n') == self.cur_char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn emit(&mut self) -> LexerEvent {
        loop {
            self.consume_whitespaces();
            match self.state {
                LexerState::Start => {
                    return self.emit_at_start()
                },
                LexerState::ReadList => {
                    return self.emit_at_read_list()
                },
                _ => {
                    return self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        }
    }

    fn emit_at_start(&mut self) -> LexerEvent {
        let evt = self.emit_next();
        self.state = match evt {
            LexerEvent::Token(Token::ListStart) => {
                LexerState::ReadList
            },
            LexerEvent::Error(_) => {
                LexerState::Finish
            },
            _ => {
                LexerState::BeforeFinish
            },
        };
        evt
    }

    fn emit_next(&mut self) -> LexerEvent {
        if let Some(c) = self.cur_char {
            match c {
                'a' ... 'z' | 'A' ... 'Z' | '+' => {
                    self.emit_symbol()
                },
                '0' ... '9' | '-' => {
                    self.emit_number()
                },
                '"' => {
                    self.emit_string()
                },
                '(' => {
                    self.bump();
                    self.emit_token(Token::ListStart)
                },
                ')' => {
                    self.bump();
                    self.emit_token(Token::ListEnd)
                },
                _ => {
                    self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        } else {
            self.emit_syntax_error(LexerErrorCode::EOFWhileReadingToken)
        }
    }

    fn emit_symbol(&mut self) -> LexerEvent {
        let mut res = String::new();

        while let Some(c) = self.cur_char {
            if c.is_whitespace() {
                break
            } else {
                res.push(c)
            }
            self.bump();
        }

        self.emit_token(Token::Symbol(res))
    }

    fn emit_number(&mut self) -> LexerEvent {
        let mut neg = false;

        if Some('-') == self.cur_char {
            neg = true;
            self.bump();
        }

        let mut accum = 0_f64;

        while let Some(c) = self.cur_char {
            match c {
                '0' ... '9' => {
                    let c_as_usize = (c as usize) - ('0' as usize);
                    accum *= 10_f64;
                    accum += c_as_usize as f64;
                    self.bump()
                },
                '.' => {
                    self.bump();

                    let mut dec = 1.0;
                    while let Some(c) = self.cur_char {
                        match c {
                            '0' ... '9' => {
                                let c_as_usize = (c as usize) - ('0' as usize);
                                dec /= 10.0;
                                accum += (c_as_usize as f64) * dec;
                                self.bump();
                            },
                            _ => {
                                break
                            }
                        }
                    }
                },
                ' ' | '\t' | '\r' | '\n' | ')' => {
                    break
                },
                _ => {
                    return self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        self.emit_token(Token::Number(accum))
    }

    fn emit_string(&mut self) -> LexerEvent {
        let mut res = String::new();

        self.bump();

        while let Some(c) = self.cur_char {
            if c == '"' {
                break
            } else {
                res.push(c)
            }
            self.bump();
        }

        self.bump();

        self.emit_token(Token::String(res))
    }

    fn emit_at_read_list(&mut self) -> LexerEvent {
        let evt = self.emit_next();
        match evt {
            LexerEvent::Token(Token::ListStart) => {
                self.lvl += 1;
            },
            LexerEvent::Token(Token::ListEnd) => {
                if self.lvl > 0 {
                    self.lvl -= 1;
                } else {
                    self.state = LexerState::BeforeFinish
                }
            },
            LexerEvent::Error(_) => {
                self.state = LexerState::Finish
            },
            _ => {}
        };
        evt
    }

    fn emit_token(&mut self, token: Token) -> LexerEvent {
        LexerEvent::Token(token)
    }

    fn emit_syntax_error(&mut self, ec: LexerErrorCode) -> LexerEvent {
        self.state = LexerState::Finish;
        LexerEvent::Error(LexerError::SyntaxError {
            code: ec,
            line: self.line,
            col: self.col
        })
    }

    fn consume_whitespaces(&mut self) {
        while let Some(c) = self.cur_char {
            if c.is_whitespace() {
                self.bump()
            } else {
                break
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Lexer, LexerEvent, Token, LexerError, LexerErrorCode};

    #[test]
    fn test_read_nil() {
        let sym_name = "nil".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(LexerEvent::Token(Token::Symbol(sym_name.clone()))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_integer_as_float() {
        let mut lexer = Lexer::new("64".chars());
        assert_eq!(Some(LexerEvent::Token(Token::Number(64_f64))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_float() {
        let mut lexer = Lexer::new("64.5".chars());
        assert_eq!(Some(LexerEvent::Token(Token::Number(64.5))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_string() {
        let s = "rust is beautiful".to_string();
        let actual_input = format!(r#""{}""#, s);
        let mut lexer = Lexer::new(actual_input.chars());
        assert_eq!(Some(LexerEvent::Token(Token::String(s))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_symbol() {
        let sym_name = "my-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(LexerEvent::Token(Token::Symbol(sym_name.clone()))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_incorrect_symbol_starting_with_digit() {
        let sym_name = "6-my-incorrect-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        let expected_result = Some(LexerEvent::Error(LexerError::SyntaxError {
            code: LexerErrorCode::InvalidSyntax,
            line: 1,
            col: 2
        }));
        assert_eq!(expected_result, lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_dense_expression() {
        let lexer = Lexer::new("(def a 1)".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_sparse_expression() {
        let lexer = Lexer::new(" ( \n def a\n1)   \n".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_nested_list_expressions() {
        let lexer = Lexer::new("(def a (+ 1 1))".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("+".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }
}
<commit_msg>Fix issue with last symbol in a list, add related test case<commit_after>#[derive(Debug, PartialEq, Copy)]
enum LexerErrorCode {
    InvalidSyntax,
    TrailingCharacters,
    EOFWhileReadingToken,
}

#[derive(Debug, PartialEq, Copy)]
pub enum LexerError {
    SyntaxError {
        code: LexerErrorCode,
        line: usize,
        col: usize,
    }
}

#[derive(Debug, PartialEq)]
pub enum Token {
    Number(f64),
    String(String),
    Symbol(String),
    ListStart,
    ListEnd,
}

#[derive(Debug, PartialEq)]
pub enum LexerEvent {
    Token(Token),
    Error(LexerError),
}

#[derive(Debug, PartialEq)]
enum LexerState {
    Start,
    ReadList,
    BeforeFinish,
    Finish,
}

pub struct Lexer<T> {
    reader: T,
    cur_char: Option<char>,
    line: usize,
    col: usize,
    state: LexerState,
    lvl: isize,
}

impl<T: Iterator<Item=char>> Iterator for Lexer<T> {
    type Item = LexerEvent;

    fn next(&mut self) -> Option<LexerEvent> {
        match self.state {
            LexerState::BeforeFinish => {
                self.consume_whitespaces();
                match self.cur_char {
                    Some(_) => {
                        Some(self.emit_syntax_error(LexerErrorCode::TrailingCharacters))
                    },
                    None => {
                        self.state = LexerState::Finish;
                        None
                    }
                }
            },
            LexerState::Finish => {
                None
            },
            _ => {
                Some(self.emit())
            }
        }
    }
}

impl<T: Iterator<Item=char>> Lexer<T> {
    pub fn new(reader: T) -> Lexer<T> {
        let mut l = Lexer {
            reader: reader,
            cur_char: None,
            line: 1,
            col: 0,
            state: LexerState::Start,
            lvl: 0,
        };
        l.bump();
        l
    }

    fn bump(&mut self) {
        self.cur_char = self.reader.next();
        if Some('\n') == self.cur_char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn emit(&mut self) -> LexerEvent {
        loop {
            self.consume_whitespaces();
            match self.state {
                LexerState::Start => {
                    return self.emit_at_start()
                },
                LexerState::ReadList => {
                    return self.emit_at_read_list()
                },
                _ => {
                    return self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        }
    }

    fn emit_at_start(&mut self) -> LexerEvent {
        let evt = self.emit_next();
        self.state = match evt {
            LexerEvent::Token(Token::ListStart) => {
                LexerState::ReadList
            },
            LexerEvent::Error(_) => {
                LexerState::Finish
            },
            _ => {
                LexerState::BeforeFinish
            },
        };
        evt
    }

    fn emit_next(&mut self) -> LexerEvent {
        if let Some(c) = self.cur_char {
            match c {
                'a' ... 'z' | 'A' ... 'Z' | '+' => {
                    self.emit_symbol()
                },
                '0' ... '9' | '-' => {
                    self.emit_number()
                },
                '"' => {
                    self.emit_string()
                },
                '(' => {
                    self.bump();
                    self.emit_token(Token::ListStart)
                },
                ')' => {
                    self.bump();
                    self.emit_token(Token::ListEnd)
                },
                _ => {
                    self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        } else {
            self.emit_syntax_error(LexerErrorCode::EOFWhileReadingToken)
        }
    }

    fn emit_symbol(&mut self) -> LexerEvent {
        let mut res = String::new();

        while let Some(c) = self.cur_char {
            if c.is_whitespace() || c == ')' {
                break
            } else {
                res.push(c)
            }
            self.bump();
        }

        self.emit_token(Token::Symbol(res))
    }

    fn emit_number(&mut self) -> LexerEvent {
        let mut neg = false;

        if Some('-') == self.cur_char {
            neg = true;
            self.bump();
        }

        let mut accum = 0_f64;

        while let Some(c) = self.cur_char {
            match c {
                '0' ... '9' => {
                    let c_as_usize = (c as usize) - ('0' as usize);
                    accum *= 10_f64;
                    accum += c_as_usize as f64;
                    self.bump()
                },
                '.' => {
                    self.bump();

                    let mut dec = 1.0;
                    while let Some(c) = self.cur_char {
                        match c {
                            '0' ... '9' => {
                                let c_as_usize = (c as usize) - ('0' as usize);
                                dec /= 10.0;
                                accum += (c_as_usize as f64) * dec;
                                self.bump();
                            },
                            _ => {
                                break
                            }
                        }
                    }
                },
                ' ' | '\t' | '\r' | '\n' | ')' => {
                    break
                },
                _ => {
                    return self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        self.emit_token(Token::Number(accum))
    }

    fn emit_string(&mut self) -> LexerEvent {
        let mut res = String::new();

        self.bump();

        while let Some(c) = self.cur_char {
            if c == '"' {
                break
            } else {
                res.push(c)
            }
            self.bump();
        }

        self.bump();

        self.emit_token(Token::String(res))
    }

    fn emit_at_read_list(&mut self) -> LexerEvent {
        let evt = self.emit_next();
        match evt {
            LexerEvent::Token(Token::ListStart) => {
                self.lvl += 1;
            },
            LexerEvent::Token(Token::ListEnd) => {
                if self.lvl > 0 {
                    self.lvl -= 1;
                } else {
                    self.state = LexerState::BeforeFinish
                }
            },
            LexerEvent::Error(_) => {
                self.state = LexerState::Finish
            },
            _ => {}
        };
        evt
    }

    fn emit_token(&mut self, token: Token) -> LexerEvent {
        LexerEvent::Token(token)
    }

    fn emit_syntax_error(&mut self, ec: LexerErrorCode) -> LexerEvent {
        self.state = LexerState::Finish;
        LexerEvent::Error(LexerError::SyntaxError {
            code: ec,
            line: self.line,
            col: self.col
        })
    }

    fn consume_whitespaces(&mut self) {
        while let Some(c) = self.cur_char {
            if c.is_whitespace() {
                self.bump()
            } else {
                break
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Lexer, LexerEvent, Token, LexerError, LexerErrorCode};

    #[test]
    fn test_read_nil() {
        let sym_name = "nil".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(LexerEvent::Token(Token::Symbol(sym_name.clone()))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_integer_as_float() {
        let mut lexer = Lexer::new("64".chars());
        assert_eq!(Some(LexerEvent::Token(Token::Number(64_f64))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_float() {
        let mut lexer = Lexer::new("64.5".chars());
        assert_eq!(Some(LexerEvent::Token(Token::Number(64.5))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_string() {
        let s = "rust is beautiful".to_string();
        let actual_input = format!(r#""{}""#, s);
        let mut lexer = Lexer::new(actual_input.chars());
        assert_eq!(Some(LexerEvent::Token(Token::String(s))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_symbol() {
        let sym_name = "my-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(LexerEvent::Token(Token::Symbol(sym_name.clone()))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_incorrect_symbol_starting_with_digit() {
        let sym_name = "6-my-incorrect-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        let expected_result = Some(LexerEvent::Error(LexerError::SyntaxError {
            code: LexerErrorCode::InvalidSyntax,
            line: 1,
            col: 2
        }));
        assert_eq!(expected_result, lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_dense_expression() {
        let lexer = Lexer::new("(def a 1)".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_sparse_expression() {
        let lexer = Lexer::new(" ( \n def a\n1)   \n".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_nested_list_expressions() {
        let lexer = Lexer::new("(def a (+ 1 1))".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("+".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_list_of_symbols() {
        let lexer = Lexer::new("(+ a b c)".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("+".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Symbol("b".to_string())),
                                   LexerEvent::Token(Token::Symbol("c".to_string())),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq, Clone)]
pub enum Token<'input> {
    LParen,
    RParen,
    Symbol(&'input str),
    Number(i64),
    EOF,
}

pub struct Lexer<'input> {
    pub s: &'input str,
    pub pos: usize,
    pub col: usize,
    pub line_num: usize,
    pub tok_buf: Option<Token<'input>>,
}

fn is_valid_in_symbol(c: char) -> bool {
    c.is_alphabetic() ||
    match c {
        '+' | '-' | '*' | '/' | '#' | '<' | '>' | '=' => true,
        _ => false,
    }
}

impl<'input> Lexer<'input> {
    pub fn new(source: &'input str) -> Lexer<'input> {
        Lexer { s: source,
                pos: 0,
                col: 0,
                line_num: 1,
                tok_buf: None}
    }

    pub fn get_token(&mut self) -> Token<'input> {
        if let Some(tok) = self.tok_buf.clone() {
            self.tok_buf = None;
            return tok;
        }
        else {
            let mut iter = self.s[self.pos..].chars().peekable();
            while let Some(&c) = iter.peek() {
                if c.is_numeric() {
                    let mut n = c;
                    let start = self.pos;
                    while n.is_numeric() {
                        iter.next();
                        self.pos += 1;
                        self.col += 1;
                        n = match iter.peek() {
                            Some(&x) => x,
                            None => break,
                        };
                    }
                    return Token::Number(self.s[start..self.pos].parse().unwrap());
                }
                else if is_valid_in_symbol(c) {
                    let mut s = c;
                    let start = self.pos;
                    while s.is_alphanumeric() || is_valid_in_symbol(s) {
                        iter.next();
                        self.pos += 1;
                        self.col += 1;
                        s = match iter.peek() {
                            Some(&x) => x,
                            None => break,
                        };
                    }
                    return Token::Symbol(&self.s[start..self.pos]);
                }
                else {
                    match c {
                        '\n' => {
                            iter.next();
                            self.pos += 1;
                            self.col = 0;
                            self.line_num += 1;
                            continue;
                        },
                        ';' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            while let Some(c) = iter.next() {
                                self.pos += 1;
                                if c.clone() == '\n' {
                                    break;
                                }
                            }
                            self.line_num += 1;
                            self.col = 0;
                        },
                        ' ' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            continue
                        },
                        '(' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            return Token::LParen
                        },
                        ')' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            return Token::RParen
                        },

                        _ => panic!("line {}:{} unexpected char: {}", self.line_num, self.col, c),
                    }
                }
            }
            return Token::EOF;
        }
    }
}

impl<'input> Iterator for Lexer<'input> {
    type Item = Token<'input>;

    fn next(&mut self) -> Option<Token<'input>> {
        match self.get_token() {
            Token::EOF => None,
            t => Some(t),
        }
    }
}
<commit_msg>Begin re-writing Parser<commit_after>#[derive(Debug, PartialEq, Clone)]
pub enum Token<'input> {
    LParen,
    RParen,
    Symbol(&'input str),
    Number(i64),
    EOF,
}

pub struct Lexer<'input> {
    pub s: &'input str,
    pub pos: usize,
    pub col: usize,
    pub line_num: usize,
    pub tok_buf: Option<Token<'input>>,
}

fn is_valid_in_symbol(c: char) -> bool {
    c.is_alphabetic() ||
    match c {
        '+' | '-' | '*' | '/' | '#' | '<' | '>' | '=' => true,
        _ => false,
    }
}

impl<'input> Lexer<'input> {
    pub fn new(source: &'input str) -> Lexer<'input> {
        Lexer { s: source,
                pos: 0,
                col: 0,
                line_num: 1,
                tok_buf: None}
    }

    pub fn unread(&mut self, tok: Token<'input>) {
        match self.tok_buf {
            Some(_) => panic!("error: unread buffer full"),
            None => self.tok_buf = Some(tok),
        }
    }

    pub fn get_token(&mut self) -> Token<'input> {
        if let Some(tok) = self.tok_buf.clone() {
            self.tok_buf = None;
            return tok;
        }
        else {
            let mut iter = self.s[self.pos..].chars().peekable();
            while let Some(&c) = iter.peek() {
                if c.is_numeric() {
                    let mut n = c;
                    let start = self.pos;
                    while n.is_numeric() {
                        iter.next();
                        self.pos += 1;
                        self.col += 1;
                        n = match iter.peek() {
                            Some(&x) => x,
                            None => break,
                        };
                    }
                    return Token::Number(self.s[start..self.pos].parse().unwrap());
                }
                else if is_valid_in_symbol(c) {
                    let mut s = c;
                    let start = self.pos;
                    while s.is_alphanumeric() || is_valid_in_symbol(s) {
                        iter.next();
                        self.pos += 1;
                        self.col += 1;
                        s = match iter.peek() {
                            Some(&x) => x,
                            None => break,
                        };
                    }
                    return Token::Symbol(&self.s[start..self.pos]);
                }
                else {
                    match c {
                        '\n' => {
                            iter.next();
                            self.pos += 1;
                            self.col = 0;
                            self.line_num += 1;
                            continue;
                        },
                        ';' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            while let Some(c) = iter.next() {
                                self.pos += 1;
                                if c.clone() == '\n' {
                                    break;
                                }
                            }
                            self.line_num += 1;
                            self.col = 0;
                        },
                        ' ' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            continue
                        },
                        '(' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            return Token::LParen
                        },
                        ')' => {
                            iter.next();
                            self.pos += 1;
                            self.col += 1;
                            return Token::RParen
                        },

                        _ => panic!("line {}:{} unexpected char: {}", self.line_num, self.col, c),
                    }
                }
            }
            return Token::EOF;
        }
    }
}

impl<'input> Iterator for Lexer<'input> {
    type Item = Token<'input>;

    fn next(&mut self) -> Option<Token<'input>> {
        match self.get_token() {
            Token::EOF => None,
            t => Some(t),
        }
    }
}

fn main() {
    #[derive(Debug)]
    pub enum Ast<'input> {
        Symbol(&'input str),
        Number(i64),
        Bool(bool),
        List(Vec<Ast<'input>>),
        FuncName(&'input str),  // for closure-conversion

        Define(&'input str, Vec<&'input str>, Box<Ast<'input>>),
    }

    pub struct Parser<'input> {
        lexer: Lexer<'input>
    }

    impl<'input> Parser<'input> {
        pub fn new(source: &'input str) -> Parser<'input> {
            Parser {
                lexer: Lexer::new(source)
            }
        }

        pub fn get_list(&mut self) -> Vec<Ast<'input>> {
            match self.get_expr() {
                Some(expr) => match self.lexer.next() {
                    None => vec![],
                    Some(Token::RParen) => vec![expr],
                    Some(tok) => {
                        self.lexer.unread(tok);
                        let mut seq = self.get_list();
                        seq.insert(0, expr);

                        return seq;
                    }
                },
                None => vec![],
            }
        }

        pub fn get_expr(&mut self) -> Option<Ast<'input>> {
            match self.lexer.next() {
                Some(Token::Symbol(s)) => Some(Ast::Symbol(s)),
                Some(Token::Number(n)) => Some(Ast::Number(n)),
                Some(Token::LParen) => Some(Ast::List(self.get_list())),
                Some(Token::RParen) => panic!("line {}: {} unmatched ')'",
                                              self.lexer.line_num,
                                              self.lexer.col),
                _ => None,
            }
        }

        pub fn get_ast(expr: &Ast<'input>) -> Ast<'input> {
            match expr {
                &Ast::Symbol(sym) =>
                    match &sym[..] {
                        "#f" => Ast::Bool(false),
                        "#t" => Ast::Bool(true),
                        _ => Ast::Symbol(sym)
                    },
                &Ast::List(ref elts) =>
                    match &elts[..] {
                        &[Ast::Symbol(k), Ast::List(ref defelts), ref body]
                            if k == "define" => {
                                let name = &defelts[0];
                                let args = &defelts[1..];

                                if let Ast::Symbol(name) = name {
                                    Ast::Define(name,
                                                vec![],
                                                Box::new(Parser::get_ast(&body)))
                                } else {
                                    panic!("invalid function prototype");
                                }
                            },
                        _ => Ast::Number(42),
                    },
                _ => Ast::Number(42),
            }
        }
    }

    let mut p = Parser::new("(define (foo x y) (+ (* 1 2) 2))");
    // println!("{:?}", p.get_expr());
    println!("{:?}", Parser::get_ast(&p.get_expr().unwrap()));
}
<|endoftext|>


<commit_before>
//
// FSUIPC library
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::ffi::CString;
use std::io;
use std::ptr;

use user32::{FindWindowExA, SendMessageTimeoutA};
use winapi::WM_USER;
use winapi::windef::HWND;
use winapi::winuser::SMTO_BLOCK;

use super::{Handle, Session};
use super::ipc::*;
use super::raw::MutRawBytes;

/// A handle to FSUIPc that uses local IPC communication to the FSUIPC module
/// This kind of handle must be used from code running in the same process as FSUIPC does.
pub struct LocalHandle {
    handle: HWND,
}

impl LocalHandle {
    pub fn new() -> io::Result<Self> {
        unsafe {
            let win_name = CString::new("UIPCMAIN").unwrap();
            let handle = FindWindowExA(
                ptr::null_mut(), ptr::null_mut(), win_name.as_ptr(), ptr::null_mut());
            if handle != ptr::null_mut() {
                Ok(LocalHandle { handle: handle })
            } else {
                Err(io::Error::new(
                    io::ErrorKind::ConnectionRefused,
                    "cannot connect to local FSUIPC: cannot create window handle"))
            }
        }
    }
}

impl<'a> Handle<'a> for LocalHandle {
    type Sess = LocalSession;

    fn session(&'a mut self) -> LocalSession {
        LocalSession::new(self.handle)
    }
}

pub struct LocalSession {
    handle: HWND,
    buffer: io::Cursor<Vec<u8>>,
}

impl LocalSession {
    fn new(handle: HWND) -> Self {
        let mut session = LocalSession {
            handle: handle,
            buffer: io::Cursor::new(Vec::with_capacity(4096))
        };
        // First 4-bytes seems to be for a stack frame pointer that is not actually used
        session.buffer.set_position(4);
        session
    }
}

impl Session for LocalSession {
    fn read_bytes(&mut self, offset: u16, dest: *mut u8, len: usize) -> io::Result<usize> {
        self.buffer.write_rsd(offset, dest, len)
    }

    fn write_bytes(&mut self, offset: u16, src: *const u8, len: usize) -> io::Result<usize> {
        self.buffer.write_wsd(offset, src, len)
    }

    fn process(mut self) -> io::Result<usize> {
        unsafe {
            try!(self.buffer.write_header(&MsgHeader::TerminationMark));
            let nbytes = self.buffer.position() as usize;
            let buff = self.buffer.get_ref().as_ptr() as i32;
            let mut process_result: u32 = 0;
            let send_result = SendMessageTimeoutA(
                self.handle,
                WM_IPCTHREADACCESS,
                nbytes as u32,
                buff,
                SMTO_BLOCK,
                WM_IPC_TIMEOUT,
                &mut process_result as *mut u32);
            if send_result == 0 {
                return Err(io::Error::new(
                    io::ErrorKind::TimedOut,
                    "timed out while waiting for a response from FSUIPC"));
            }
            if process_result != FS6IPC_MESSAGE_SUCCESS {
                return Err(io::Error::new(io::ErrorKind::InvalidData, format!(
                    "FSUIPC rejected the requests with error {}; possible buffer corruption in bytes: {:?}",
                    send_result, self.buffer.get_ref())));
            }
            // First 4-bytes seems to be for a stack frame pointer that is not actually used
            self.buffer.set_position(4);
            loop {
                let header = try!(self.buffer.read_header());
                match &header {
                    &MsgHeader::ReadStateData { offset: _, len, target } => {
                        let mut output = MutRawBytes::new(target, len);
                        try!(self.buffer.read_body(&header, &mut output));
                    },
                    &MsgHeader::WriteStateData { offset: _, len: _ } => {
                        let mut output = io::sink();
                        try!(self.buffer.read_body(&header, &mut output));
                    },
                    &MsgHeader::TerminationMark => return Ok(nbytes),
                }
            }
        }
    }
}

const FS6IPC_MESSAGE_SUCCESS: u32 = 1;
const WM_IPCTHREADACCESS: u32 = WM_USER + 130;
const WM_IPC_TIMEOUT: u32 = 10000;
<commit_msg>Make `LocalHandle` implement `Clone` and `Send`<commit_after>
//
// FSUIPC library
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::ffi::CString;
use std::io;
use std::ptr;

use user32::{FindWindowExA, SendMessageTimeoutA};
use winapi::WM_USER;
use winapi::windef::HWND;
use winapi::winuser::SMTO_BLOCK;

use super::{Handle, Session};
use super::ipc::*;
use super::raw::MutRawBytes;

/// A handle to FSUIPc that uses local IPC communication to the FSUIPC module
/// This kind of handle must be used from code running in the same process as FSUIPC does.
#[derive(Clone)]
pub struct LocalHandle {
    handle: HWND,
}

unsafe impl Send for LocalHandle {}

impl LocalHandle {
    pub fn new() -> io::Result<Self> {
        unsafe {
            let win_name = CString::new("UIPCMAIN").unwrap();
            let handle = FindWindowExA(
                ptr::null_mut(), ptr::null_mut(), win_name.as_ptr(), ptr::null_mut());
            if handle != ptr::null_mut() {
                Ok(LocalHandle { handle: handle })
            } else {
                Err(io::Error::new(
                    io::ErrorKind::ConnectionRefused,
                    "cannot connect to local FSUIPC: cannot create window handle"))
            }
        }
    }
}

impl<'a> Handle<'a> for LocalHandle {
    type Sess = LocalSession;

    fn session(&'a mut self) -> LocalSession {
        LocalSession::new(self.handle)
    }
}

pub struct LocalSession {
    handle: HWND,
    buffer: io::Cursor<Vec<u8>>,
}

impl LocalSession {
    fn new(handle: HWND) -> Self {
        let mut session = LocalSession {
            handle: handle,
            buffer: io::Cursor::new(Vec::with_capacity(4096))
        };
        // First 4-bytes seems to be for a stack frame pointer that is not actually used
        session.buffer.set_position(4);
        session
    }
}

impl Session for LocalSession {
    fn read_bytes(&mut self, offset: u16, dest: *mut u8, len: usize) -> io::Result<usize> {
        self.buffer.write_rsd(offset, dest, len)
    }

    fn write_bytes(&mut self, offset: u16, src: *const u8, len: usize) -> io::Result<usize> {
        self.buffer.write_wsd(offset, src, len)
    }

    fn process(mut self) -> io::Result<usize> {
        unsafe {
            try!(self.buffer.write_header(&MsgHeader::TerminationMark));
            let nbytes = self.buffer.position() as usize;
            let buff = self.buffer.get_ref().as_ptr() as i32;
            let mut process_result: u32 = 0;
            let send_result = SendMessageTimeoutA(
                self.handle,
                WM_IPCTHREADACCESS,
                nbytes as u32,
                buff,
                SMTO_BLOCK,
                WM_IPC_TIMEOUT,
                &mut process_result as *mut u32);
            if send_result == 0 {
                return Err(io::Error::new(
                    io::ErrorKind::TimedOut,
                    "timed out while waiting for a response from FSUIPC"));
            }
            if process_result != FS6IPC_MESSAGE_SUCCESS {
                return Err(io::Error::new(io::ErrorKind::InvalidData, format!(
                    "FSUIPC rejected the requests with error {}; possible buffer corruption in bytes: {:?}",
                    send_result, self.buffer.get_ref())));
            }
            // First 4-bytes seems to be for a stack frame pointer that is not actually used
            self.buffer.set_position(4);
            loop {
                let header = try!(self.buffer.read_header());
                match &header {
                    &MsgHeader::ReadStateData { offset: _, len, target } => {
                        let mut output = MutRawBytes::new(target, len);
                        try!(self.buffer.read_body(&header, &mut output));
                    },
                    &MsgHeader::WriteStateData { offset: _, len: _ } => {
                        let mut output = io::sink();
                        try!(self.buffer.read_body(&header, &mut output));
                    },
                    &MsgHeader::TerminationMark => return Ok(nbytes),
                }
            }
        }
    }
}

const FS6IPC_MESSAGE_SUCCESS: u32 = 1;
const WM_IPCTHREADACCESS: u32 = WM_USER + 130;
const WM_IPC_TIMEOUT: u32 = 10000;

#[cfg(test)]
mod test {
    use std::thread;
    use winapi::windef::HWND;
    use super::*;

    #[test]
    fn test_local_handler_can_be_shared() {
        let handler = LocalHandle{ handle: 0 as HWND };
        let handler_copy = handler.clone();
        let child = thread::spawn(move|| {
            assert_eq!(0 as HWND, handler_copy.handle);
        });
        child.join().unwrap();
        assert_eq!(0 as HWND, handler.handle);
    }
}<|endoftext|>