<commit_before>use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
use { gfx, Texture };
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;

const POS_COMPONENTS: usize = 2;
const UV_COMPONENTS: usize = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

gfx_vertex_struct!( PositionFormat {
    pos: [f32; 2] = "pos",
});

gfx_vertex_struct!( ColorFormat {
    color: [f32; 4] = "color",
});

gfx_vertex_struct!( TexCoordsFormat {
    uv: [f32; 2] = "uv",
});

gfx_pipeline!( pipe_colored {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

gfx_pipeline!( pipe_textured {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    uv: gfx::VertexBuffer<TexCoordsFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    texture: gfx::TextureSampler<[f32; 4]> = "s_texture",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

/// The data used for drawing 2D graphics.
pub struct Gfx2d<R: gfx::Resources> {
    buffer_pos: gfx::handle::Buffer<R, f32>,
    buffer_uv: gfx::handle::Buffer<R, f32>,
    pso_colored: gfx::pso::PipelineState<R, pipe_colored::Meta>,
    pso_textured: gfx::pso::PipelineState<R, pipe_textured::Meta>,
}

impl<R: gfx::Resources> Gfx2d<R> {
    /// Creates a new Gfx2d object.
    pub fn new<F>(opengl: OpenGL, factory: &mut F) -> Self
        where F: gfx::Factory<R>
    {
        use gfx::traits::*;
        use shaders::{ colored, textured };

        let glsl = opengl.to_glsl();

        let pso_colored = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, colored::VERTEX_GLSL_120)
                .set(GLSL::V1_50, colored::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, colored::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, colored::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_colored::new()
        ).unwrap();

        let pso_textured = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, textured::VERTEX_GLSL_120)
                .set(GLSL::V1_50, textured::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, textured::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, textured::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_textured::new()
        ).unwrap();

        let buffer_pos = factory.create_buffer_dynamic(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );
        let buffer_uv = factory.create_buffer_dynamic(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            pso_colored: pso_colored,
            pso_textured: pso_textured,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C, Cf, Df, F>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        output_color: &gfx::handle::RenderTargetView<R, Cf>,
        output_stencil: &gfx::handle::DepthStencilView<R, Df>,
        viewport: Viewport,
        f: F
    )
        where C: gfx::CommandBuffer<R>,
              Cf: gfx::format::RenderFormat,
              Df: gfx::format::StencilFormat,
              F: FnOnce(Context, &mut GfxGraphics<R, C, Cf, Df>)
    {
        let ref mut g = GfxGraphics::new(
            encoder,
            output_color,
            output_stencil,
            self
        );
        let c = Context::new_viewport(viewport);
        f(c, g);
    }
}

/// Used for rendering 2D graphics.
pub struct GfxGraphics<'a, R, C, Cf, Df>
    where R: gfx::Resources + 'a,
          C: gfx::CommandBuffer<R> + 'a,
          Cf: gfx::format::RenderFormat + 'a,
          Df: gfx::format::StencilFormat + 'a,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    encoder: &'a mut gfx::Encoder<R, C>,
    output_color: &'a gfx::handle::RenderTargetView<R, Cf>,
    output_stencil: &'a gfx::handle::DepthStencilView<R, Df>,
    g2d: &'a mut Gfx2d<R>,
}

impl<'a, R, C, Cf, Df> GfxGraphics<'a, R, C, Cf, Df>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
          Cf: gfx::format::RenderFormat,
          Df: gfx::format::StencilFormat,
{
    /// Creates a new object for rendering 2D graphics.
    pub fn new(encoder: &'a mut gfx::Encoder<R, C>,
               output_color: &'a gfx::handle::RenderTargetView<R, Cf>,
               output_stencil: &'a gfx::handle::DepthStencilView<R, Df>,
               g2d: &'a mut Gfx2d<R>) -> Self {
        GfxGraphics {
            encoder: encoder,
            output_color: output_color,
            output_stencil: output_stencil,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture<R>) -> bool {
        use gfx::format::SurfaceType::*;

        match texture.surface.get_info().format {
            R4_G4_B4_A4
            | R5_G5_B5_A1
            | R8_G8_B8_A8
            | R10_G10_B10_A2
            | R16_G16_B16_A16
            | R32_G32_B32_A32 => true,
            R3_G3_B2
            | R4_G4
            | R5_G6_B5
            | R8 | R8_G8 | R8_G8_B8
            | R11_G11_B10
            | R16 | R16_G16 | R16_G16_B16
            | R32 | R32_G32 | R32_G32_B32
            | D16 | D24 | D24_S8 | D32 => false,
        }
    }
}

impl<'a, R, C, Cf, Df> Graphics for GfxGraphics<'a, R, C, Cf, Df>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
          Cf: gfx::format::RenderFormat,
          Df: gfx::format::StencilFormat,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    type Texture = Texture<R>;

    fn clear_color(&mut self, color: [f32; 4]) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            ..
        } = self;
        encoder.clear(output_color, color);
    }

    fn clear_stencil(&mut self, value: u8) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_stencil,
            ..
        } = self;
        encoder.clear_stencil(output_stencil, value);
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut pso_colored,
                ..
            },
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32]| {
            encoder.update_buffer(&buffer_pos.raw(), vertices, 0).unwrap();

            let data = pipe_colored::Data {
                pos: buffer_pos,
                color: *color,
                out_color: output_color.clone(),
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_colored, &data);
        })
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &<Self as Graphics>::Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut pso_textured,
                ..
            },
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            assert_eq!(
                vertices.len() * UV_COMPONENTS,
                texture_coords.len() * POS_COMPONENTS
            );
            encoder.update_buffer(&buffer_pos, vertices, 0).unwrap();
            encoder.update_buffer(&buffer_uv, texture_coords, 0).unwrap();

            let data = pipe_textured::Data {
                pos: buffer_pos.clone(),
                uv: buffer_uv.clone(),
                color: *color,
                texture: texture.view,
                out_color: *output_color,
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_textured, &data);
        })
    }
}
<commit_msg>It compiles<commit_after>use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
use { gfx, Texture };
use gfx::format::{DepthStencil, Rgba8};
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;

