<commit_before><commit_msg>Remove `mem::replace` from `join` and `subdivide`.<commit_after><|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{BufReader, Cursor, Read};
use std::fs::File;
use std::path::Path;

use shader::ShaderType;
use camera::Camera;

use genmesh;

use glium::{DepthTest, DrawError, DrawParameters, Surface, Program, VertexBuffer};
use glium::backend::Facade;
use glium::index::{IndicesSource, NoIndices, PrimitiveType};
use glium::texture::Texture2d;
use glium::uniforms::{UniformValue, Uniforms};
use glium::vertex::VertexBufferAny;

use image;

use nalgebra::{self, Vec3, Mat4};

use obj;

use time;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 3],
    tex_coord: [f32; 2],
}

impl Vertex {
    fn new(x: f32, y: f32, z: f32) -> Self {
        Vertex { position: [x, y, z], tex_coord: [0., 0.] }
    }
}

implement_vertex!(Vertex, position, tex_coord);

pub struct ObjectBuilder<'a> {
    vertex_buffer: VertexBufferAny,
    indices: IndicesSource<'a>,
    draw_params: Option<DrawParameters<'a>>,
    transform: Option<Mat4<f32>>,
    shader_type: Option<ShaderType>,
}

impl<'a> ObjectBuilder<'a> {
    pub fn new<I: Into<IndicesSource<'a>>>(vb: VertexBufferAny, indices: I) -> Self {
        ObjectBuilder {
            vertex_buffer: vb,
            indices: indices.into(),
            draw_params: None,
            transform: None,
            shader_type: None,
        }
    }

    pub fn from_obj<F, I, P>(facade: &F, path: P, indices: I) -> Self
    where F: Facade, I: Into<IndicesSource<'a>>, P: AsRef<Path> {
        let vb = load_obj(facade, &mut BufReader::new(File::open(path).unwrap()));
        Self::new(vb, indices)
    }

    pub fn draw_params(mut self, params: DrawParameters<'a>) -> Self {
        self.draw_params = Some(params);
        self
    }

    pub fn transform(mut self, transform: Mat4<f32>) -> Self {
        self.transform = Some(transform);
        self
    }

    pub fn shader(mut self, shader_type: ShaderType) -> Self {
        self.shader_type = Some(shader_type);
        self
    }

    pub fn build(self) -> Object<'a> {
        Object {
            vertex_buffer: self.vertex_buffer,
            indices: self.indices,
            draw_params: self.draw_params.unwrap_or_else(|| Default::default()),
            transform: self.transform.unwrap_or_else(|| nalgebra::new_identity(4)),
            shader_type: self.shader_type.unwrap_or(ShaderType::UnlitColor),
        }
    }
}

pub struct Object<'a> {
    vertex_buffer: VertexBufferAny,
    indices: IndicesSource<'a>,
    draw_params: DrawParameters<'a>,
    transform: Mat4<f32>,
    shader_type: ShaderType,
}

pub struct EngineContext {
    vertex_shader: String,
    shader_map: HashMap<ShaderType, String>,
}

struct UniformsVec<'a>(Vec<(&'static str, UniformValue<'a>)>);
impl<'b> Uniforms for UniformsVec<'b> {
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut f: F) {
        for v in self.0.iter() {
            f(&v.0, v.1);
        }
    }
}

impl EngineContext {
    pub fn new() -> Self {
        let mut shader = String::new();
        File::open("shaders/vertex.glsl").unwrap().read_to_string(&mut shader).unwrap();
        EngineContext { vertex_shader: shader, shader_map: HashMap::new() }
    }

    pub fn draw<'a, F: Facade, S: Surface>(&mut self,
                                           surface: &mut S,
                                           facade: &F,
                                           obj: &Object,
                                           uniforms: &UniformsVec<'a>)
                                           -> Result<(), DrawError> {
        let &mut EngineContext { ref vertex_shader, ref mut shader_map } = self;
        let fragment_shader = Self::get_shader(shader_map, obj.shader_type);
        let program = Program::from_source(facade, vertex_shader,
                                           fragment_shader, None).unwrap();
        surface.draw(&obj.vertex_buffer, obj.indices.clone(), &program, uniforms, &obj.draw_params)
    }

    fn get_shader(shader_map: &mut HashMap<ShaderType, String>, shader_type: ShaderType) -> &str {
        shader_map.entry(shader_type).or_insert_with(|| {
            let mut shader = String::new();
            File::open(shader_type.to_filename()).unwrap().read_to_string(&mut shader).unwrap();
            shader
        })
    }
}

pub struct Grid<'a> {
    pub parent: Object<'a>,
    dim: u16,
}

impl<'a> Grid<'a> {
    pub fn new<F: Facade>(facade: &F, dim: u16) -> Self {
        let mut shape = Vec::new();
        let len = dim as f32 / 10.;
        for i in 0..dim * 2 + 1 {
            let i = i as f32;
            let v1 = Vertex::new(-len + i * 0.1, -len, 0.);
            let v2 = Vertex::new(-len + i * 0.1, len, 0.);

            let v3 = Vertex::new(-len, -len + i * 0.1, 0.);
            let v4 = Vertex::new(len, -len + i * 0.1, 0.);

            shape.push(v1);
            shape.push(v2);
            shape.push(v3);
            shape.push(v4);
        }

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let vb = VertexBuffer::new(facade, shape).into_vertex_buffer_any();
        let indices = NoIndices(PrimitiveType::LinesList);
        let parent = ObjectBuilder::new(vb, indices)
            .draw_params(params)
            .build();

        Grid { parent: parent, dim: dim }
    }

    pub fn construct_uniforms(&self, camera: &Camera) -> UniformsVec {
        UniformsVec(vec![
            ("proj_matrix", UniformValue::Mat4(*camera.projection_matrix().as_array())),
            ("view_matrix", UniformValue::Mat4(*camera.view_matrix().as_array())),
            ("transform", UniformValue::Mat4(*self.parent.transform.as_array())),
            ("color", UniformValue::Vec3([1., 1., 1.]))])
    }
}

pub struct Cube<'a> {
    pub parent: Object<'a>,
    dim: f32,
    pos: Vec3<f32>,
    texture: ::glium::texture::CompressedSrgbTexture2d,
}

impl<'a> Cube<'a> {
    pub fn new<F: Facade>(facade: &F, dim: f32, pos: Vec3<f32>) -> Self {
        let image = image::load(Cursor::new(&include_bytes!("../resources/cube.png")[..]),
                                image::PNG).unwrap();
        let tex = ::glium::texture::CompressedSrgbTexture2d::new(facade, image);

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let parent = ObjectBuilder::from_obj(facade, "resources/cube.obj",
                                             NoIndices(PrimitiveType::TrianglesList))
            .draw_params(params)
            .shader(ShaderType::UnlitTexture)
            .build();

        Cube { parent: parent, dim: dim, pos: pos, texture: tex }
    }

    pub fn get_rotation_mat(t: time::Timespec) -> Mat4<f32> {
        let sec = (t.sec as f64) + ((t.nsec as f64)/1e9);

        Mat4::new(sec.cos() as f32,  -sec.sin() as f32, 0., 0.,
                  sec.sin() as f32,  sec.cos() as f32,  0., 0.,
                  0.,                0.,                1., 0.,
                  0.,                0.,                0., 1.)
    }

    pub fn construct_uniforms(&self, camera: &Camera) -> UniformsVec {
        UniformsVec(vec![
            ("proj_matrix", UniformValue::Mat4(*camera.projection_matrix().as_array())),
            ("view_matrix", UniformValue::Mat4(*camera.view_matrix().as_array())),
            ("transform", UniformValue::Mat4(*self.parent.transform.as_array())),
            ("tex", UniformValue::CompressedSrgbTexture2d(&self.texture, Some(Default::default())))])
    }
}

fn load_obj<F: Facade, R: Read>(facade: &F, data: &mut BufReader<R>) -> VertexBufferAny {
    let data = obj::Obj::load(data);
    let mut vertex_data = Vec::new();

    for shape in data.object_iter().next().unwrap().group_iter().flat_map(|g| g.indices().iter()) {
        match shape {
            &genmesh::Polygon::PolyTri(genmesh::Triangle { x: v1, y: v2, z: v3 }) => {
                for v in [v1, v2, v3].iter() {
                    let position = data.position()[v.0];
                    let texture = v.1.map(|index| data.texture()[index]);
                    //let normal = v.2.map(|index| data.normal()[index]);

                    let texture = texture.unwrap_or([0.0, 0.0]);
                    //let normal = normal.unwrap_or([0.0, 0.0, 0.0]);

                    vertex_data.push(Vertex {
                        position: position,
                        tex_coord: texture,
                    })
                }
            },
            _ => {println!("{:?}", shape); unimplemented!()}
        }
    }

    VertexBuffer::new(facade, vertex_data).into_vertex_buffer_any()
}
<commit_msg>Transform cube<commit_after>use std::collections::HashMap;
use std::io::{BufReader, Cursor, Read};
use std::fs::File;
use std::path::Path;

use shader::ShaderType;
use camera::Camera;

use genmesh;

use glium::{DepthTest, DrawError, DrawParameters, Surface, Program, VertexBuffer};
use glium::backend::Facade;
use glium::index::{IndicesSource, NoIndices, PrimitiveType};
use glium::texture::Texture2d;
use glium::uniforms::{UniformValue, Uniforms};
use glium::vertex::VertexBufferAny;

use image;

use nalgebra::{self, Col, Mat4, Vec3, Vec4};

use obj;

use time;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 3],
    tex_coord: [f32; 2],
}

impl Vertex {
    fn new(x: f32, y: f32, z: f32) -> Self {
        Vertex { position: [x, y, z], tex_coord: [0., 0.] }
    }
}