const POS_COMPONENTS: usize = 2;
const UV_COMPONENTS: usize = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

gfx_vertex_struct!( PositionFormat {
    pos: [f32; 2] = "pos",
});

gfx_vertex_struct!( ColorFormat {
    color: [f32; 4] = "color",
});

gfx_vertex_struct!( TexCoordsFormat {
    uv: [f32; 2] = "uv",
});

gfx_pipeline!( pipe_colored {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

gfx_pipeline!( pipe_textured {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    uv: gfx::VertexBuffer<TexCoordsFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    texture: gfx::TextureSampler<[f32; 4]> = "s_texture",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

/// The data used for drawing 2D graphics.
pub struct Gfx2d<R: gfx::Resources> {
    buffer_pos: gfx::handle::Buffer<R, f32>,
    buffer_uv: gfx::handle::Buffer<R, f32>,
    pso_colored: gfx::pso::PipelineState<R, pipe_colored::Meta>,
    pso_textured: gfx::pso::PipelineState<R, pipe_textured::Meta>,
    sampler: gfx::handle::Sampler<R>,
}

impl<R: gfx::Resources> Gfx2d<R> {
    /// Creates a new Gfx2d object.
    pub fn new<F>(opengl: OpenGL, factory: &mut F) -> Self
        where F: gfx::Factory<R>
    {
        use gfx::traits::*;
        use shaders::{ colored, textured };

        let glsl = opengl.to_glsl();

        let pso_colored = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, colored::VERTEX_GLSL_120)
                .set(GLSL::V1_50, colored::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, colored::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, colored::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_colored::new()
        ).unwrap();

        let pso_textured = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, textured::VERTEX_GLSL_120)
                .set(GLSL::V1_50, textured::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, textured::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, textured::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_textured::new()
        ).unwrap();

        let buffer_pos = factory.create_buffer_dynamic(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );
        let buffer_uv = factory.create_buffer_dynamic(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );

        let sampler_info = gfx::tex::SamplerInfo::new(
            gfx::tex::FilterMethod::Bilinear,
            gfx::tex::WrapMode::Clamp
        );
        let sampler = factory.create_sampler(sampler_info);

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            pso_colored: pso_colored,
            pso_textured: pso_textured,
            sampler: sampler
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C, F>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        output_color: &gfx::handle::RenderTargetView<R, Rgba8>,
        output_stencil: &gfx::handle::DepthStencilView<R, DepthStencil>,
        viewport: Viewport,
        f: F
    )
        where C: gfx::CommandBuffer<R>,
              F: FnOnce(Context, &mut GfxGraphics<R, C>)
    {
        let ref mut g = GfxGraphics::new(
            encoder,
            output_color,
            output_stencil,
            self
        );
        let c = Context::new_viewport(viewport);
        f(c, g);
    }
}

/// Used for rendering 2D graphics.
pub struct GfxGraphics<'a, R, C>
    where R: gfx::Resources + 'a,
          C: gfx::CommandBuffer<R> + 'a,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    encoder: &'a mut gfx::Encoder<R, C>,
    output_color: &'a gfx::handle::RenderTargetView<R, Rgba8>,
    output_stencil: &'a gfx::handle::DepthStencilView<R, DepthStencil>,
    g2d: &'a mut Gfx2d<R>,
}

impl<'a, R, C> GfxGraphics<'a, R, C>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
{
    /// Creates a new object for rendering 2D graphics.
    pub fn new(encoder: &'a mut gfx::Encoder<R, C>,
               output_color: &'a gfx::handle::RenderTargetView<R, Rgba8>,
               output_stencil: &'a gfx::handle::DepthStencilView<R, DepthStencil>,
               g2d: &'a mut Gfx2d<R>) -> Self {
        GfxGraphics {
            encoder: encoder,
            output_color: output_color,
            output_stencil: output_stencil,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture<R>) -> bool {
        use gfx::format::SurfaceType::*;

        match texture.surface.get_info().format {
            R4_G4_B4_A4
            | R5_G5_B5_A1
            | R8_G8_B8_A8
            | R10_G10_B10_A2
            | R16_G16_B16_A16
            | R32_G32_B32_A32 => true,
            R3_G3_B2
            | R4_G4
            | R5_G6_B5
            | R8 | R8_G8 | R8_G8_B8
            | R11_G11_B10
            | R16 | R16_G16 | R16_G16_B16
            | R32 | R32_G32 | R32_G32_B32
            | D16 | D24 | D24_S8 | D32 => false,
        }
    }
}

impl<'a, R, C> Graphics for GfxGraphics<'a, R, C>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    type Texture = Texture<R>;

    fn clear_color(&mut self, color: [f32; 4]) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            ..
        } = self;
        encoder.clear(output_color, color);
    }

    fn clear_stencil(&mut self, value: u8) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_stencil,
            ..
        } = self;
        encoder.clear_stencil(output_stencil, value);
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut pso_colored,
                ..
            },
            ..
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32]| {
            use std::mem::transmute;

            encoder.update_buffer(&buffer_pos, vertices, 0).unwrap();

            let data = pipe_colored::Data {
                pos: unsafe { transmute(buffer_pos.clone()) },
                color: *color,
                out_color: output_color.clone(),
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_colored, &data);
        })
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &<Self as Graphics>::Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut pso_textured,
                ref sampler,
                ..
            },
            ..
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            use std::mem::transmute;

            assert_eq!(
                vertices.len() * UV_COMPONENTS,
                texture_coords.len() * POS_COMPONENTS
            );
            encoder.update_buffer(&buffer_pos, vertices, 0).unwrap();
            encoder.update_buffer(&buffer_uv, texture_coords, 0).unwrap();

            let data = pipe_textured::Data {
                pos: unsafe { transmute(buffer_pos.clone()) },
                uv: unsafe { transmute(buffer_uv.clone()) },
                color: *color,
                texture: (texture.view.clone(), sampler.clone()),
                out_color: output_color.clone(),
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_textured, &data);
        })
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate coreutils;
use coreutils::extra::OptionalExt;
use std::env::args;
use std::io;
use std::io::Write;
//use std::rand::FloatMath::*;

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => coreutils::extra::fail("Invalid operator", &mut io::stderr())
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: any smarter way to guess an initial capacity?
    let mut tokens: Vec<Token> = Vec::with_capacity(25);

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c : char = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => return break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let g1 = try!(g_expr(token_list));
    // TODO: uncomment all of this once I can figure out why powf won't work
    /*
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    */
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens[..]).map(|answer| answer.value.to_string())
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    /*
    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
    */
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Invalid number: ", s.as_str() ].join(""),
            ParseError::UnrecognizedToken(s) => ["Unrecognized token: ", s.as_str()].join(""),
            ParseError::UnexpectedToken(found, expected) => ["Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].join(""),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        println!("{}", eval(&input.join("")));
    } else {
        let prompt = "[]> ".as_bytes();
        loop {
            stdout.write(prompt).try(&mut stderr);
            stdout.flush().try(&mut stderr);
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                       .try(&mut stderr);
            match input.trim() {
                "exit" => break,
                s => {
                    stdout.write(eval(s).as_bytes()).try(&mut stderr);
                    stdout.write("\n".as_bytes()).try(&mut stderr);
                    stdout.flush().try(&mut stderr);
                },
            }
        }
    }
}
<commit_msg>Remote 'return break'<commit_after>#![deny(warnings)]
extern crate coreutils;
use coreutils::extra::OptionalExt;
use std::env::args;
use std::io;
use std::io::Write;
//use std::rand::FloatMath::*;

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => coreutils::extra::fail("Invalid operator", &mut io::stderr())
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: any smarter way to guess an initial capacity?
    let mut tokens: Vec<Token> = Vec::with_capacity(25);

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c : char = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let g1 = try!(g_expr(token_list));
    // TODO: uncomment all of this once I can figure out why powf won't work
    /*
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    */
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens[..]).map(|answer| answer.value.to_string())
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    /*
    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
    */
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Invalid number: ", s.as_str() ].join(""),
            ParseError::UnrecognizedToken(s) => ["Unrecognized token: ", s.as_str()].join(""),
            ParseError::UnexpectedToken(found, expected) => ["Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].join(""),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        println!("{}", eval(&input.join("")));
    } else {
        let prompt = "[]> ".as_bytes();
        loop {
            stdout.write(prompt).try(&mut stderr);
            stdout.flush().try(&mut stderr);
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                       .try(&mut stderr);
            match input.trim() {
                "exit" => break,
                s => {
                    stdout.write(eval(s).as_bytes()).try(&mut stderr);
                    stdout.write("\n".as_bytes()).try(&mut stderr);
                    stdout.flush().try(&mut stderr);
                },
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            String::from("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        // Don't continue execution
        false
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUST_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUST_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUST_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUST_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`.
    // Do this late, so we really only apply this to miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUST_CTFE_BACKTRACE", &var);
        }
    }
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \
                     build-time specify `RUST_SYSROOT` env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut seed: Option<u64> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")).unwrap();
                    if seed_raw.len() > 8 {
                        panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));

                },
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot and let rustc know about it.
    let sysroot_flag = String::from("--sysroot");
    if !rustc_args.contains(&sysroot_flag) {
        rustc_args.push(sysroot_flag);
        rustc_args.push(find_sysroot());
    }
    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig { validate, args: miri_args, seed };
    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<commit_msg>RUST_LOG got renamed to RUSTC_LOG<commit_after>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            String::from("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        // Don't continue execution
        false
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`.
    // Do this late, so we really only apply this to miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUST_CTFE_BACKTRACE", &var);
        }
    }
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \
                     build-time specify `RUST_SYSROOT` env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut seed: Option<u64> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")).unwrap();
                    if seed_raw.len() > 8 {
                        panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));

                },
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot and let rustc know about it.
    let sysroot_flag = String::from("--sysroot");
    if !rustc_args.contains(&sysroot_flag) {
        rustc_args.push(sysroot_flag);
        rustc_args.push(find_sysroot());
    }
    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig { validate, args: miri_args, seed };
    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(io)]
#![feature(os)]
#![feature(env)]
#![feature(path)]

extern crate document;

use std::env;
use std::cmp::min;
use std::old_io::{File,BufferedWriter,stdio};

use document::parser::Parser;

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn process_input<R>(input: R)
    where R: Reader
{
    let mut input = input;
    let data = match input.read_to_string() {
        Ok(x) => x,
        Err(x) => panic!("Can't read: {}", x),
    };

    let p = Parser::new();

    let package = match p.parse(&data) {
        Ok(d) => d,
        Err(point) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    };

    let mut out = BufferedWriter::new(stdio::stdout_raw());

    {
        let d = package.as_document();
        document::writer::format_document(&d, &mut out).ok().expect("I can't output");
    }
}

#[allow(dead_code)]
fn main() {
    let args: Result<Vec<_>, _> = env::args().map(|a| a.into_string()).collect();
    let mut args = args.unwrap();

    let filename = args.remove(1);

    if filename == "-" {
        process_input(stdio::stdin_raw());
    } else {
        process_input(File::open(&Path::new(filename)))
    }
}
<commit_msg>env::args returns Strings<commit_after>#![feature(collections)]
#![feature(io)]
#![feature(env)]
#![feature(path)]

extern crate document;

use std::env;
use std::cmp::min;
use std::old_io::{File,BufferedWriter,stdio};

use document::parser::Parser;

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn process_input<R>(input: R)
    where R: Reader
{
    let mut input = input;
    let data = match input.read_to_string() {
        Ok(x) => x,
        Err(x) => panic!("Can't read: {}", x),
    };

    let p = Parser::new();

    let package = match p.parse(&data) {
        Ok(d) => d,
        Err(point) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    };

    let mut out = BufferedWriter::new(stdio::stdout_raw());

    {
        let d = package.as_document();
        document::writer::format_document(&d, &mut out).ok().expect("I can't output");
    }
}