implement_vertex!(Vertex, position, tex_coord);

pub struct ObjectBuilder<'a> {
    vertex_buffer: VertexBufferAny,
    indices: IndicesSource<'a>,
    draw_params: Option<DrawParameters<'a>>,
    transform: Option<Mat4<f32>>,
    shader_type: Option<ShaderType>,
}

impl<'a> ObjectBuilder<'a> {
    pub fn new<I: Into<IndicesSource<'a>>>(vb: VertexBufferAny, indices: I) -> Self {
        ObjectBuilder {
            vertex_buffer: vb,
            indices: indices.into(),
            draw_params: None,
            transform: None,
            shader_type: None,
        }
    }

    pub fn from_obj<F, I, P>(facade: &F, path: P, indices: I) -> Self
    where F: Facade, I: Into<IndicesSource<'a>>, P: AsRef<Path> {
        let vb = load_obj(facade, &mut BufReader::new(File::open(path).unwrap()));
        Self::new(vb, indices)
    }

    pub fn draw_params(mut self, params: DrawParameters<'a>) -> Self {
        self.draw_params = Some(params);
        self
    }

    pub fn transform(mut self, transform: Mat4<f32>) -> Self {
        self.transform = Some(transform);
        self
    }

    pub fn shader(mut self, shader_type: ShaderType) -> Self {
        self.shader_type = Some(shader_type);
        self
    }

    pub fn build(self) -> Object<'a> {
        Object {
            vertex_buffer: self.vertex_buffer,
            indices: self.indices,
            draw_params: self.draw_params.unwrap_or_else(|| Default::default()),
            transform: self.transform.unwrap_or_else(|| nalgebra::new_identity(4)),
            shader_type: self.shader_type.unwrap_or(ShaderType::UnlitColor),
        }
    }
}

pub struct Object<'a> {
    vertex_buffer: VertexBufferAny,
    indices: IndicesSource<'a>,
    draw_params: DrawParameters<'a>,
    transform: Mat4<f32>,
    shader_type: ShaderType,
}

pub struct EngineContext {
    vertex_shader: String,
    shader_map: HashMap<ShaderType, String>,
}

struct UniformsVec<'a>(Vec<(&'static str, UniformValue<'a>)>);
impl<'b> Uniforms for UniformsVec<'b> {
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut f: F) {
        for v in self.0.iter() {
            f(&v.0, v.1);
        }
    }
}

impl EngineContext {
    pub fn new() -> Self {
        let mut shader = String::new();
        File::open("shaders/vertex.glsl").unwrap().read_to_string(&mut shader).unwrap();
        EngineContext { vertex_shader: shader, shader_map: HashMap::new() }
    }

    pub fn draw<'a, F: Facade, S: Surface>(&mut self,
                                           surface: &mut S,
                                           facade: &F,
                                           obj: &Object,
                                           uniforms: &UniformsVec<'a>)
                                           -> Result<(), DrawError> {
        let &mut EngineContext { ref vertex_shader, ref mut shader_map } = self;
        let fragment_shader = Self::get_shader(shader_map, obj.shader_type);
        let program = Program::from_source(facade, vertex_shader,
                                           fragment_shader, None).unwrap();
        surface.draw(&obj.vertex_buffer, obj.indices.clone(), &program, uniforms, &obj.draw_params)
    }

    fn get_shader(shader_map: &mut HashMap<ShaderType, String>, shader_type: ShaderType) -> &str {
        shader_map.entry(shader_type).or_insert_with(|| {
            let mut shader = String::new();
            File::open(shader_type.to_filename()).unwrap().read_to_string(&mut shader).unwrap();
            shader
        })
    }
}

pub struct Grid<'a> {
    pub parent: Object<'a>,
}

impl<'a> Grid<'a> {
    pub fn new<F: Facade>(facade: &F, dim: u16) -> Self {
        let mut shape = Vec::new();
        let len = dim as f32 / 10.;
        for i in 0..dim * 2 + 1 {
            let i = i as f32;
            let v1 = Vertex::new(-len + i * 0.1, -len, 0.);
            let v2 = Vertex::new(-len + i * 0.1, len, 0.);

            let v3 = Vertex::new(-len, -len + i * 0.1, 0.);
            let v4 = Vertex::new(len, -len + i * 0.1, 0.);

            shape.push(v1);
            shape.push(v2);
            shape.push(v3);
            shape.push(v4);
        }

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let vb = VertexBuffer::new(facade, shape).into_vertex_buffer_any();
        let indices = NoIndices(PrimitiveType::LinesList);
        let parent = ObjectBuilder::new(vb, indices)
            .draw_params(params)
            .build();

        Grid { parent: parent }
    }

    pub fn construct_uniforms(&self, camera: &Camera) -> UniformsVec {
        UniformsVec(vec![
            ("proj_matrix", UniformValue::Mat4(*camera.projection_matrix().as_array())),
            ("view_matrix", UniformValue::Mat4(*camera.view_matrix().as_array())),
            ("transform", UniformValue::Mat4(*self.parent.transform.as_array())),
            ("color", UniformValue::Vec3([1., 1., 1.]))])
    }
}

pub struct Cube<'a> {
    pub parent: Object<'a>,
    texture: Texture2d,
}

impl<'a> Cube<'a> {
    pub fn new<F: Facade>(facade: &F, dim: f32, pos: Vec3<f32>) -> Self {
        let image = image::load(Cursor::new(&include_bytes!("../resources/cube.png")[..]),
                                image::PNG).unwrap();
        let tex = Texture2d::new(facade, image);

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut transform: Mat4<f32> = nalgebra::new_identity(4);
        transform = transform * dim;
        transform.set_col(3, Vec4::new(pos.x, pos.y, pos.z, 1.));

        let parent = ObjectBuilder::from_obj(facade, "resources/cube.obj",
                                             NoIndices(PrimitiveType::TrianglesList))
            .draw_params(params)
            .shader(ShaderType::UnlitTexture)
            .transform(transform)
            .build();

        Cube { parent: parent, texture: tex }
    }

    pub fn get_rotation_mat(t: time::Timespec) -> Mat4<f32> {
        let sec = (t.sec as f64) + ((t.nsec as f64)/1e9);

        Mat4::new(sec.cos() as f32,  -sec.sin() as f32, 0., 0.,
                  sec.sin() as f32,  sec.cos() as f32,  0., 0.,
                  0.,                0.,                1., 0.,
                  0.,                0.,                0., 1.)
    }

    pub fn construct_uniforms(&self, camera: &Camera) -> UniformsVec {
        UniformsVec(vec![
            ("proj_matrix", UniformValue::Mat4(*camera.projection_matrix().as_array())),
            ("view_matrix", UniformValue::Mat4(*camera.view_matrix().as_array())),
            ("transform", UniformValue::Mat4(*self.parent.transform.as_array())),
            ("tex", UniformValue::Texture2d(&self.texture, None))])
    }
}

fn load_obj<F: Facade, R: Read>(facade: &F, data: &mut BufReader<R>) -> VertexBufferAny {
    let data = obj::Obj::load(data);
    let mut vertex_data = Vec::new();

    for shape in data.object_iter().next().unwrap().group_iter().flat_map(|g| g.indices().iter()) {
        match shape {
            &genmesh::Polygon::PolyTri(genmesh::Triangle { x: v1, y: v2, z: v3 }) => {
                for v in [v1, v2, v3].iter() {
                    let position = data.position()[v.0];
                    let texture = v.1.map(|index| data.texture()[index]);
                    //let normal = v.2.map(|index| data.normal()[index]);

                    let texture = texture.unwrap_or([0.0, 0.0]);
                    //let normal = normal.unwrap_or([0.0, 0.0, 0.0]);

                    vertex_data.push(Vertex {
                        position: position,
                        tex_coord: texture,
                    })
                }
            },
            _ => {println!("{:?}", shape); unimplemented!()}
        }
    }

    VertexBuffer::new(facade, vertex_data).into_vertex_buffer_any()
}
<|endoftext|>


<commit_before>use super::object::Object;
use super::object::NULL;
use super::object::TRUE;
use super::object::FALSE;
use super::ast::Program;
use super::ast::Statement;
use super::ast::Expression;

pub fn eval(program: Program) -> Object {
    eval_statements(&program.statements)
}

fn eval_statements(stmts: &Vec<Statement>) -> Object {
    let mut result = NULL;

    for stmt in stmts {
        result = eval_statement(&stmt);

        if let Object::ReturnValue(val) = result {
            return *val;
        }
    }

    result
}

fn eval_statement(stmt: &Statement) -> Object {
    match *stmt {
        Statement::Expression { ref expression, .. } => eval_expr(expression),
        Statement::Block { ref statements, .. } => eval_statements(statements),
        Statement::Return { ref value, .. } => {
            let mut return_val = NULL;
            if let Some(ref v) = *value {
                return_val = eval_expr(v);
            }

            Object::ReturnValue(Box::new(return_val))
        }
        _ => NULL
    }
}

fn eval_expr(expr: &Expression) -> Object {
    match *expr {
        Expression::IntegerLiteral { value, .. } => Object::Integer(value),
        Expression::Boolean { value, .. } => to_boolean_object(value),
        Expression::Prefix { ref operator, ref right, .. } => {
            let right = eval_expr(right);
            eval_prefix_expr(operator, right)
        },
        Expression::Infix { ref left, ref right, ref operator, .. } => {
            let left = eval_expr(left);
            let right = eval_expr(right);
            eval_infix_expr(operator, left, right)
        },
        Expression::If { ref condition, ref consequence, ref alternative, .. } => {
            let cond = eval_expr(condition);

            if cond.is_truthy() {
                eval_statement(consequence)
            } else if let Some(ref alt) = *alternative {
                eval_statement(alt)
            } else {
                NULL
            }
        }
        _ => NULL
    }
}