#[allow(dead_code)]
fn main() {
    let mut args: Vec<_> = env::args().collect();

    let filename = args.remove(1);

    if filename == "-" {
        process_input(stdio::stdin_raw());
    } else {
        process_input(File::open(&Path::new(filename)))
    }
}
<|endoftext|>


<commit_before>#![feature(drain, slice_patterns)]

extern crate glium;
use glium::DisplayBuild;

extern crate fps_counter;
extern crate time;

use std::cell::{Cell, RefCell};
use std::path::PathBuf;

#[macro_use]
extern crate r3;
pub use r3::{cfg, ui};
use r3::glyph::GlyphCache;

use ui::Px;
use ui::color::Scheme;
use ui::draw::DrawCx;
use ui::event::Dispatch;
use ui::tab::Tab;
use ui::text::FontFaces;

fn main() {
    r3::ide::rustc::init_env();

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(String::from("rid3"))
        .build_glium()
        .unwrap();

    let renderer = &mut ui::render::Renderer::new(&display, FontFaces {
        regular: GlyphCache::from_data(include_bytes!("../../assets/NotoSans/NotoSans-Regular.ttf"), display.clone()).unwrap(),
        mono: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Regular.otf"), display.clone()).unwrap(),
        mono_bold: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Bold.otf"), display.clone()).unwrap()
    });

    let open_queue = RefCell::new(std::env::args().skip(1).map(PathBuf::from).collect::<Vec<_>>());
    let save_current = Cell::new(false);
    let run_current = Cell::new(false);
    let close_current = Cell::new(false);

    let tool_bar = tool_bar![
        ui::tool::Button::new("Open", || {
            open_queue.borrow_mut().extend(ui::dialog::open_file().into_iter())
        }),
        ui::tool::Button::new("Save", || save_current.set(true)),
        ui::tool::Button::new("Run", || {
            save_current.set(true);
            run_current.set(true);
        }),
        ui::tool::Button::new("Close", || close_current.set(true))
    ];
    let mut root = flow![down: tool_bar, ui::tab::Set::<ui::editor::Editor>::new()];

    let (mut x, mut y) = (0.0, 0.0);
    let mut last_update = time::precise_time_ns();
    let mut cursor = ui::draw::MouseCursor::Default;
    let mut fps_counter = fps_counter::FPSCounter::new();
    'main: loop {
        use glium::glutin::Event as E;
        use glium::glutin::{ElementState, MouseButton, MouseScrollDelta};

        let mut dirty = true;
        for event in display.poll_events() {
            dirty |= match event {
                E::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    root.dispatch(&ui::event::KeyDown(key))
                }
                E::KeyboardInput(ElementState::Released, _, Some(key)) => {
                    root.dispatch(&ui::event::KeyUp(key))
                }
                E::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseDown::new(x, y))
                }
                E::MouseInput(ElementState::Released, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseUp::new(x, y))
                }
                E::MouseMoved((nx, ny)) => {
                    x = nx as Px;
                    y = ny as Px;
                    root.dispatch(&ui::event::MouseMove::new(x, y))
                }
                // FIXME Convert lines into pixels, or vice-versa.
                E::MouseWheel(MouseScrollDelta::LineDelta(dx, dy)) |
                E::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    root.dispatch(&ui::event::MouseScroll::with(x, y,
                        ui::event::mouse::Scroll([dx as Px, dy as Px])))
                }
                E::ReceivedCharacter(c) => {
                    root.dispatch(&ui::event::TextInput(c))
                }
                E::Resized(..) => true,
                E::Closed => break 'main,
                _ => false
            }
        }

        let current = time::precise_time_ns();
        dirty |= root.dispatch(&ui::event::Update((current - last_update) as f32 / 1e9));
        last_update = current;

        if save_current.get() {
            root.kids.1.current_mut().map(|e| e.save());
            save_current.set(false);
            dirty = true;
        }

        if run_current.get() {
            root.kids.1.current().map(|e| {
                println!("{}", std::iter::repeat('\n').take(200).collect::<String>());
                r3::ide::rustc::compile_and_run(e.path());
            });
            run_current.set(false);
        }

        if close_current.get() {
            let is_unsaved = root.kids.1.current().and_then(|e| {
                if e.is_saved() {
                    None
                } else {
                    Some(())
                }
            }).is_some();
            if is_unsaved {
                println!("Save file first!");
            } else {
                root.kids.1.remove();
                dirty = true;
            }
            close_current.set(false);
        }

        {
            let mut q = open_queue.borrow_mut();
            for file in q.drain(..) {
                root.kids.1.add(ui::editor::Editor::open(file));
                dirty = true;
            }
        }

        if dirty {
            let mut draw_cx = DrawCx::new(renderer, display.draw());
            let [w, h] = draw_cx.dimensions();

            // TODO maybe integrate this with draw_cx?
            ui::layout::compute(&mut root, draw_cx.fonts(), w, h);

            draw_cx.clear(cfg::ColorScheme.background());
            draw_cx.draw(&root);

            let new_cursor = draw_cx.get_cursor();
            draw_cx.finish();

            if (new_cursor as usize) != (cursor as usize) {
                if !cfg!(windows) {
                    display.get_window().map(|w| w.set_cursor(new_cursor));
                }
                cursor = new_cursor;
            }

            let fps = fps_counter.tick();
            let tab_title = root.kids.1.current().map(|tab| tab.title());
            let title = format!("rid3: {} @ {}FPS", tab_title.as_ref().map_or("", |s| &s[..]), fps);
            display.get_window().map(|w| w.set_title(&title));
        } else {
            // Sleep for half a frame (assuming 60FPS).
            std::thread::sleep_ms(1000 / 120);
        }
    }
}
<commit_msg>Handle redraws correctly.<commit_after>#![feature(drain, slice_patterns)]

extern crate glium;
use glium::DisplayBuild;

extern crate fps_counter;
extern crate time;

use std::cell::{Cell, RefCell};
use std::path::PathBuf;

#[macro_use]
extern crate r3;
pub use r3::{cfg, ui};
use r3::glyph::GlyphCache;

use ui::Px;
use ui::color::Scheme;
use ui::draw::DrawCx;
use ui::event::Dispatch;
use ui::tab::Tab;
use ui::text::FontFaces;

fn main() {
    r3::ide::rustc::init_env();

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(String::from("rid3"))
        .build_glium()
        .unwrap();

    let renderer = &mut ui::render::Renderer::new(&display, FontFaces {
        regular: GlyphCache::from_data(include_bytes!("../../assets/NotoSans/NotoSans-Regular.ttf"), display.clone()).unwrap(),
        mono: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Regular.otf"), display.clone()).unwrap(),
        mono_bold: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Bold.otf"), display.clone()).unwrap()
    });

    let open_queue = RefCell::new(std::env::args().skip(1).map(PathBuf::from).collect::<Vec<_>>());
    let save_current = Cell::new(false);
    let run_current = Cell::new(false);
    let close_current = Cell::new(false);

    let tool_bar = tool_bar![
        ui::tool::Button::new("Open", || {
            open_queue.borrow_mut().extend(ui::dialog::open_file().into_iter())
        }),
        ui::tool::Button::new("Save", || save_current.set(true)),
        ui::tool::Button::new("Run", || {
            save_current.set(true);
            run_current.set(true);
        }),
        ui::tool::Button::new("Close", || close_current.set(true))
    ];
    let mut root = flow![down: tool_bar, ui::tab::Set::<ui::editor::Editor>::new()];

    let (mut x, mut y) = (0.0, 0.0);
    let mut last_update = time::precise_time_ns();
    let mut cursor = ui::draw::MouseCursor::Default;
    let mut fps_counter = fps_counter::FPSCounter::new();
    let mut dirty = true;
    'main: loop {
        use glium::glutin::Event as E;
        use glium::glutin::{ElementState, MouseButton, MouseScrollDelta};

        for event in display.poll_events() {
            dirty |= match event {
                E::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    root.dispatch(&ui::event::KeyDown(key))
                }
                E::KeyboardInput(ElementState::Released, _, Some(key)) => {
                    root.dispatch(&ui::event::KeyUp(key))
                }
                E::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseDown::new(x, y))
                }
                E::MouseInput(ElementState::Released, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseUp::new(x, y))
                }
                E::MouseMoved((nx, ny)) => {
                    x = nx as Px;
                    y = ny as Px;
                    root.dispatch(&ui::event::MouseMove::new(x, y))
                }
                // FIXME Convert lines into pixels, or vice-versa.
                E::MouseWheel(MouseScrollDelta::LineDelta(dx, dy)) |
                E::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    root.dispatch(&ui::event::MouseScroll::with(x, y,
                        ui::event::mouse::Scroll([dx as Px, dy as Px])))
                }
                E::ReceivedCharacter(c) => {
                    root.dispatch(&ui::event::TextInput(c))
                }
                E::Resized(..) => true,
                E::Closed => break 'main,
                _ => false
            }
        }

        let current = time::precise_time_ns();
        dirty |= root.dispatch(&ui::event::Update((current - last_update) as f32 / 1e9));
        last_update = current;

        if save_current.get() {
            root.kids.1.current_mut().map(|e| e.save());
            save_current.set(false);
            dirty = true;
        }

        if run_current.get() {
            root.kids.1.current().map(|e| {
                println!("{}", std::iter::repeat('\n').take(200).collect::<String>());
                r3::ide::rustc::compile_and_run(e.path());
            });
            run_current.set(false);
        }

        if close_current.get() {
            let is_unsaved = root.kids.1.current().and_then(|e| {
                if e.is_saved() {
                    None
                } else {
                    Some(())
                }
            }).is_some();
            if is_unsaved {
                println!("Save file first!");
            } else {
                root.kids.1.remove();
                dirty = true;
            }
            close_current.set(false);
        }

        {
            let mut q = open_queue.borrow_mut();
            for file in q.drain(..) {
                root.kids.1.add(ui::editor::Editor::open(file));
                dirty = true;
            }
        }

        if dirty {
            let mut draw_cx = DrawCx::new(renderer, display.draw());
            let [w, h] = draw_cx.dimensions();

            // TODO maybe integrate this with draw_cx?
            ui::layout::compute(&mut root, draw_cx.fonts(), w, h);

            draw_cx.clear(cfg::ColorScheme.background());
            draw_cx.draw(&root);

            let new_cursor = draw_cx.get_cursor();
            draw_cx.finish();

            if (new_cursor as usize) != (cursor as usize) {
                if !cfg!(windows) {
                    display.get_window().map(|w| w.set_cursor(new_cursor));
                }
                cursor = new_cursor;
            }

            let fps = fps_counter.tick();
            let tab_title = root.kids.1.current().map(|tab| tab.title());
            let title = format!("rid3: {} @ {}FPS", tab_title.as_ref().map_or("", |s| &s[..]), fps);
            display.get_window().map(|w| w.set_title(&title));

            dirty = false;
        } else {
            // Sleep for half a frame (assuming 60FPS).
            std::thread::sleep_ms(1000 / 120);
        }
    }
}
<|endoftext|>


<commit_before>use cargo::ops;
use cargo::util::{CliResult, CliError, Human, Config};
use cargo::util::important_paths::{find_root_manifest_for_wd};

#[derive(RustcDecodable)]
struct Options {
    arg_args: Vec<String>,
    flag_features: Vec<String>,
    flag_jobs: Option<u32>,
    flag_manifest_path: Option<String>,
    flag_no_default_features: bool,
    flag_no_run: bool,
    flag_package: Vec<String>,
    flag_target: Option<String>,
    flag_lib: bool,
    flag_bin: Vec<String>,
    flag_example: Vec<String>,
    flag_test: Vec<String>,
    flag_bench: Vec<String>,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    flag_release: bool,
    flag_no_fail_fast: bool,
}