fn to_boolean_object(val: bool) -> Object {
    if val { TRUE } else { FALSE }
}

fn eval_prefix_expr(op: &str, right: Object) -> Object {
    match op {
        "!" => eval_bang_operator_expr(right),
        "-" => eval_minus_prefix_operator_expr(right),
        _ => NULL
    }
}

fn eval_bang_operator_expr(right: Object) -> Object {
    match right {
        TRUE => FALSE,
        FALSE => TRUE,
        NULL => TRUE,
        _ => FALSE
    }
}

fn eval_minus_prefix_operator_expr(right: Object) -> Object {
    match right {
        Object::Integer(val) => Object::Integer(-val),
        _ => NULL,
    }
}

fn eval_infix_expr(op: &str, left: Object, right: Object) -> Object {
    match (op, left, right) {
        (_, Object::Integer(lval), Object::Integer(rval)) => {
            match op {
                "+" => Object::Integer(lval + rval),
                "-" => Object::Integer(lval - rval),
                "*" => Object::Integer(lval * rval),
                "/" => Object::Integer(lval / rval),
                "<" => to_boolean_object(lval < rval),
                ">" => to_boolean_object(lval > rval),
                "==" => to_boolean_object(lval == rval),
                "!=" => to_boolean_object(lval != rval),
                _ => NULL
            }
        },
        ("==", lval @ _, rval @ _) => to_boolean_object(lval == rval),
        ("!=", lval @ _, rval @ _) => to_boolean_object(lval != rval),
        _ => NULL
    }
}

#[cfg(test)]
use super::lexer::Lexer;
#[cfg(test)]
use super::parser::Parser;

#[cfg(test)]
fn test_eval(input: &str) -> Object {
    let mut l = Lexer::new(input.to_string());
    let mut p = Parser::new(&mut l);
    let program = p.parse_program();

    eval(program)
}

#[cfg(test)]
fn check_integer_object(obj: Object, expected: i64) {
    match obj {
        Object::Integer(val) => {
            assert!(val == expected,
                    "Object has wrong value. Got {}, want {}",
                    val,
                    expected);
        },
        _ => panic!("Object is not an Integer. Got {:?}", obj)
    }
}

#[cfg(test)]
fn check_boolean_object(obj: Object, expected: bool) {
    match obj {
        Object::Boolean(val) => {
            assert!(val == expected,
                    "Object has wrong value. Got {}, want {}",
                    val,
                    expected);
        },
        _ => panic!("Object is not an Boolean. Got {:?}", obj)
    }
}

#[cfg(test)]
fn check_null_object(obj: Object) {
    assert!(obj == NULL, "obj is not NULL. Got {:?}", obj);
}