pub const USAGE: &'static str = "
Execute all unit and integration tests of a local package

Usage:
    cargo test [options] [--] [<args>...]

Options:
    -h, --help                   Print this message
    --lib                        Test only this package's library
    --bin NAME                   Test only the specified binary
    --example NAME               Test only the specified example
    --test NAME                  Test only the specified integration test target
    --bench NAME                 Test only the specified benchmark target
    --no-run                     Compile, but don't run tests
    -p SPEC, --package SPEC ...  Package to run tests for
    -j N, --jobs N               The number of jobs to run in parallel
    --release                    Build artifacts in release mode, with optimizations
    --features FEATURES          Space-separated list of features to also build
    --no-default-features        Do not build the `default` feature
    --target TRIPLE              Build for the target triple
    --manifest-path PATH         Path to the manifest to build tests for
    -v, --verbose                Use verbose output
    -q, --quiet                  No output printed to stdout
    --color WHEN                 Coloring: auto, always, never
    --no-fail-fast               Run all tests regardless of failure

All of the trailing arguments are passed to the test binaries generated for
filtering tests and generally providing options configuring how they run. For
example, this will run all tests with the name `foo` in their name:

    cargo test foo

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be tested. If it is not given, then the
current package is tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.

The --jobs argument affects the building of the test executable but does
not affect how many jobs are used when running the tests.

Compilation can be configured via the `test` profile in the manifest.
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
    let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));
    try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..])));

    let ops = ops::TestOptions {
        no_run: options.flag_no_run,
        no_fail_fast: options.flag_no_fail_fast,
        compile_opts: ops::CompileOptions {
            config: config,
            jobs: options.flag_jobs,
            target: options.flag_target.as_ref().map(|s| &s[..]),
            features: &options.flag_features,
            no_default_features: options.flag_no_default_features,
            spec: &options.flag_package,
            exec_engine: None,
            release: options.flag_release,
            mode: ops::CompileMode::Test,
            filter: ops::CompileFilter::new(options.flag_lib,
                                            &options.flag_bin,
                                            &options.flag_test,
                                            &options.flag_example,
                                            &options.flag_bench),
            target_rustdoc_args: None,
            target_rustc_args: None,
        },
    };

    let err = try!(ops::run_tests(&root, &ops, &options.arg_args));
    match err {
        None => Ok(None),
        Some(err) => {
            Err(match err.exit.as_ref().and_then(|e| e.code()) {
                Some(i) => CliError::new("", i),
                None => CliError::from_error(Human(err), 101)
            })
        }
    }
}
<commit_msg>Document --nocapture to reduce confusion running tests.<commit_after>use cargo::ops;
use cargo::util::{CliResult, CliError, Human, Config};
use cargo::util::important_paths::{find_root_manifest_for_wd};

#[derive(RustcDecodable)]
struct Options {
    arg_args: Vec<String>,
    flag_features: Vec<String>,
    flag_jobs: Option<u32>,
    flag_manifest_path: Option<String>,
    flag_no_default_features: bool,
    flag_no_run: bool,
    flag_package: Vec<String>,
    flag_target: Option<String>,
    flag_lib: bool,
    flag_bin: Vec<String>,
    flag_example: Vec<String>,
    flag_test: Vec<String>,
    flag_bench: Vec<String>,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    flag_release: bool,
    flag_no_fail_fast: bool,
}

pub const USAGE: &'static str = "
Execute all unit and integration tests of a local package

Usage:
    cargo test [options] [--] [<args>...]

Options:
    -h, --help                   Print this message
    --lib                        Test only this package's library
    --bin NAME                   Test only the specified binary
    --example NAME               Test only the specified example
    --test NAME                  Test only the specified integration test target
    --bench NAME                 Test only the specified benchmark target
    --no-run                     Compile, but don't run tests
    -p SPEC, --package SPEC ...  Package to run tests for
    -j N, --jobs N               The number of jobs to run in parallel
    --release                    Build artifacts in release mode, with optimizations
    --features FEATURES          Space-separated list of features to also build
    --no-default-features        Do not build the `default` feature
    --target TRIPLE              Build for the target triple
    --manifest-path PATH         Path to the manifest to build tests for
    -v, --verbose                Use verbose output
    -q, --quiet                  No output printed to stdout
    --color WHEN                 Coloring: auto, always, never
    --no-fail-fast               Run all tests regardless of failure

All of the trailing arguments are passed to the test binaries generated for
filtering tests and generally providing options configuring how they run. For
example, this will run all tests with the name `foo` in their name:

    cargo test foo

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be tested. If it is not given, then the
current package is tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.

The --jobs argument affects the building of the test executable but does
not affect how many jobs are used when running the tests.

Compilation can be configured via the `test` profile in the manifest.