#[test]
fn test_eval_integer_expression() {
    let tests = vec![
        ("5", 5),
        ("10", 10),
        ("-5", -5),
        ("-10", -10),
        ("5 + 5 + 5 + 5 - 10", 10),
        ("-50 + 100 + -50", 0),
        ("5 * 2 + 10", 20),
        ("5 + 2 * 10", 25),
        ("2 * 2 * 2 * 2 * 2", 32),
        ("20 + 2 * -10", 0),
        ("50 / 2 * 2 + 10", 60),
        ("2 * (5 + 10)", 30),
        ("3 * 3 * 3 + 10", 37),
        ("3 * (3 * 3) + 10", 37),
        ("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}

#[test]
fn test_eval_boolean_expression() {
    let tests = vec![
        ("true", true),
        ("false", false),
        ("1 < 2", true),
        ("1 > 2", false),
        ("1 < 1", false),
        ("1 > 1", false),
        ("1 == 1", true),
        ("1 != 1", false),
        ("1 == 2", false),
        ("1 != 2", true),
        ("true == true", true),
        ("false == false", true),
        ("true == false", false),
        ("true != false", true),
        ("false!= true", true),
        ("(1 < 2) == true", true),
        ("(1 < 2) == false", false),
        ("(1 > 2) == true", false),
        ("(1 > 2) == false", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_bang_operator() {
    let tests = vec![
        ("!true", false),
        ("!false", true),
        ("!5", false),
        ("!!true", true),
        ("!!false", false),
        ("!!5", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_if_else_expressions() {
    let tests = vec![
        ("if (true) { 10 }", Object::Integer(10)),
        ("if (false) { 10 }", NULL),
        ("if (1) { 10 }", Object::Integer(10)),
        ("if (1 < 2) { 10 }", Object::Integer(10)),
        ("if (1 > 2) { 10 }", NULL),
        ("if (1 > 2) { 10 } else { 20 }", Object::Integer(20)),
        ("if (1 < 2) { 10 } else { 20 }", Object::Integer(10)),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        match expected {
            Object::Integer(val) => check_integer_object(evaluated, val),
            NULL => check_null_object(evaluated),
            _ => panic!("Fix the test."),
        }
    }
}

#[test]
fn test_return_statements() {
    let tests = vec![
        ("return 10;", 10),
        ("return 10; 9;", 10),
        ("return 2 * 5; 9;", 10),
        ("9; return 2 * 5; 9;", 10),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}<commit_msg>Support for nested returns.<commit_after>use super::object::Object;
use super::object::NULL;
use super::object::TRUE;
use super::object::FALSE;
use super::ast::Program;
use super::ast::Statement;
use super::ast::Expression;

pub fn eval(program: Program) -> Object {
    eval_statements(&program.statements, false)
}

fn eval_statements(stmts: &Vec<Statement>, nested: bool) -> Object {
    let mut result = NULL;

    for stmt in stmts {
        result = eval_statement(&stmt);

        if let Object::ReturnValue(val) = result {
            if nested {
                return Object::ReturnValue(val);
            } else {
                return *val;
            }
        }
    }

    result
}

fn eval_statement(stmt: &Statement) -> Object {
    match *stmt {
        Statement::Expression { ref expression, .. } => eval_expr(expression),
        Statement::Block { ref statements, .. } => eval_statements(statements, true),
        Statement::Return { ref value, .. } => {
            let mut return_val = NULL;
            if let Some(ref v) = *value {
                return_val = eval_expr(v);
            }

            Object::ReturnValue(Box::new(return_val))
        }
        _ => NULL
    }
}

fn eval_expr(expr: &Expression) -> Object {
    match *expr {
        Expression::IntegerLiteral { value, .. } => Object::Integer(value),
        Expression::Boolean { value, .. } => to_boolean_object(value),
        Expression::Prefix { ref operator, ref right, .. } => {
            let right = eval_expr(right);
            eval_prefix_expr(operator, right)
        },
        Expression::Infix { ref left, ref right, ref operator, .. } => {
            let left = eval_expr(left);
            let right = eval_expr(right);
            eval_infix_expr(operator, left, right)
        },
        Expression::If { ref condition, ref consequence, ref alternative, .. } => {
            let cond = eval_expr(condition);

            if cond.is_truthy() {
                eval_statement(consequence)
            } else if let Some(ref alt) = *alternative {
                eval_statement(alt)
            } else {
                NULL
            }
        }
        _ => NULL
    }
}

fn to_boolean_object(val: bool) -> Object {
    if val { TRUE } else { FALSE }
}

fn eval_prefix_expr(op: &str, right: Object) -> Object {
    match op {
        "!" => eval_bang_operator_expr(right),
        "-" => eval_minus_prefix_operator_expr(right),
        _ => NULL
    }
}

fn eval_bang_operator_expr(right: Object) -> Object {
    match right {
        TRUE => FALSE,
        FALSE => TRUE,
        NULL => TRUE,
        _ => FALSE
    }
}

fn eval_minus_prefix_operator_expr(right: Object) -> Object {
    match right {
        Object::Integer(val) => Object::Integer(-val),
        _ => NULL,
    }
}

fn eval_infix_expr(op: &str, left: Object, right: Object) -> Object {
    match (op, left, right) {
        (_, Object::Integer(lval), Object::Integer(rval)) => {
            match op {
                "+" => Object::Integer(lval + rval),
                "-" => Object::Integer(lval - rval),
                "*" => Object::Integer(lval * rval),
                "/" => Object::Integer(lval / rval),
                "<" => to_boolean_object(lval < rval),
                ">" => to_boolean_object(lval > rval),
                "==" => to_boolean_object(lval == rval),
                "!=" => to_boolean_object(lval != rval),
                _ => NULL
            }
        },
        ("==", lval @ _, rval @ _) => to_boolean_object(lval == rval),
        ("!=", lval @ _, rval @ _) => to_boolean_object(lval != rval),
        _ => NULL
    }
}

#[cfg(test)]
use super::lexer::Lexer;
#[cfg(test)]
use super::parser::Parser;

#[cfg(test)]
fn test_eval(input: &str) -> Object {
    let mut l = Lexer::new(input.to_string());
    let mut p = Parser::new(&mut l);
    let program = p.parse_program();

    eval(program)
}

#[cfg(test)]
fn check_integer_object(obj: Object, expected: i64) {
    match obj {
        Object::Integer(val) => {
            assert!(val == expected,
                    "Object has wrong value. Got {}, want {}",
                    val,
                    expected);
        },
        _ => panic!("Object is not an Integer. Got {:?}", obj)
    }
}

#[cfg(test)]
fn check_boolean_object(obj: Object, expected: bool) {
    match obj {
        Object::Boolean(val) => {
            assert!(val == expected,
                    "Object has wrong value. Got {}, want {}",
                    val,
                    expected);
        },
        _ => panic!("Object is not an Boolean. Got {:?}", obj)
    }
}

#[cfg(test)]
fn check_null_object(obj: Object) {
    assert!(obj == NULL, "obj is not NULL. Got {:?}", obj);
}

#[test]
fn test_eval_integer_expression() {
    let tests = vec![
        ("5", 5),
        ("10", 10),
        ("-5", -5),
        ("-10", -10),
        ("5 + 5 + 5 + 5 - 10", 10),
        ("-50 + 100 + -50", 0),
        ("5 * 2 + 10", 20),
        ("5 + 2 * 10", 25),
        ("2 * 2 * 2 * 2 * 2", 32),
        ("20 + 2 * -10", 0),
        ("50 / 2 * 2 + 10", 60),
        ("2 * (5 + 10)", 30),
        ("3 * 3 * 3 + 10", 37),
        ("3 * (3 * 3) + 10", 37),
        ("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}

#[test]
fn test_eval_boolean_expression() {
    let tests = vec![
        ("true", true),
        ("false", false),
        ("1 < 2", true),
        ("1 > 2", false),
        ("1 < 1", false),
        ("1 > 1", false),
        ("1 == 1", true),
        ("1 != 1", false),
        ("1 == 2", false),
        ("1 != 2", true),
        ("true == true", true),
        ("false == false", true),
        ("true == false", false),
        ("true != false", true),
        ("false!= true", true),
        ("(1 < 2) == true", true),
        ("(1 < 2) == false", false),
        ("(1 > 2) == true", false),
        ("(1 > 2) == false", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_bang_operator() {
    let tests = vec![
        ("!true", false),
        ("!false", true),
        ("!5", false),
        ("!!true", true),
        ("!!false", false),
        ("!!5", true),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_boolean_object(evaluated, expected);
    }
}

#[test]
fn test_if_else_expressions() {
    let tests = vec![
        ("if (true) { 10 }", Object::Integer(10)),
        ("if (false) { 10 }", NULL),
        ("if (1) { 10 }", Object::Integer(10)),
        ("if (1 < 2) { 10 }", Object::Integer(10)),
        ("if (1 > 2) { 10 }", NULL),
        ("if (1 > 2) { 10 } else { 20 }", Object::Integer(20)),
        ("if (1 < 2) { 10 } else { 20 }", Object::Integer(10)),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        match expected {
            Object::Integer(val) => check_integer_object(evaluated, val),
            NULL => check_null_object(evaluated),
            _ => panic!("Fix the test."),
        }
    }
}

#[test]
fn test_return_statements() {
    let tests = vec![
        ("return 10;", 10),
        ("return 10; 9;", 10),
        ("return 2 * 5; 9;", 10),
        ("9; return 2 * 5; 9;", 10),
        ("if (10 > 1) {
            if (10 > 1) {
              return 10;
            }

            return 1;
         }", 10),
    ];

    for (input, expected) in tests {
        let evaluated = test_eval(input);
        check_integer_object(evaluated, expected);
    }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::iter::Map;
use parser::Node;

#[derive(Debug, Clone)]
pub struct EvalError(String);

pub struct Eval;

// TODO: Reduce memory copy...
impl Eval {
    pub fn new() -> Self {
        Eval {}
    }

    fn calc_integer<F>(&self,
                       env: &mut HashMap<String, Node>,
                       f: &F,
                       args: &[Node], node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> i64 {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok(aa)) => Some(Ok(f(aa, i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok(i)),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(i)) => Ok(Node::Integer(i)),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn cond<F>(&self,
               env: &mut HashMap<String, Node>,
               f: &F,
               args: &[Node],
               node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> bool {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok((result, prev))) => Some(Ok((result && f(prev, i), i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok((true, i))),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(result)) => Ok(if result.0 { Node::True } else { Node::False }),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn if_then_else(&self,
                    env: &mut HashMap<String, Node>,
                    args: &[Node],
                    node: &Node) -> Result<Node, EvalError> {

        if args.len() < 2 || args.len() > 3 {
            return Err(EvalError(format!("`if` takes 2 or 3 arguments, but got {:?}", args)));
        }

        Ok(match &try!(self.eval(env, args[0].clone())) {
            &Node::True => try!(self.eval(env, args[1].clone())),
            &Node::False => {
                if args.len() == 3 {
                    try!(self.eval(env, args[2].clone()))
                }
                else {
                    Node::List(Vec::new())
                }
            },
            _ => return Err(EvalError(format!("The 1st parameter of `if` should be boolean, but got {:?}", args)))
        })
    }

    fn car(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((hd, _)) => hd.clone(),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`car` takes only a quoted list, but got {:?}", args)))
    }

    fn cdr(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((_, tl)) => Node::QuotedList(tl.to_vec()),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`cdr` takes only a quoted list, but got {:?}", args)))
    }

    fn setq(&self,
            env: &mut HashMap<String, Node>,
            args: &[Node],
            node: &Node) -> Result<Node, EvalError> {

        if args.len() % 2 == 0 {
            let mut key = None;
            for arg in args {
                if let Some(k) = key {
                    let evalated_node = try!(self.eval(env, arg.clone()));
                    env.insert(k, evalated_node);
                    key = None;
                }
                else {
                    if let &Node::Keyword(ref k) = arg {
                        key = Some(k.clone())
                    }
                    else {
                        return Err(EvalError(format!("`setq` accepts only Node::Keyword as a key, but got {:?}", arg)));
                    }
                }
            }
            return Ok(node.clone())
        }

        Err(EvalError(format!("`setq` takes only key value pairs, but got {:?}", args)))
    }

    fn lambda(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        if args.len() == 2 {
            match (&args[0], &args[1]) {
                (&Node::List(ref xs), &Node::List(ref body)) => {
                    let mut fargs = Vec::new();
                    let mut errors = Vec::new();

                    for x in xs {
                        match x {
                            &Node::Keyword(ref kwd) => fargs.push(kwd.clone()),
                            _ => errors.push(
                                EvalError(format!("The 2nd parameter of `lambda` should be a list of keywords, but got {:?}", args))
                                ),
                        }
                    }

                    if ! errors.is_empty() {
                        return Err(errors[0].clone())
                    }

                    return Ok(Node::Func(fargs, body.clone()))
                },
                _ => ()
            }
        }

        Err(EvalError(format!("`lambda` takes only (name:keyword args:list body:list), but got {:?}", args)))
    }

    fn call(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        match node {
            &Node::Func(ref xs, ref body) => {
                let cloned_env = env.clone();

                let saved_env_kvs = xs.iter().
                    map(|k| (k, cloned_env.get(k))).
                    collect::<Vec<(&String, Option<&Node>)>>();

                for (i, x) in xs.iter().enumerate() {
                    let evaled_arg = try!(self.eval(env, args[i].clone()));
                    env.insert(x.clone(), evaled_arg);
                }

                // Dynamic scope, not lexical scope
                let result = try!(self.eval(env, Node::List(body.clone())));
                for x in xs {
                    env.remove(x);
                }
                for (k, v) in saved_env_kvs {
                    if let Some(saved_node) = v {
                        env.insert(k.clone(), saved_node.clone());
                    }
                }
                return Ok(result)
            },
            _ => ()
        }

        Err(EvalError(format!("Failed to call a function due to unexpected arguments: node is {:?} and arguments are {:?}", node, args)))
    }

    pub fn eval(&self, env: &mut HashMap<String, Node>, node: Node) -> Result<Node, EvalError> {
        Ok(
            match node {
                Node::Integer(_) => node,
                Node::Keyword(kwd) => {
                    let cloned_env = env.clone();
                    match cloned_env.get(&kwd) {
                        Some(x) => try!(self.eval(env, x.clone())),
                        None => Node::Keyword(kwd),
                    }
                },
                Node::List(ref xs) => {
                    let (hd, tl) = xs.split_first().unwrap();
                    match hd {
                        &Node::Keyword(ref kwd) => {
                            match kwd.as_str() {
                                "+" => try!(self.calc_integer(env, &|a, i| a + i, tl, &node)),
                                "-" => try!(self.calc_integer(env, &|a, i| a - i, tl, &node)),
                                "*" => try!(self.calc_integer(env, &|a, i| a * i, tl, &node)),
                                "/" => try!(self.calc_integer(env, &|a, i| a / i, tl, &node)),
                                "=" => try!(self.cond(env, &|a, i| a == i, tl, &node)),
                                ">" => try!(self.cond(env, &|a, i| a > i, tl, &node)),
                                ">=" => try!(self.cond(env, &|a, i| a >= i, tl, &node)),
                                "<" => try!(self.cond(env, &|a, i| a < i, tl, &node)),
                                "<=" => try!(self.cond(env, &|a, i| a <= i, tl, &node)),
                                "/=" => try!(self.cond(env, &|a, i| a != i, tl, &node)),
                                "if" => try!(self.if_then_else(env, tl, &node)),
                                "car" => try!(self.car(env, tl, &node)),
                                "cdr" => try!(self.cdr(env, tl, &node)),
                                "setq" => try!(self.setq(env, tl, &node)),
                                "lambda" => try!(self.lambda(env, tl, &node)),
                                _ =>  {
                                    let cloned_env = env.clone();
                                    match cloned_env.get(kwd) {
                                        Some(f) => try!(self.call(env, &tl, &f)),
                                        None => return Err(EvalError(format!("Unknown keyword: {:?}", kwd)))
                                    }
                                }
                            }
                        },
                        _ => return Err(EvalError(format!("Unexpected node: {:?}", node))),
                    }
                },
                Node::QuotedList(x) => Node::List(x),
                _ => node,
            }
        )
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use super::Eval;
    use parser::Node;

    #[test]
    fn eval() {
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Integer(40),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("*")),
                        Node::Integer(6),
                        Node::List(
                            vec![
                                Node::Keyword(String::from("-")),
                                Node::Integer(42),
                                Node::Integer(35),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("car")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(42),
                                Node::Integer(-123),
                                Node::Integer(0),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::QuotedList(
                vec![
                    Node::Integer(4),
                    Node::Integer(2),
                ]
            ),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("cdr")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(0),
                                Node::Integer(4),
                                Node::Integer(2),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        let env0 = &mut HashMap::new();
        env0.insert(String::from("x"), Node::Integer(40));
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env0,
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Keyword(String::from("x"))
                    ]
                )
            ).unwrap()
        );

        let env1 = &mut HashMap::new();
        Eval::new().eval(
            env1,
            Node::List(
                vec![
                    Node::Keyword(String::from("setq")),
                    Node::Keyword(String::from("add")),
                    Node::List(
                        vec![
                            Node::Keyword(String::from("lambda")),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("+")),
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                        ]
                    )
                ]
            )
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env1,
                Node::List(
                    vec![
                        Node::Keyword(String::from("add")),
                        Node::Integer(40),
                        Node::Integer(2),
                    ]
                )
            ).unwrap()
        );
    }
}

<commit_msg>Refactoring<commit_after>use std::collections::HashMap;
use std::iter::Map;
use parser::Node;

#[derive(Debug, Clone)]
pub struct EvalError(String);

pub struct Eval;

// TODO: Reduce memory copy...
impl Eval {
    pub fn new() -> Self {
        Eval {}
    }

    fn calc_integer<F>(&self,
                       env: &mut HashMap<String, Node>,
                       f: &F,
                       args: &[Node], node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> i64 {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok(aa)) => Some(Ok(f(aa, i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok(i)),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(i)) => Ok(Node::Integer(i)),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn cond<F>(&self,
               env: &mut HashMap<String, Node>,
               f: &F,
               args: &[Node],
               node: &Node) -> Result<Node, EvalError>
        where F: Fn(i64, i64) -> bool {

        let result =
            args.iter().fold(
                None,
                |a, x| {
                    let nd = self.eval(env, x.clone());
                    match nd {
                        Ok(Node::Integer(i)) => match a {
                            Some(Ok((result, prev))) => Some(Ok((result && f(prev, i), i))),
                            Some(Err(err)) => Some(Err(err)),
                            None => Some(Ok((true, i))),
                        },
                        Ok(_) => Some(Err(EvalError(format!("{:?} takes only an integer, but got {:?}", node, x)))),
                        Err(err) => Some(Err(err)),
                    }
                }
            );

        match result {
            Some(Ok(result)) => Ok(if result.0 { Node::True } else { Node::False }),
            Some(Err(err)) => Err(err),
            None => Err(EvalError(format!("Empty argument")))
        }
    }

    fn if_then_else(&self,
                    env: &mut HashMap<String, Node>,
                    args: &[Node],
                    node: &Node) -> Result<Node, EvalError> {

        if args.len() < 2 || args.len() > 3 {
            return Err(EvalError(format!("`if` takes 2 or 3 arguments, but got {:?}", args)));
        }

        Ok(match &try!(self.eval(env, args[0].clone())) {
            &Node::True => try!(self.eval(env, args[1].clone())),
            &Node::False => {
                if args.len() == 3 {
                    try!(self.eval(env, args[2].clone()))
                }
                else {
                    Node::List(Vec::new())
                }
            },
            _ => return Err(EvalError(format!("The 1st parameter of `if` should be boolean, but got {:?}", args)))
        })
    }

    fn car(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((hd, _)) => hd.clone(),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`car` takes only a quoted list, but got {:?}", args)))
    }

    fn cdr(&self,
           env: &mut HashMap<String, Node>,
           args: &[Node],
           node: &Node) -> Result<Node, EvalError> {

        if args.len() == 1 {
            if let &Node::QuotedList(ref xs) = &args[0] {
                return Ok(match xs.split_first() {
                    Some((_, tl)) => Node::QuotedList(tl.to_vec()),
                    None => Node::List(vec![])
                })
            }
        }

        Err(EvalError(format!("`cdr` takes only a quoted list, but got {:?}", args)))
    }

    fn setq(&self,
            env: &mut HashMap<String, Node>,
            args: &[Node],
            node: &Node) -> Result<Node, EvalError> {

        if args.len() % 2 == 0 {
            let mut key = None;
            for arg in args {
                if let Some(k) = key {
                    let evalated_node = try!(self.eval(env, arg.clone()));
                    env.insert(k, evalated_node);
                    key = None;
                }
                else {
                    if let &Node::Keyword(ref k) = arg {
                        key = Some(k.clone())
                    }
                    else {
                        return Err(EvalError(format!("`setq` accepts only Node::Keyword as a key, but got {:?}", arg)));
                    }
                }
            }
            return Ok(node.clone())
        }

        Err(EvalError(format!("`setq` takes only key value pairs, but got {:?}", args)))
    }

    fn lambda(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        if args.len() == 2 {
            match (&args[0], &args[1]) {
                (&Node::List(ref xs), &Node::List(ref body)) => {
                    let mut fargs = Vec::new();
                    let mut errors = Vec::new();

                    for x in xs {
                        match x {
                            &Node::Keyword(ref kwd) => fargs.push(kwd.clone()),
                            _ => errors.push(
                                EvalError(format!("The 2nd parameter of `lambda` should be a list of keywords, but got {:?}", args))
                                ),
                        }
                    }

                    if ! errors.is_empty() {
                        return Err(errors[0].clone())
                    }

                    return Ok(Node::Func(fargs, body.clone()))
                },
                _ => ()
            }
        }

        Err(EvalError(format!("`lambda` takes only (name:keyword args:list body:list), but got {:?}", args)))
    }

    fn call(&self, env: &mut HashMap<String, Node>, args: &[Node], node: &Node) -> Result<Node, EvalError> {
        match node {
            &Node::Func(ref xs, ref body) => {
                let cloned_env = env.clone();

                let saved_env_kvs = xs.iter().
                    map(|k| (k, cloned_env.get(k))).
                    collect::<Vec<(&String, Option<&Node>)>>();

                for (i, x) in xs.iter().enumerate() {
                    let evaled_arg = try!(self.eval(env, args[i].clone()));
                    env.insert(x.clone(), evaled_arg);
                }

                // Dynamic scope, not lexical scope
                let result = try!(self.eval(env, Node::List(body.clone())));
                for x in xs {
                    env.remove(x);
                }
                for (k, v) in saved_env_kvs {
                    if let Some(saved_node) = v {
                        env.insert(k.clone(), saved_node.clone());
                    }
                }
                return Ok(result)
            },
            _ => ()
        }

        Err(EvalError(format!("Failed to call a function due to unexpected arguments: node is {:?} and arguments are {:?}", node, args)))
    }

    pub fn eval(&self, env: &mut HashMap<String, Node>, node: Node) -> Result<Node, EvalError> {
        match node {
            Node::Integer(_) => Ok(node),
            Node::Keyword(kwd) => {
                let cloned_env = env.clone();
                Ok(match cloned_env.get(&kwd) {
                    Some(x) => try!(self.eval(env, x.clone())),
                    None => Node::Keyword(kwd),
                })
            },
            Node::List(ref xs) => self.eval_func(env, &node, xs),
            Node::QuotedList(x) => Ok(Node::List(x)),
            _ => Ok(node),
        }
    }

    fn eval_func(&self, env: &mut HashMap<String, Node>, node: &Node, xs: &Vec<Node>) -> Result<Node, EvalError> {
        let (hd, tl) = xs.split_first().unwrap();
        if let &Node::Keyword(ref kwd) = hd {
            Ok(match kwd.as_str() {
                "+" => try!(self.calc_integer(env, &|a, i| a + i, tl, node)),
                "-" => try!(self.calc_integer(env, &|a, i| a - i, tl, node)),
                "*" => try!(self.calc_integer(env, &|a, i| a * i, tl, node)),
                "/" => try!(self.calc_integer(env, &|a, i| a / i, tl, node)),
                "=" => try!(self.cond(env, &|a, i| a == i, tl, node)),
                ">" => try!(self.cond(env, &|a, i| a > i, tl, node)),
                ">=" => try!(self.cond(env, &|a, i| a >= i, tl, node)),
                "<" => try!(self.cond(env, &|a, i| a < i, tl, node)),
                "<=" => try!(self.cond(env, &|a, i| a <= i, tl, node)),
                "/=" => try!(self.cond(env, &|a, i| a != i, tl, node)),
                "if" => try!(self.if_then_else(env, tl, node)),
                "car" => try!(self.car(env, tl, node)),
                "cdr" => try!(self.cdr(env, tl, node)),
                "setq" => try!(self.setq(env, tl, node)),
                "lambda" => try!(self.lambda(env, tl, node)),
                _ =>  {
                    let cloned_env = env.clone();
                    match cloned_env.get(kwd) {
                        Some(f) => try!(self.call(env, &tl, &f)),
                        None => return Err(EvalError(format!("Unknown keyword: {:?}", kwd)))
                    }
                }
            })
        }
        else {
            Err(EvalError(format!("Unexpected node: {:?}", node)))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use super::Eval;
    use parser::Node;

    #[test]
    fn eval() {
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Integer(40),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("*")),
                        Node::Integer(6),
                        Node::List(
                            vec![
                                Node::Keyword(String::from("-")),
                                Node::Integer(42),
                                Node::Integer(35),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("car")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(42),
                                Node::Integer(-123),
                                Node::Integer(0),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        assert_eq!(
            Node::QuotedList(
                vec![
                    Node::Integer(4),
                    Node::Integer(2),
                ]
            ),
            Eval::new().eval(
                &mut HashMap::new(),
                Node::List(
                    vec![
                        Node::Keyword(String::from("cdr")),
                        Node::QuotedList(
                            vec![
                                Node::Integer(0),
                                Node::Integer(4),
                                Node::Integer(2),
                            ]
                        ),
                    ]
                )
            ).unwrap()
        );

        let env0 = &mut HashMap::new();
        env0.insert(String::from("x"), Node::Integer(40));
        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env0,
                Node::List(
                    vec![
                        Node::Keyword(String::from("+")),
                        Node::Integer(2),
                        Node::Keyword(String::from("x"))
                    ]
                )
            ).unwrap()
        );

        let env1 = &mut HashMap::new();
        Eval::new().eval(
            env1,
            Node::List(
                vec![
                    Node::Keyword(String::from("setq")),
                    Node::Keyword(String::from("add")),
                    Node::List(
                        vec![
                            Node::Keyword(String::from("lambda")),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                            Node::List(
                                vec![
                                    Node::Keyword(String::from("+")),
                                    Node::Keyword(String::from("a")),
                                    Node::Keyword(String::from("b")),
                                ]
                            ),
                        ]
                    )
                ]
            )
        );

        assert_eq!(
            Node::Integer(42),
            Eval::new().eval(
                env1,
                Node::List(
                    vec![
                        Node::Keyword(String::from("add")),
                        Node::Integer(40),
                        Node::Integer(2),
                    ]
                )
            ).unwrap()
        );
    }
}

<|endoftext|>


<commit_before>use super::*;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Expr {
    /// A `box x` expression.
    Box(Box<Expr>),
    /// First expr is the place; second expr is the value.
    InPlace(Box<Expr>, Box<Expr>),
    /// An array (`[a, b, c, d]`)
    Vec(Vec<Expr>),
    /// A function call
    ///
    /// The first field resolves to the function itself,
    /// and the second field is the list of arguments
    Call(Box<Expr>, Vec<Expr>),
    /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
    ///
    /// The `Ident` is the identifier for the method name.
    /// The vector of `Ty`s are the ascripted type parameters for the method
    /// (within the angle brackets).
    ///
    /// The first element of the vector of `Expr`s is the expression that evaluates
    /// to the object on which the method is being called on (the receiver),
    /// and the remaining elements are the rest of the arguments.
    ///
    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
    /// `ExprKind::MethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
    MethodCall(Ident, Vec<Ty>, Vec<Expr>),
    /// A tuple (`(a, b, c, d)`)
    Tup(Vec<Expr>),
    /// A binary operation (For example: `a + b`, `a * b`)
    Binary(BinOp, Box<Expr>, Box<Expr>),
    /// A unary operation (For example: `!x`, `*x`)
    Unary(UnOp, Box<Expr>),
    /// A literal (For example: `1`, `"foo"`)
    Lit(Lit),
    /// A cast (`foo as f64`)
    Cast(Box<Expr>, Box<Ty>),
    Type(Box<Expr>, Box<Ty>),
    /// An `if` block, with an optional else block
    ///
    /// `if expr { block } else { expr }`
    If(Box<Expr>, Box<Block>, Option<Box<Expr>>),
    /// An `if let` expression with an optional else block
    ///
    /// `if let pat = expr { block } else { expr }`
    ///
    /// This is desugared to a `match` expression.
    IfLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Box<Expr>>),
    /// A while loop, with an optional label
    ///
    /// `'label: while expr { block }`
    While(Box<Expr>, Box<Block>, Option<Ident>),
    /// A while-let loop, with an optional label
    ///
    /// `'label: while let pat = expr { block }`
    ///
    /// This is desugared to a combination of `loop` and `match` expressions.
    WhileLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
    /// A for loop, with an optional label
    ///
    /// `'label: for pat in expr { block }`
    ///
    /// This is desugared to a combination of `loop` and `match` expressions.
    ForLoop(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
    /// Conditionless loop (can be exited with break, continue, or return)
    ///
    /// `'label: loop { block }`
    Loop(Box<Block>, Option<Ident>),
    /// A `match` block.
    Match(Box<Expr>, Vec<Arm>),
    /// A closure (for example, `move |a, b, c| {a + b + c}`)
    Closure(CaptureBy, Box<FnDecl>, Box<Block>),
    /// A block (`{ ... }`)
    Block(Box<Block>),

    /// An assignment (`a = foo()`)
    Assign(Box<Expr>, Box<Expr>),
    /// An assignment with an operator
    ///
    /// For example, `a += 1`.
    AssignOp(BinOp, Box<Expr>, Box<Expr>),
    /// Access of a named struct field (`obj.foo`)
    Field(Box<Expr>, Ident),
    /// Access of an unnamed field of a struct or tuple-struct
    ///
    /// For example, `foo.0`.
    TupField(Box<Expr>, usize),
    /// An indexing operation (`foo[2]`)
    Index(Box<Expr>, Box<Expr>),
    /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`)
    Range(Option<Box<Expr>>, Option<Box<Expr>>, RangeLimits),

    /// Variable reference, possibly containing `::` and/or type
    /// parameters, e.g. foo::bar::<baz>.
    ///
    /// Optionally "qualified",
    /// E.g. `<Vec<T> as SomeTrait>::SomeType`.
    Path(Option<QSelf>, Path),

    /// A referencing operation (`&a` or `&mut a`)
    AddrOf(Mutability, Box<Expr>),
    /// A `break`, with an optional label to break
    Break(Option<Ident>),
    /// A `continue`, with an optional label
    Continue(Option<Ident>),
    /// A `return`, with an optional value to be returned
    Ret(Option<Box<Expr>>),

    /// A macro invocation; pre-expansion
    Mac(Mac),

    /// A struct literal expression.
    ///
    /// For example, `Foo {x: 1, y: 2}`, or
    /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
    Struct(Path, Vec<Field>, Option<Box<Expr>>),

    /// An array literal constructed from one repeated element.
    ///
    /// For example, `[1; 5]`. The first expression is the element
    /// to be repeated; the second is the number of times to repeat it.
    Repeat(Box<Expr>, Box<Expr>),

    /// No-op: used solely so we can pretty-print faithfully
    Paren(Box<Expr>),

    /// `expr?`
    Try(Box<Expr>),
}

/// A Block (`{ .. }`).
///
/// E.g. `{ .. }` as in `fn foo() { .. }`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Block {
    /// Statements in a block
    pub stmts: Vec<Stmt>,
    /// Distinguishes between `unsafe { ... }` and `{ ... }`
    pub rules: BlockCheckMode,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BlockCheckMode {
    Default,
    Unsafe,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Stmt {
    /// A local (let) binding.
    Local(Box<Local>),

    /// An item definition.
    Item(Box<Item>),

    /// Expr without trailing semi-colon.
    Expr(Box<Expr>),

    Semi(Box<Expr>),

    Mac(Box<(Mac, MacStmtStyle, Vec<Attribute>)>),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum MacStmtStyle {
    /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
    /// `foo!(...);`, `foo![...];`
    Semicolon,
    /// The macro statement had braces; e.g. foo! { ... }
    Braces,
    /// The macro statement had parentheses or brackets and no semicolon; e.g.
    /// `foo!(...)`. All of these will end up being converted into macro
    /// expressions.
    NoBraces,
}

/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Local {
    pub pat: Box<Pat>,
    pub ty: Option<Box<Ty>>,
    /// Initializer expression to set the value, if any
    pub init: Option<Box<Expr>>,
    pub attrs: Vec<Attribute>,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BinOp {
    /// The `+` operator (addition)
    Add,
    /// The `-` operator (subtraction)
    Sub,
    /// The `*` operator (multiplication)
    Mul,
    /// The `/` operator (division)
    Div,
    /// The `%` operator (modulus)
    Rem,
    /// The `&&` operator (logical and)
    And,
    /// The `||` operator (logical or)
    Or,
    /// The `^` operator (bitwise xor)
    BitXor,
    /// The `&` operator (bitwise and)
    BitAnd,
    /// The `|` operator (bitwise or)
    BitOr,
    /// The `<<` operator (shift left)
    Shl,
    /// The `>>` operator (shift right)
    Shr,
    /// The `==` operator (equality)
    Eq,
    /// The `<` operator (less than)
    Lt,
    /// The `<=` operator (less than or equal to)
    Le,
    /// The `!=` operator (not equal to)
    Ne,
    /// The `>=` operator (greater than or equal to)
    Ge,
    /// The `>` operator (greater than)
    Gt,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum UnOp {
    /// The `*` operator for dereferencing
    Deref,
    /// The `!` operator for logical inversion
    Not,
    /// The `-` operator for negation
    Neg,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Pat {
    /// Represents a wildcard pattern (`_`)
    Wild,

    /// A `PatKind::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`),
    /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
    /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
    /// during name resolution.
    Ident(BindingMode, Ident, Option<Box<Pat>>),

    /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
    /// The `bool` is `true` in the presence of a `..`.
    Struct(Path, Vec<FieldPat>, bool),

    /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
    /// 0 <= position <= subpats.len()
    TupleStruct(Path, Vec<Pat>, Option<usize>),

    /// A possibly qualified path pattern.
    /// Unquailfied path patterns `A::B::C` can legally refer to variants, structs, constants
    /// or associated constants. Quailfied path patterns `<A>::B::C`/`<A as Trait>::B::C` can
    /// only legally refer to associated constants.
    Path(Option<QSelf>, Path),

    /// A tuple pattern `(a, b)`.
    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
    /// 0 <= position <= subpats.len()
    Tuple(Vec<Pat>, Option<usize>),
    /// A `box` pattern
    Box(Box<Pat>),
    /// A reference pattern, e.g. `&mut (a, b)`
    Ref(Box<Pat>, Mutability),
    /// A literal
    Lit(Box<Expr>),
    /// A range pattern, e.g. `1...2`
    Range(Box<Expr>, Box<Expr>),
    /// `[a, b, ..i, y, z]` is represented as:
    ///     `PatKind::Vec(box [a, b], Some(i), box [y, z])`
    Vec(Vec<Pat>, Option<Box<Pat>>, Vec<Pat>),
    /// A macro pattern; pre-expansion
    Mac(Mac),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Arm {
    pub attrs: Vec<Attribute>,
    pub pats: Vec<Pat>,
    pub guard: Option<Box<Expr>>,
    pub body: Box<Expr>,
}

/// A capture clause
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum CaptureBy {
    Value,
    Ref,
}

/// Limit types of a range (inclusive or exclusive)
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum RangeLimits {
    /// Inclusive at the beginning, exclusive at the end
    HalfOpen,
    /// Inclusive at the beginning and end
    Closed,
}

/// A single field in a struct pattern
///
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
/// are treated the same as` x: x, y: ref y, z: ref mut z`,
/// except is_shorthand is true
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FieldPat {
    /// The identifier for the field
    pub ident: Ident,
    /// The pattern the field is destructured to
    pub pat: Box<Pat>,
    pub is_shorthand: bool,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BindingMode {
    ByRef(Mutability),
    ByValue(Mutability),
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use lit::parsing::lit;

    named!(expr -> Expr, alt!(
        // TODO other expressions
        lit => { Expr::Lit }
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Expr {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Expr::Lit(ref lit) => lit.to_tokens(tokens),
                _ => unimplemented!(),
            }
        }
    }
}
<commit_msg>Remove unused expr parser<commit_after>use super::*;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Expr {
    /// A `box x` expression.
    Box(Box<Expr>),
    /// First expr is the place; second expr is the value.
    InPlace(Box<Expr>, Box<Expr>),
    /// An array (`[a, b, c, d]`)
    Vec(Vec<Expr>),
    /// A function call
    ///
    /// The first field resolves to the function itself,
    /// and the second field is the list of arguments
    Call(Box<Expr>, Vec<Expr>),
    /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
    ///
    /// The `Ident` is the identifier for the method name.
    /// The vector of `Ty`s are the ascripted type parameters for the method
    /// (within the angle brackets).
    ///
    /// The first element of the vector of `Expr`s is the expression that evaluates
    /// to the object on which the method is being called on (the receiver),
    /// and the remaining elements are the rest of the arguments.
    ///
    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
    /// `ExprKind::MethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
    MethodCall(Ident, Vec<Ty>, Vec<Expr>),
    /// A tuple (`(a, b, c, d)`)
    Tup(Vec<Expr>),
    /// A binary operation (For example: `a + b`, `a * b`)
    Binary(BinOp, Box<Expr>, Box<Expr>),
    /// A unary operation (For example: `!x`, `*x`)
    Unary(UnOp, Box<Expr>),
    /// A literal (For example: `1`, `"foo"`)
    Lit(Lit),
    /// A cast (`foo as f64`)
    Cast(Box<Expr>, Box<Ty>),
    Type(Box<Expr>, Box<Ty>),
    /// An `if` block, with an optional else block
    ///
    /// `if expr { block } else { expr }`
    If(Box<Expr>, Box<Block>, Option<Box<Expr>>),
    /// An `if let` expression with an optional else block
    ///
    /// `if let pat = expr { block } else { expr }`
    ///
    /// This is desugared to a `match` expression.
    IfLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Box<Expr>>),
    /// A while loop, with an optional label
    ///
    /// `'label: while expr { block }`
    While(Box<Expr>, Box<Block>, Option<Ident>),
    /// A while-let loop, with an optional label
    ///
    /// `'label: while let pat = expr { block }`
    ///
    /// This is desugared to a combination of `loop` and `match` expressions.
    WhileLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
    /// A for loop, with an optional label
    ///
    /// `'label: for pat in expr { block }`
    ///
    /// This is desugared to a combination of `loop` and `match` expressions.
    ForLoop(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
    /// Conditionless loop (can be exited with break, continue, or return)
    ///
    /// `'label: loop { block }`
    Loop(Box<Block>, Option<Ident>),
    /// A `match` block.
    Match(Box<Expr>, Vec<Arm>),
    /// A closure (for example, `move |a, b, c| {a + b + c}`)
    Closure(CaptureBy, Box<FnDecl>, Box<Block>),
    /// A block (`{ ... }`)
    Block(Box<Block>),

    /// An assignment (`a = foo()`)
    Assign(Box<Expr>, Box<Expr>),
    /// An assignment with an operator
    ///
    /// For example, `a += 1`.
    AssignOp(BinOp, Box<Expr>, Box<Expr>),
    /// Access of a named struct field (`obj.foo`)
    Field(Box<Expr>, Ident),
    /// Access of an unnamed field of a struct or tuple-struct
    ///
    /// For example, `foo.0`.
    TupField(Box<Expr>, usize),
    /// An indexing operation (`foo[2]`)
    Index(Box<Expr>, Box<Expr>),
    /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`)
    Range(Option<Box<Expr>>, Option<Box<Expr>>, RangeLimits),

    /// Variable reference, possibly containing `::` and/or type
    /// parameters, e.g. foo::bar::<baz>.
    ///
    /// Optionally "qualified",
    /// E.g. `<Vec<T> as SomeTrait>::SomeType`.
    Path(Option<QSelf>, Path),

    /// A referencing operation (`&a` or `&mut a`)
    AddrOf(Mutability, Box<Expr>),
    /// A `break`, with an optional label to break
    Break(Option<Ident>),
    /// A `continue`, with an optional label
    Continue(Option<Ident>),
    /// A `return`, with an optional value to be returned
    Ret(Option<Box<Expr>>),

    /// A macro invocation; pre-expansion
    Mac(Mac),

    /// A struct literal expression.
    ///
    /// For example, `Foo {x: 1, y: 2}`, or
    /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
    Struct(Path, Vec<Field>, Option<Box<Expr>>),

    /// An array literal constructed from one repeated element.
    ///
    /// For example, `[1; 5]`. The first expression is the element
    /// to be repeated; the second is the number of times to repeat it.
    Repeat(Box<Expr>, Box<Expr>),

    /// No-op: used solely so we can pretty-print faithfully
    Paren(Box<Expr>),

    /// `expr?`
    Try(Box<Expr>),
}

/// A Block (`{ .. }`).
///
/// E.g. `{ .. }` as in `fn foo() { .. }`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Block {
    /// Statements in a block
    pub stmts: Vec<Stmt>,
    /// Distinguishes between `unsafe { ... }` and `{ ... }`
    pub rules: BlockCheckMode,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BlockCheckMode {
    Default,
    Unsafe,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Stmt {
    /// A local (let) binding.
    Local(Box<Local>),

    /// An item definition.
    Item(Box<Item>),

    /// Expr without trailing semi-colon.
    Expr(Box<Expr>),

    Semi(Box<Expr>),

    Mac(Box<(Mac, MacStmtStyle, Vec<Attribute>)>),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum MacStmtStyle {
    /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
    /// `foo!(...);`, `foo![...];`
    Semicolon,
    /// The macro statement had braces; e.g. foo! { ... }
    Braces,
    /// The macro statement had parentheses or brackets and no semicolon; e.g.
    /// `foo!(...)`. All of these will end up being converted into macro
    /// expressions.
    NoBraces,
}

/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Local {
    pub pat: Box<Pat>,
    pub ty: Option<Box<Ty>>,
    /// Initializer expression to set the value, if any
    pub init: Option<Box<Expr>>,
    pub attrs: Vec<Attribute>,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BinOp {
    /// The `+` operator (addition)
    Add,
    /// The `-` operator (subtraction)
    Sub,
    /// The `*` operator (multiplication)
    Mul,
    /// The `/` operator (division)
    Div,
    /// The `%` operator (modulus)
    Rem,
    /// The `&&` operator (logical and)
    And,
    /// The `||` operator (logical or)
    Or,
    /// The `^` operator (bitwise xor)
    BitXor,
    /// The `&` operator (bitwise and)
    BitAnd,
    /// The `|` operator (bitwise or)
    BitOr,
    /// The `<<` operator (shift left)
    Shl,
    /// The `>>` operator (shift right)
    Shr,
    /// The `==` operator (equality)
    Eq,
    /// The `<` operator (less than)
    Lt,
    /// The `<=` operator (less than or equal to)
    Le,
    /// The `!=` operator (not equal to)
    Ne,
    /// The `>=` operator (greater than or equal to)
    Ge,
    /// The `>` operator (greater than)
    Gt,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum UnOp {
    /// The `*` operator for dereferencing
    Deref,
    /// The `!` operator for logical inversion
    Not,
    /// The `-` operator for negation
    Neg,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Pat {
    /// Represents a wildcard pattern (`_`)
    Wild,

    /// A `PatKind::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`),
    /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
    /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
    /// during name resolution.
    Ident(BindingMode, Ident, Option<Box<Pat>>),

    /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
    /// The `bool` is `true` in the presence of a `..`.
    Struct(Path, Vec<FieldPat>, bool),

    /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
    /// 0 <= position <= subpats.len()
    TupleStruct(Path, Vec<Pat>, Option<usize>),

    /// A possibly qualified path pattern.
    /// Unquailfied path patterns `A::B::C` can legally refer to variants, structs, constants
    /// or associated constants. Quailfied path patterns `<A>::B::C`/`<A as Trait>::B::C` can
    /// only legally refer to associated constants.
    Path(Option<QSelf>, Path),

    /// A tuple pattern `(a, b)`.
    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
    /// 0 <= position <= subpats.len()
    Tuple(Vec<Pat>, Option<usize>),
    /// A `box` pattern
    Box(Box<Pat>),
    /// A reference pattern, e.g. `&mut (a, b)`
    Ref(Box<Pat>, Mutability),
    /// A literal
    Lit(Box<Expr>),
    /// A range pattern, e.g. `1...2`
    Range(Box<Expr>, Box<Expr>),
    /// `[a, b, ..i, y, z]` is represented as:
    ///     `PatKind::Vec(box [a, b], Some(i), box [y, z])`
    Vec(Vec<Pat>, Option<Box<Pat>>, Vec<Pat>),
    /// A macro pattern; pre-expansion
    Mac(Mac),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Arm {
    pub attrs: Vec<Attribute>,
    pub pats: Vec<Pat>,
    pub guard: Option<Box<Expr>>,
    pub body: Box<Expr>,
}

/// A capture clause
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum CaptureBy {
    Value,
    Ref,
}

/// Limit types of a range (inclusive or exclusive)
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum RangeLimits {
    /// Inclusive at the beginning, exclusive at the end
    HalfOpen,
    /// Inclusive at the beginning and end
    Closed,
}

/// A single field in a struct pattern
///
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
/// are treated the same as` x: x, y: ref y, z: ref mut z`,
/// except is_shorthand is true
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FieldPat {
    /// The identifier for the field
    pub ident: Ident,
    /// The pattern the field is destructured to
    pub pat: Box<Pat>,
    pub is_shorthand: bool,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BindingMode {
    ByRef(Mutability),
    ByValue(Mutability),
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Expr {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Expr::Lit(ref lit) => lit.to_tokens(tokens),
                _ => unimplemented!(),
            }
        }
    }
}
<|endoftext|>


<commit_before>use util::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH};

const HASH_SHIFT: i32 = 5;
const HASH_MASK: i32 = 32767;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Which {
    Hash1,
    Hash2,
}

pub struct ZopfliHash {
    head: Vec<i32>,  /* Hash value to index of its most recent occurrence. */
    prev: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval: Vec<i32>,  /* Index to hash value at this index. */
    val: i32,  /* Current hash value. */

    /* Fields with similar purpose as the above hash, but for the second hash with
    a value that is calculated differently.  */
    head2: Vec<i32>,  /* Hash value to index of its most recent occurrence. */
    prev2: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval2: Vec<i32>,  /* Index to hash value at this index. */
    val2: i32,  /* Current hash value. */

    pub same: Vec<u16>,  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new(window_size: usize) -> ZopfliHash {
        ZopfliHash {
           head: vec![-1; 65536],
           prev: (0..window_size as u16).collect(),
           hashval: vec![-1; window_size],
           val: 0,

           /* Fields with similar purpose as the above hash, but for the second hash with
           a value that is calculated differently.  */
           head2: vec![-1; 65536],
           prev2: (0..window_size as u16).collect(),
           hashval2: vec![-1; window_size],
           val2: 0,

           same: vec![0; window_size],
       }
    }

    pub fn reset(&mut self, window_size: usize) {
        self.val = 0;
        self.head = vec![-1; 65536];
        self.prev = (0..window_size as u16).collect();
        self.hashval = vec![-1; window_size];

        self.same = vec![0; window_size];
        self.val2 = 0;
        self.head2 = vec![-1; 65536];
        self.prev2 = (0..window_size as u16).collect();
        self.hashval2 = vec![-1; window_size];
    }

    pub fn warmup(&mut self, arr: &[u8], pos: usize, end: usize) {
        let c = arr[pos];
        self.update_val(c);

        if pos + 1 < end {
            let c = arr[pos + 1];
            self.update_val(c);
        }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    fn update_val(&mut self, c: u8) {
        self.val = ((self.val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
    }

    pub fn update(&mut self, array: &[u8], pos: usize) {
        let hash_value = array.get(pos + ZOPFLI_MIN_MATCH - 1).cloned().unwrap_or(0);
        self.update_val(hash_value);

        let hpos = pos & ZOPFLI_WINDOW_MASK;
        self.hashval[hpos] = self.val;

        let index = self.val as usize;
        if self.head[index] != -1 && self.hashval[self.head[index] as usize] == self.val {
            self.prev[hpos] = self.head[index] as u16;
        } else {
            self.prev[hpos] = hpos as u16;
        }
        self.head[index] = hpos as i32;

        // Update "same".
        let mut amount = 0;
        let same_index = pos.wrapping_sub(1) & ZOPFLI_WINDOW_MASK;
        if self.same[same_index] > 1 {
            amount = self.same[same_index] as i32 - 1;
        }

        while pos + amount as usize + 1 < array.len() && array[pos] == array[pos + amount as usize + 1] && amount < -1 {
            amount += 1;
        }
        self.same[hpos] = amount as u16;

        self.val2 = ((self.same[hpos].wrapping_sub(ZOPFLI_MIN_MATCH as u16) & 255) ^ self.val as u16) as i32;
        self.hashval2[hpos] = self.val2;

        let index2 = self.val2 as usize;
        if self.head2[index2] != -1 && self.hashval2[self.head2[index2] as usize] == self.val2 {
            self.prev2[hpos] = self.head2[index2] as u16;
        } else {
            self.prev2[hpos] = hpos as u16;
        }
        self.head2[index2] = hpos as i32;
    }

    pub fn head_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.head[index],
            Which::Hash2 => self.head2[index],
        }
    }

    pub fn prev_at(&self, index: usize, which: Which) -> u16 {
        match which {
            Which::Hash1 => self.prev[index],
            Which::Hash2 => self.prev2[index],
        }
    }

    pub fn hash_val_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hashval[index],
            Which::Hash2 => self.hashval2[index],
        }
    }

    pub fn val(&self, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.val,
            Which::Hash2 => self.val2,
        }
    }
}
<commit_msg>Extract another index var that gets used multiple times<commit_after>use util::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH};

const HASH_SHIFT: i32 = 5;
const HASH_MASK: i32 = 32767;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Which {
    Hash1,
    Hash2,
}

pub struct ZopfliHash {
    head: Vec<i32>,  /* Hash value to index of its most recent occurrence. */
    prev: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval: Vec<i32>,  /* Index to hash value at this index. */
    val: i32,  /* Current hash value. */

    /* Fields with similar purpose as the above hash, but for the second hash with
    a value that is calculated differently.  */
    head2: Vec<i32>,  /* Hash value to index of its most recent occurrence. */
    prev2: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval2: Vec<i32>,  /* Index to hash value at this index. */
    val2: i32,  /* Current hash value. */

    pub same: Vec<u16>,  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new(window_size: usize) -> ZopfliHash {
        ZopfliHash {
           head: vec![-1; 65536],
           prev: (0..window_size as u16).collect(),
           hashval: vec![-1; window_size],
           val: 0,

           /* Fields with similar purpose as the above hash, but for the second hash with
           a value that is calculated differently.  */
           head2: vec![-1; 65536],
           prev2: (0..window_size as u16).collect(),
           hashval2: vec![-1; window_size],
           val2: 0,

           same: vec![0; window_size],
       }
    }

    pub fn reset(&mut self, window_size: usize) {
        self.val = 0;
        self.head = vec![-1; 65536];
        self.prev = (0..window_size as u16).collect();
        self.hashval = vec![-1; window_size];

        self.same = vec![0; window_size];
        self.val2 = 0;
        self.head2 = vec![-1; 65536];
        self.prev2 = (0..window_size as u16).collect();
        self.hashval2 = vec![-1; window_size];
    }

    pub fn warmup(&mut self, arr: &[u8], pos: usize, end: usize) {
        let c = arr[pos];
        self.update_val(c);

        if pos + 1 < end {
            let c = arr[pos + 1];
            self.update_val(c);
        }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    fn update_val(&mut self, c: u8) {
        self.val = ((self.val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
    }

    pub fn update(&mut self, array: &[u8], pos: usize) {
        let hash_value = array.get(pos + ZOPFLI_MIN_MATCH - 1).cloned().unwrap_or(0);
        self.update_val(hash_value);

        let hpos = pos & ZOPFLI_WINDOW_MASK;
        self.hashval[hpos] = self.val;

        let index = self.val as usize;
        if self.head[index] != -1 && self.hashval[self.head[index] as usize] == self.val {
            self.prev[hpos] = self.head[index] as u16;
        } else {
            self.prev[hpos] = hpos as u16;
        }
        self.head[index] = hpos as i32;

        // Update "same".
        let mut amount = 0;
        let same_index = pos.wrapping_sub(1) & ZOPFLI_WINDOW_MASK;
        if self.same[same_index] > 1 {
            amount = self.same[same_index] as i32 - 1;
        }

        let mut another_index = pos + amount as usize + 1;
        while another_index < array.len() && array[pos] == array[another_index] && amount < -1 {
            amount += 1;
            another_index += 1;
        }
        self.same[hpos] = amount as u16;

        self.val2 = ((self.same[hpos].wrapping_sub(ZOPFLI_MIN_MATCH as u16) & 255) ^ self.val as u16) as i32;
        self.hashval2[hpos] = self.val2;

        let index2 = self.val2 as usize;
        if self.head2[index2] != -1 && self.hashval2[self.head2[index2] as usize] == self.val2 {
            self.prev2[hpos] = self.head2[index2] as u16;
        } else {
            self.prev2[hpos] = hpos as u16;
        }
        self.head2[index2] = hpos as i32;
    }

    pub fn head_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.head[index],
            Which::Hash2 => self.head2[index],
        }
    }

    pub fn prev_at(&self, index: usize, which: Which) -> u16 {
        match which {
            Which::Hash1 => self.prev[index],
            Which::Hash2 => self.prev2[index],
        }
    }

    pub fn hash_val_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hashval[index],
            Which::Hash2 => self.hashval2[index],
        }
    }

    pub fn val(&self, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.val,
            Which::Hash2 => self.val2,
        }
    }
}
<|endoftext|>