By default the rust test harness hides output from test execution to
keep results readable. Test output can be recovered (e.g. for debugging)
by passing `--nocapture` to the test binaries:

  cargo test -- --nocapture
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
    let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));
    try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..])));

    let ops = ops::TestOptions {
        no_run: options.flag_no_run,
        no_fail_fast: options.flag_no_fail_fast,
        compile_opts: ops::CompileOptions {
            config: config,
            jobs: options.flag_jobs,
            target: options.flag_target.as_ref().map(|s| &s[..]),
            features: &options.flag_features,
            no_default_features: options.flag_no_default_features,
            spec: &options.flag_package,
            exec_engine: None,
            release: options.flag_release,
            mode: ops::CompileMode::Test,
            filter: ops::CompileFilter::new(options.flag_lib,
                                            &options.flag_bin,
                                            &options.flag_test,
                                            &options.flag_example,
                                            &options.flag_bench),
            target_rustdoc_args: None,
            target_rustc_args: None,
        },
    };

    let err = try!(ops::run_tests(&root, &ops, &options.arg_args));
    match err {
        None => Ok(None),
        Some(err) => {
            Err(match err.exit.as_ref().and_then(|e| e.code()) {
                Some(i) => CliError::new("", i),
                None => CliError::from_error(Human(err), 101)
            })
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

macro_rules! return_first_error {
    () => {
        for args.each() |&arg| {
            if arg.is_error() {
                return arg;
            }
        };
    }
}

fn sometimes_ess( number:uint ) -> ~str {
    if number == 1 {
        ~""
    } else {
        ~"s"
    }
}

macro_rules! assert_mininum_number_of_args {
    ($function:expr $minimum:expr) => {
        if args.len() < $minimum {
            return Error(fmt!("Built-in function '%s' takes at least %u argument%s. It was called with %u '%s'", $function, $minimum, sometimes_ess($minimum), args.len(), List(args).to_str()));
        };
    }
}

macro_rules! ensure_arguments_are_numbers {
    () => {
        for args.each() |&arg| {
            if !arg.is_number() {
                return Error( fmt!("%s was given where a number was expected", arg.to_str()) );
            }
        };
    }
}

macro_rules! comparison_function {
    ($function:ident $name:expr) => {
        pub fn $function( args:~[Expression], _:@Environment ) -> Expression {
            assert_mininum_number_of_args!($name 2)
            return_first_error!()
            ensure_arguments_are_numbers!()

            let comparisons = vec::map2( args.init(), args.tail(),
                                         |a, b| {a.$function(b)});
            Bool(vec::foldl(true, comparisons, |x, &y| {x && y}))
        }
    }
}

comparison_function!(lt ~"<")
comparison_function!(le ~"<=")
comparison_function!(gt ~">")
comparison_function!(ge ~">=")

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()

    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

macro_rules! assert_arg_count_range {
    ($function:expr $minimum:expr $maximum:expr) => {
        if args.len() > $maximum || args.len() < $minimum {
            let head = fmt!("Built-in function '%s' takes", $function);
            let middle = if $minimum == $maximum {
                fmt!("only %u argument%s.", $minimum, sometimes_ess($minimum))
            } else {
                fmt!("betwen %u and %u arguments.", $minimum, $maximum)
            };
            let tail = fmt!("It was called with %u '%s'.", args.len(), List(args).to_str());

            return Error( fmt!("%s %s %s", head, middle, tail) );
        }
    }
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"not" 1 1 )

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"car" 1 1 )

    match copy args[0] {
        List(list) => list.head(),
        _ => Error( fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str()) )
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"cdr" 1 1 )

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => Error( fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str()) )
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"cons" 2 2 )

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"append" 2 2 )

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => Error( fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str()) )
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"length" 1 1 )

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => Error( fmt!("Built-in function 'length' requires a list argument. It was called with %s", List(args).to_str()) )
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"equal?" 2 2 )

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"symbol?" 1 1 )

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"list?" 1 1 )

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"null?" 1 1 )

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    List(args)
}

pub fn eq_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"eq?" 2 2 )

    Bool( args[0] == args[1] )
}

pub fn eqv_( args:~[Expression], _env:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"eqv?" 2 2 )

    eq_( args, _env )
}

#[test]
fn test_eqv_() {
    fn eqv__( args:~[Expression] ) -> Expression {
        eqv_( args, @Environment::new_global_environment() )
    }

    assert( Bool(true) == eqv__( ~[ Bool(true), Bool(true) ] ) );
    assert( Bool(true) == eqv__( ~[ Bool(false), Bool(false) ] ) );
    assert( Bool(false) == eqv__( ~[ Bool(true), Bool(false) ] ) );
    assert( Bool(true) == eqv__( ~[ Symbol(~"a"), Symbol(~"a") ] ) );
    assert( Bool(false) == eqv__( ~[ Symbol(~"b"), Symbol(~"a") ] ) );
    assert( Bool(true) == eqv__( ~[ Int(1), Int(1) ] ) );
    assert( Bool(false) == eqv__( ~[ Int(2), Int(1) ] ) );
    assert( Bool(true) == eqv__( ~[ Float(1.0), Float(1.0) ] ) );
    assert( Bool(false) == eqv__( ~[ Float(2.0), Float(1.0) ] ) );
    assert( Bool(true) == eqv__( ~[ List( ~[] ), List( ~[] ) ] ) );
    assert( Bool(false) == eqv__( ~[ List( ~[Int(1)] ), List( ~[] ) ] ) );

    let env = @Environment::new_global_environment();
    let proc = eval( parse("(lambda (x) (* x x))"), env ).first();
    let proc2 = eval( parse("(lambda (x) (* x x))"), env ).first();
    assert( Bool(true) == eqv__( ~[ proc, proc ] ) );
    assert( Bool(false) == eqv__( ~[ proc, proc2 ] ) );
}

#[test]
fn test_math() {
    test_eval( ~"(+ 4 2)", ~"6" );
    test_eval( ~"(- 4 2)", ~"2" );
    test_eval( ~"(/ 4 2)", ~"2" );
    test_eval( ~"(* 4 2)", ~"8" );
    test_eval( ~"(= 4 2)", ~"#f" );
    test_eval( ~"(= 4 4)", ~"#t" );
}

#[test]
fn test_list() {
    test_eval( ~"(list? (quote ()))", ~"#t" );
    test_eval( ~"(car (quote (1 2 3)))", ~"1" );
    test_eval( ~"(cdr (quote (1 2 3)))", ~"(2 3)" );
    test_eval( ~"(cons 1 (quote (2 3)))", ~"(1 2 3)" );
    test_eval( ~"(list 1)", ~"(1)" );
    test_eval( ~"(list)", ~"()" );
    test_eval( ~"(list 1 2 3)", ~"(1 2 3)" );
    test_eval( ~"(length (list))", ~"0" );
    test_eval( ~"(length (list 1))", ~"1" );
    test_eval( ~"(length (list 1 2))", ~"2" );
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"<", lt), (~"<=", le), (~">", gt), (~">=", ge),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"eq?", eq_), (~"eqv?", eqv_),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<commit_msg>update comments in builtins.rs<commit_after>/*
 * Built-in method definitions for scheme
 *
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 * eq?
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

macro_rules! return_first_error {
    () => {
        for args.each() |&arg| {
            if arg.is_error() {
                return arg;
            }
        };
    }
}

fn sometimes_ess( number:uint ) -> ~str {
    if number == 1 {
        ~""
    } else {
        ~"s"
    }
}

macro_rules! assert_mininum_number_of_args {
    ($function:expr $minimum:expr) => {
        if args.len() < $minimum {
            return Error(fmt!("Built-in function '%s' takes at least %u argument%s. It was called with %u '%s'", $function, $minimum, sometimes_ess($minimum), args.len(), List(args).to_str()));
        };
    }
}

macro_rules! ensure_arguments_are_numbers {
    () => {
        for args.each() |&arg| {
            if !arg.is_number() {
                return Error( fmt!("%s was given where a number was expected", arg.to_str()) );
            }
        };
    }
}

macro_rules! comparison_function {
    ($function:ident $name:expr) => {
        pub fn $function( args:~[Expression], _:@Environment ) -> Expression {
            assert_mininum_number_of_args!($name 2)
            return_first_error!()
            ensure_arguments_are_numbers!()

            let comparisons = vec::map2( args.init(), args.tail(),
                                         |a, b| {a.$function(b)});
            Bool(vec::foldl(true, comparisons, |x, &y| {x && y}))
        }
    }
}

comparison_function!(lt ~"<")
comparison_function!(le ~"<=")
comparison_function!(gt ~">")
comparison_function!(ge ~">=")

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()

    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

macro_rules! assert_arg_count_range {
    ($function:expr $minimum:expr $maximum:expr) => {
        if args.len() > $maximum || args.len() < $minimum {
            let head = fmt!("Built-in function '%s' takes", $function);
            let middle = if $minimum == $maximum {
                fmt!("only %u argument%s.", $minimum, sometimes_ess($minimum))
            } else {
                fmt!("betwen %u and %u arguments.", $minimum, $maximum)
            };
            let tail = fmt!("It was called with %u '%s'.", args.len(), List(args).to_str());

            return Error( fmt!("%s %s %s", head, middle, tail) );
        }
    }
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"not" 1 1 )

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"car" 1 1 )

    match copy args[0] {
        List(list) => list.head(),
        _ => Error( fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str()) )
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"cdr" 1 1 )

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => Error( fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str()) )
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"cons" 2 2 )

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"append" 2 2 )

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => Error( fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str()) )
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"length" 1 1 )

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => Error( fmt!("Built-in function 'length' requires a list argument. It was called with %s", List(args).to_str()) )
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"equal?" 2 2 )

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"symbol?" 1 1 )

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"list?" 1 1 )

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"null?" 1 1 )

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    List(args)
}

pub fn eq_( args:~[Expression], _:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"eq?" 2 2 )

    Bool( args[0] == args[1] )
}

pub fn eqv_( args:~[Expression], _env:@Environment) -> Expression {
    return_first_error!()
    assert_arg_count_range!( ~"eqv?" 2 2 )

    eq_( args, _env )
}

#[test]
fn test_eqv_() {
    fn eqv__( args:~[Expression] ) -> Expression {
        eqv_( args, @Environment::new_global_environment() )
    }

    assert( Bool(true) == eqv__( ~[ Bool(true), Bool(true) ] ) );
    assert( Bool(true) == eqv__( ~[ Bool(false), Bool(false) ] ) );
    assert( Bool(false) == eqv__( ~[ Bool(true), Bool(false) ] ) );
    assert( Bool(true) == eqv__( ~[ Symbol(~"a"), Symbol(~"a") ] ) );
    assert( Bool(false) == eqv__( ~[ Symbol(~"b"), Symbol(~"a") ] ) );
    assert( Bool(true) == eqv__( ~[ Int(1), Int(1) ] ) );
    assert( Bool(false) == eqv__( ~[ Int(2), Int(1) ] ) );
    assert( Bool(true) == eqv__( ~[ Float(1.0), Float(1.0) ] ) );
    assert( Bool(false) == eqv__( ~[ Float(2.0), Float(1.0) ] ) );
    assert( Bool(true) == eqv__( ~[ List( ~[] ), List( ~[] ) ] ) );
    assert( Bool(false) == eqv__( ~[ List( ~[Int(1)] ), List( ~[] ) ] ) );

    let env = @Environment::new_global_environment();
    let proc = eval( parse("(lambda (x) (* x x))"), env ).first();
    let proc2 = eval( parse("(lambda (x) (* x x))"), env ).first();
    assert( Bool(true) == eqv__( ~[ proc, proc ] ) );
    assert( Bool(false) == eqv__( ~[ proc, proc2 ] ) );
}

#[test]
fn test_math() {
    test_eval( ~"(+ 4 2)", ~"6" );
    test_eval( ~"(- 4 2)", ~"2" );
    test_eval( ~"(/ 4 2)", ~"2" );
    test_eval( ~"(* 4 2)", ~"8" );
    test_eval( ~"(= 4 2)", ~"#f" );
    test_eval( ~"(= 4 4)", ~"#t" );
}

#[test]
fn test_list() {
    test_eval( ~"(list? (quote ()))", ~"#t" );
    test_eval( ~"(car (quote (1 2 3)))", ~"1" );
    test_eval( ~"(cdr (quote (1 2 3)))", ~"(2 3)" );
    test_eval( ~"(cons 1 (quote (2 3)))", ~"(1 2 3)" );
    test_eval( ~"(list 1)", ~"(1)" );
    test_eval( ~"(list)", ~"()" );
    test_eval( ~"(list 1 2 3)", ~"(1 2 3)" );
    test_eval( ~"(length (list))", ~"0" );
    test_eval( ~"(length (list 1))", ~"1" );
    test_eval( ~"(length (list 1 2))", ~"2" );
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"<", lt), (~"<=", le), (~">", gt), (~">=", ge),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"eq?", eq_), (~"eqv?", eqv_),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<|endoftext|>