<commit_before>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn run_mode(dir: &'static str, mode: &'static str, sysroot: &str) {
    // Disable rustc's new error fomatting. It breaks these tests.
    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = mode.parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from(format!("tests/{}", dir));
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn for_all_targets<F: Fn(String)>(sysroot: &str, f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.path().iter().rev().next().unwrap().to_str().unwrap().to_owned();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from 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"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    run_mode("compile-fail", "compile-fail", &sysroot);
    for_all_targets(&sysroot, |target| {
        for file in std::fs::read_dir("tests/run-pass").unwrap() {
            let file = file.unwrap();
            if !file.metadata().unwrap().is_file() {
                continue;
            }
            let file = file.path();
            let stderr = std::io::stderr();
            writeln!(stderr.lock(), "test [miri-pass] {}", file.to_str().unwrap()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(file);
            cmd.arg(format!("--sysroot={}", sysroot));
            cmd.arg("-Dwarnings");
            cmd.arg(format!("-target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "").unwrap();
    })
}
<commit_msg>actually execute miri-pass tests<commit_after>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn run_mode(dir: &'static str, mode: &'static str, sysroot: &str) {
    // Disable rustc's new error fomatting. It breaks these tests.
    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = mode.parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from(format!("tests/{}", dir));
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn for_all_targets<F: Fn(String)>(sysroot: &str, f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.path().iter().rev().next().unwrap().to_str().unwrap().to_owned();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from 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"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    run_mode("compile-fail", "compile-fail", &sysroot);
    for_all_targets(&sysroot, |target| {
        for file in std::fs::read_dir("tests/run-pass").unwrap() {
            let file = file.unwrap();
            if !file.metadata().unwrap().is_file() {
                continue;
            }
            let file = file.path();
            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ", file.to_str().unwrap()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(file);
            cmd.arg(format!("--sysroot={}", sysroot));
            cmd.arg("-Dwarnings");
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);
            match cmd.output() {
                Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
                Ok(output) => {
                    writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
                    writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                    writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
                }
                Err(e) => writeln!(stderr.lock(), "FAILED: {}", e).unwrap(),
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "").unwrap();
    })
}
<|endoftext|>


<commit_before>use std::{fmt, path::Path};

use crate::RenderTarget;

#[derive(Clone, Default)]
pub struct Image {
    render_target: RenderTarget,
    source: String,
}

impl fmt::Debug for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Image ( source: {})", self.source)
    }
}

impl std::cmp::PartialEq for Image {
    fn eq(&self, other: &Self) -> bool {
        self.source == other.source
    }
}

impl Image {
    /// Creates a new image with the given width and height.
    pub fn new(width: u32, height: u32) -> Self {
        Image {
            render_target: RenderTarget::new(width, height),
            source: String::default(),
        }
    }

    /// Draws a u32 slice into the image.
    pub fn draw(&mut self, data: &[u32]) {
        self.render_target.data.clone_from_slice(data);
    }

    /// Create a new image from a boxed slice of colors
    pub fn from_data(width: u32, height: u32, data: Vec<u32>) -> Result<Self, String> {
        Ok(Image {
            render_target: RenderTarget::from_data(width, height, data).unwrap(),
            source: String::new(),
        })
    }

    fn from_rgba_image(image: image::RgbaImage) -> Result<Self, String> {
        let data: Vec<u32> = image
            .pixels()
            .map(|p| {
                ((p[3] as u32) << 24) | ((p[0] as u32) << 16) | ((p[1] as u32) << 8) | (p[2] as u32)
            })
            .collect();
        Self::from_data(image.width(), image.height(), data)
    }

    /// Load an image from file path. Supports BMP and PNG
    pub fn from_path<P: AsRef<Path> + std::fmt::Debug + Clone>(path: P) -> Result<Self, String> {
        let img = image::open(path.clone());

        if let Ok(img) = img {
            return Self::from_rgba_image(img.to_rgba());
        }

        Err(format!("Could not load image width path: {:?}", path))
    }

    /// Gets the width.
    pub fn width(&self) -> f64 {
        self.render_target.width() as f64
    }

    /// Gets the height.
    pub fn height(&self) -> f64 {
        self.render_target.height() as f64
    }

    pub fn data(&self) -> &[u32] {
        &self.render_target.data
    }

    pub fn data_mut(&mut self) -> &mut [u32] {
        &mut self.render_target.data
    }
}

impl From<(u32, u32, Vec<u32>)> for Image {
    fn from(image: (u32, u32, Vec<u32>)) -> Self {
        Image::from_data(image.0, image.1, image.2).unwrap()
    }
}

// --- Conversions ---

impl From<&str> for Image {
    fn from(s: &str) -> Image {
        Image::from_path(s).unwrap()
    }
}

impl From<String> for Image {
    fn from(s: String) -> Image {
        Image::from_path(s).unwrap()
    }
}

// --- Conversions ---
<commit_msg>make `from_rgba_image` public<commit_after>use std::{fmt, path::Path};

use crate::RenderTarget;

#[derive(Clone, Default)]
pub struct Image {
    render_target: RenderTarget,
    source: String,
}

impl fmt::Debug for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Image ( source: {})", self.source)
    }
}

impl std::cmp::PartialEq for Image {
    fn eq(&self, other: &Self) -> bool {
        self.source == other.source
    }
}

impl Image {
    /// Creates a new image with the given width and height.
    pub fn new(width: u32, height: u32) -> Self {
        Image {
            render_target: RenderTarget::new(width, height),
            source: String::default(),
        }
    }

    /// Draws a u32 slice into the image.
    pub fn draw(&mut self, data: &[u32]) {
        self.render_target.data.clone_from_slice(data);
    }

    /// Create a new image from a boxed slice of colors
    pub fn from_data(width: u32, height: u32, data: Vec<u32>) -> Result<Self, String> {
        Ok(Image {
            render_target: RenderTarget::from_data(width, height, data).unwrap(),
            source: String::new(),
        })
    }

    /// Creates a new image from an `RgbaImage`.
    pub fn from_rgba_image(image: image::RgbaImage) -> Result<Self, String> {
        let data: Vec<u32> = image
            .pixels()
            .map(|p| {
                ((p[3] as u32) << 24) | ((p[0] as u32) << 16) | ((p[1] as u32) << 8) | (p[2] as u32)
            })
            .collect();
        Self::from_data(image.width(), image.height(), data)
    }

    /// Load an image from file path. Supports BMP and PNG
    pub fn from_path<P: AsRef<Path> + std::fmt::Debug + Clone>(path: P) -> Result<Self, String> {
        let img = image::open(path.clone());

        if let Ok(img) = img {
            return Self::from_rgba_image(img.to_rgba());
        }

        Err(format!("Could not load image width path: {:?}", path))
    }

    /// Gets the width.
    pub fn width(&self) -> f64 {
        self.render_target.width() as f64
    }

    /// Gets the height.
    pub fn height(&self) -> f64 {
        self.render_target.height() as f64
    }

    pub fn data(&self) -> &[u32] {
        &self.render_target.data
    }

    pub fn data_mut(&mut self) -> &mut [u32] {
        &mut self.render_target.data
    }
}

impl From<(u32, u32, Vec<u32>)> for Image {
    fn from(image: (u32, u32, Vec<u32>)) -> Self {
        Image::from_data(image.0, image.1, image.2).unwrap()
    }
}

// --- Conversions ---

impl From<&str> for Image {
    fn from(s: &str) -> Image {
        Image::from_path(s).unwrap()
    }
}

impl From<String> for Image {
    fn from(s: String) -> Image {
        Image::from_path(s).unwrap()
    }
}

// --- Conversions ---
<|endoftext|>


<commit_before>#![allow(
    clippy::diverging_sub_expression,
    clippy::let_and_return,
    clippy::let_underscore_drop,
    clippy::never_loop,
    clippy::unit_arg
)]

use anyhow::{anyhow, ensure, Chain, Error, Result};
use std::fmt::Debug;
use std::iter;
use std::marker::PhantomData;
use std::ops::Add;

struct S;

impl<T> Add<T> for S {
    type Output = bool;
    fn add(self, rhs: T) -> Self::Output {
        let _ = rhs;
        false
    }
}

trait Trait: Sized {
    fn t(self, i: i32) -> i32 {
        i
    }
}

impl<T> Trait for T {}

#[track_caller]
fn assert_err<T: Debug>(result: impl FnOnce() -> Result<T>, expected: &'static str) {
    assert_eq!(result().unwrap_err().to_string(), expected);
}

#[test]
fn test_low_precedence_control_flow() {
    #[allow(unreachable_code)]
    let test = || {
        let val = loop {
            // Break has lower precedence than the comparison operators so the
            // expression here is `S + (break (1 == 1))`. It would be bad if the
            // ensure macro partitioned this input into `(S + break 1) == (1)`
            // because that means a different thing than what was written.
            ensure!(S + break 1 == 1);
        };
        Ok(val)
    };

    assert!(test().unwrap());
}

#[test]
fn test_low_precedence_binary_operator() {
    // Must not partition as `false == (true && false)`.
    let test = || Ok(ensure!(false == true && false));
    assert_err(test, "Condition failed: `false == true && false`");

    // But outside the root level, it is fine.
    let test = || Ok(ensure!(while false == true && false {} < ()));
    assert_err(
        test,
        "Condition failed: `while false == true && false { } < ()` (() vs ())",
    );
}

#[test]
fn test_closure() {
    // Must not partition as `(S + move) || (1 == 1)` by treating move as an
    // identifier, nor as `(S + move || 1) == (1)` by misinterpreting the
    // closure precedence.
    let test = || Ok(ensure!(S + move || 1 == 1));
    assert_err(test, "Condition failed: `S + (move || 1 == 1)`");

    let test = || Ok(ensure!(S + || 1 == 1));
    assert_err(test, "Condition failed: `S + (|| 1 == 1)`");

    // Must not partition as `S + ((move | ()) | 1) == 1` by treating those
    // pipes as bitwise-or.
    let test = || Ok(ensure!(S + move |()| 1 == 1));
    assert_err(test, "Condition failed: `S + (move |()| 1 == 1)`");

    let test = || Ok(ensure!(S + |()| 1 == 1));
    assert_err(test, "Condition failed: `S + (|()| 1 == 1)`");
}

#[test]
fn test_unary() {
    let mut x = &1;
    let test = || Ok(ensure!(*x == 2));
    assert_err(test, "Condition failed: `*x == 2` (1 vs 2)");

    let test = || Ok(ensure!(!x == 1));
    assert_err(test, "Condition failed: `!x == 1` (-2 vs 1)");

    let test = || Ok(ensure!(-x == 1));
    assert_err(test, "Condition failed: `-x == 1` (-1 vs 1)");

    let test = || Ok(ensure!(&x == &&2));
    assert_err(test, "Condition failed: `&x == &&2` (1 vs 2)");

    let test = || Ok(ensure!(&mut x == *&&mut &2));
    assert_err(test, "Condition failed: `&mut x == *&&mut &2` (1 vs 2)");
}

#[test]
fn test_if() {
    #[rustfmt::skip]
    let test = || Ok(ensure!(if false {}.t(1) == 2));
    assert_err(test, "Condition failed: `if false { }.t(1) == 2` (1 vs 2)");

    #[rustfmt::skip]
    let test = || Ok(ensure!(if false {} else {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if false { } else { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if false {} else if false {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if false { } else if false { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if let 1 = 2 {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if let 1 = 2 { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if let 1 | 2 = 2 {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if let 1 | 2 = 2 { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if let | 1 | 2 = 2 {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if let 1 | 2 = 2 { }.t(1) == 2` (1 vs 2)",
    );
}

#[test]
fn test_loop() {
    #[rustfmt::skip]
    let test = || Ok(ensure!(1 + loop { break 1 } == 1));
    assert_err(
        test,
        "Condition failed: `1 + loop { break 1  } == 1` (2 vs 1)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(1 + 'a: loop { break 'a 1 } == 1));
    assert_err(
        test,
        "Condition failed: `1 + 'a: loop { break 'a 1  } == 1` (2 vs 1)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(while false {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `while false { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(while let None = Some(1) {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `while let None = Some(1) { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(for _x in iter::once(0) {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `for _x in iter::once(0) { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(for | _x in iter::once(0) {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `for _x in iter::once(0) { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(for true | false in iter::empty() {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `for true | false in iter::empty() { }.t(1) == 2` (1 vs 2)",
    );
}

#[test]
fn test_match() {
    #[rustfmt::skip]
    let test = || Ok(ensure!(match 1 == 1 { true => 1, false => 0 } == 2));
    assert_err(
        test,
        "Condition failed: `match 1 == 1 { true => 1, false => 0, } == 2` (1 vs 2)",
    );
}

#[test]
fn test_atom() {
    let test = || Ok(ensure!([false, false].len() > 3));
    assert_err(
        test,
        "Condition failed: `[false, false].len() > 3` (2 vs 3)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!({ let x = 1; x } >= 3));
    assert_err(test, "Condition failed: `{ let x = 1; x } >= 3` (1 vs 3)");

    let test = || Ok(ensure!(S + async { 1 } == true));
    assert_err(
        test,
        "Condition failed: `S + async  { 1 } == true` (false vs true)",
    );

    let test = || Ok(ensure!(S + async move { 1 } == true));
    assert_err(
        test,
        "Condition failed: `S + async move  { 1 } == true` (false vs true)",
    );

    let test = || Ok(ensure!(S + unsafe { 1 } == true));
    assert_err(
        test,
        "Condition failed: `S + unsafe { 1 } == true` (false vs true)",
    );
}

#[test]
fn test_path() {
    let test = || Ok(ensure!(crate::S.t(1) == 2));
    assert_err(test, "Condition failed: `crate::S.t(1) == 2` (1 vs 2)");

    let test = || Ok(ensure!(::anyhow::Error::root_cause.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `::anyhow::Error::root_cause.t(1) == 2` (1 vs 2)",
    );

    let test = || Ok(ensure!(Error::msg::<&str>.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(Error::msg::<&str,>.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)",
    );

    let test = || Ok(ensure!(Error::msg::<<str as ToOwned>::Owned>.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Error::msg::<<str as ToOwned>::Owned>.t(1) == 2` (1 vs 2)",
    );

    let test = || Ok(ensure!(Chain::<'static>::new.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(Chain::<'static,>::new.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)",
    );
}

#[test]
fn test_macro() {
    let test = || Ok(ensure!(anyhow!("...").to_string().len() <= 1));
    assert_err(
        test,
        "Condition failed: `anyhow!(\"...\").to_string().len() <= 1` (3 vs 1)",
    );

    let test = || Ok(ensure!(vec![1].len() < 1));
    assert_err(test, "Condition failed: `vec![1].len() < 1` (1 vs 1)");

    let test = || Ok(ensure!(stringify! {} != ""));
    assert_err(
        test,
        "Condition failed: `stringify! { } != \"\"` (\"\" vs \"\")",
    );
}

#[test]
fn test_trailer() {
    let test = || Ok(ensure!((|| 1)() == 2));
    assert_err(test, "Condition failed: `(|| 1)() == 2` (1 vs 2)");

    let test = || Ok(ensure!(b"hmm"[1] == b'c'));
    assert_err(test, "Condition failed: `b\"hmm\"[1] == b'c'` (109 vs 99)");

    let test = || Ok(ensure!(PhantomData::<u8> {} != PhantomData));
    assert_err(
        test,
        "Condition failed: `PhantomData::<u8>{} != PhantomData` (PhantomData vs PhantomData)",
    );

    let result = Ok::<_, Error>(1);
    let test = || Ok(ensure!(result? == 2));
    assert_err(test, "Condition failed: `result? == 2` (1 vs 2)");

    let test = || Ok(ensure!((2, 3).1 == 2));
    assert_err(test, "Condition failed: `(2, 3).1 == 2` (3 vs 2)");

    let err = anyhow!("");
    let test = || Ok(ensure!(err.is::<&str>() == false));
    assert_err(
        test,
        "Condition failed: `err.is::<&str>() == false` (true vs false)",
    );

    let test = || Ok(ensure!(err.is::<<str as ToOwned>::Owned>() == true));
    assert_err(
        test,
        "Condition failed: `err.is::<<str as ToOwned>::Owned>() == true` (false vs true)",
    );
}
<commit_msg>Make ensure tests work on old rustc<commit_after>#![allow(
    clippy::diverging_sub_expression,
    clippy::let_and_return,
    clippy::let_underscore_drop,
    clippy::never_loop,
    clippy::unit_arg
)]

use anyhow::{anyhow, ensure, Chain, Error, Result};
use std::fmt::Debug;
use std::iter;
use std::marker::PhantomData;
use std::ops::Add;

struct S;

impl<T> Add<T> for S {
    type Output = bool;
    fn add(self, rhs: T) -> Self::Output {
        let _ = rhs;
        false
    }
}

trait Trait: Sized {
    fn t(self, i: i32) -> i32 {
        i
    }
}

impl<T> Trait for T {}

#[track_caller]
fn assert_err<T: Debug>(result: impl FnOnce() -> Result<T>, expected: &'static str) {
    let actual = result().unwrap_err().to_string();

    let mut accepted_alternatives = expected.split('\n');
    let expected = accepted_alternatives.next_back().unwrap();
    if accepted_alternatives.any(|alternative| actual == alternative) {
        return;
    }

    assert_eq!(actual, expected);
}

#[test]
fn test_low_precedence_control_flow() {
    #[allow(unreachable_code)]
    let test = || {
        let val = loop {
            // Break has lower precedence than the comparison operators so the
            // expression here is `S + (break (1 == 1))`. It would be bad if the
            // ensure macro partitioned this input into `(S + break 1) == (1)`
            // because that means a different thing than what was written.
            ensure!(S + break 1 == 1);
        };
        Ok(val)
    };

    assert!(test().unwrap());
}

#[test]
fn test_low_precedence_binary_operator() {
    // Must not partition as `false == (true && false)`.
    let test = || Ok(ensure!(false == true && false));
    assert_err(test, "Condition failed: `false == true && false`");

    // But outside the root level, it is fine.
    let test = || Ok(ensure!(while false == true && false {} < ()));
    assert_err(
        test,
        "Condition failed: `while false == true && false { } < ()` (() vs ())",
    );
}

#[test]
fn test_closure() {
    // Must not partition as `(S + move) || (1 == 1)` by treating move as an
    // identifier, nor as `(S + move || 1) == (1)` by misinterpreting the
    // closure precedence.
    let test = || Ok(ensure!(S + move || 1 == 1));
    assert_err(test, "Condition failed: `S + (move || 1 == 1)`");

    let test = || Ok(ensure!(S + || 1 == 1));
    assert_err(test, "Condition failed: `S + (|| 1 == 1)`");

    // Must not partition as `S + ((move | ()) | 1) == 1` by treating those
    // pipes as bitwise-or.
    let test = || Ok(ensure!(S + move |()| 1 == 1));
    assert_err(test, "Condition failed: `S + (move |()| 1 == 1)`");

    let test = || Ok(ensure!(S + |()| 1 == 1));
    assert_err(test, "Condition failed: `S + (|()| 1 == 1)`");
}

#[test]
fn test_unary() {
    let mut x = &1;
    let test = || Ok(ensure!(*x == 2));
    assert_err(test, "Condition failed: `*x == 2` (1 vs 2)");

    let test = || Ok(ensure!(!x == 1));
    assert_err(test, "Condition failed: `!x == 1` (-2 vs 1)");

    let test = || Ok(ensure!(-x == 1));
    assert_err(test, "Condition failed: `-x == 1` (-1 vs 1)");

    let test = || Ok(ensure!(&x == &&2));
    assert_err(test, "Condition failed: `&x == &&2` (1 vs 2)");

    let test = || Ok(ensure!(&mut x == *&&mut &2));
    assert_err(test, "Condition failed: `&mut x == *&&mut &2` (1 vs 2)");
}

#[test]
fn test_if() {
    #[rustfmt::skip]
    let test = || Ok(ensure!(if false {}.t(1) == 2));
    assert_err(test, "Condition failed: `if false { }.t(1) == 2` (1 vs 2)");

    #[rustfmt::skip]
    let test = || Ok(ensure!(if false {} else {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if false { } else { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if false {} else if false {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if false { } else if false { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if let 1 = 2 {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if let 1 = 2 { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if let 1 | 2 = 2 {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if let 1 | 2 = 2 { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(if let | 1 | 2 = 2 {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `if let 1 | 2 = 2 { }.t(1) == 2` (1 vs 2)",
    );
}

#[test]
fn test_loop() {
    #[rustfmt::skip]
    let test = || Ok(ensure!(1 + loop { break 1 } == 1));
    assert_err(
        test,
        // 1.54 puts a double space after loop
        "Condition failed: `1 + loop  { break 1  } == 1` (2 vs 1)\n\
         Condition failed: `1 + loop { break 1  } == 1` (2 vs 1)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(1 + 'a: loop { break 'a 1 } == 1));
    assert_err(
        test,
        // 1.54 puts a double space after loop
        "Condition failed: `1 + 'a: loop  { break 'a 1  } == 1` (2 vs 1)\n\
         Condition failed: `1 + 'a: loop { break 'a 1  } == 1` (2 vs 1)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(while false {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `while false { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(while let None = Some(1) {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `while let None = Some(1) { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(for _x in iter::once(0) {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `for _x in iter::once(0) { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(for | _x in iter::once(0) {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `for _x in iter::once(0) { }.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(for true | false in iter::empty() {}.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `for true | false in iter::empty() { }.t(1) == 2` (1 vs 2)",
    );
}

#[test]
fn test_match() {
    #[rustfmt::skip]
    let test = || Ok(ensure!(match 1 == 1 { true => 1, false => 0 } == 2));
    assert_err(
        test,
        "Condition failed: `match 1 == 1 { true => 1, false => 0, } == 2` (1 vs 2)",
    );
}

#[test]
fn test_atom() {
    let test = || Ok(ensure!([false, false].len() > 3));
    assert_err(
        test,
        "Condition failed: `[false, false].len() > 3` (2 vs 3)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!({ let x = 1; x } >= 3));
    assert_err(test, "Condition failed: `{ let x = 1; x } >= 3` (1 vs 3)");

    let test = || Ok(ensure!(S + async { 1 } == true));
    assert_err(
        test,
        "Condition failed: `S + async  { 1 } == true` (false vs true)",
    );

    let test = || Ok(ensure!(S + async move { 1 } == true));
    assert_err(
        test,
        "Condition failed: `S + async move  { 1 } == true` (false vs true)",
    );

    let test = || Ok(ensure!(S + unsafe { 1 } == true));
    assert_err(
        test,
        "Condition failed: `S + unsafe { 1 } == true` (false vs true)",
    );
}

#[test]
fn test_path() {
    let test = || Ok(ensure!(crate::S.t(1) == 2));
    assert_err(test, "Condition failed: `crate::S.t(1) == 2` (1 vs 2)");

    let test = || Ok(ensure!(::anyhow::Error::root_cause.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `::anyhow::Error::root_cause.t(1) == 2` (1 vs 2)",
    );

    let test = || Ok(ensure!(Error::msg::<&str>.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(Error::msg::<&str,>.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)",
    );

    let test = || Ok(ensure!(Error::msg::<<str as ToOwned>::Owned>.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Error::msg::<<str as ToOwned>::Owned>.t(1) == 2` (1 vs 2)",
    );

    let test = || Ok(ensure!(Chain::<'static>::new.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)",
    );

    #[rustfmt::skip]
    let test = || Ok(ensure!(Chain::<'static,>::new.t(1) == 2));
    assert_err(
        test,
        "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)",
    );
}

#[test]
fn test_macro() {
    let test = || Ok(ensure!(anyhow!("...").to_string().len() <= 1));
    assert_err(
        test,
        "Condition failed: `anyhow!(\"...\").to_string().len() <= 1` (3 vs 1)",
    );

    let test = || Ok(ensure!(vec![1].len() < 1));
    assert_err(test, "Condition failed: `vec![1].len() < 1` (1 vs 1)");

    let test = || Ok(ensure!(stringify! {} != ""));
    assert_err(
        test,
        "Condition failed: `stringify! { } != \"\"` (\"\" vs \"\")",
    );
}

#[test]
fn test_trailer() {
    let test = || Ok(ensure!((|| 1)() == 2));
    assert_err(test, "Condition failed: `(|| 1)() == 2` (1 vs 2)");

    let test = || Ok(ensure!(b"hmm"[1] == b'c'));
    assert_err(test, "Condition failed: `b\"hmm\"[1] == b'c'` (109 vs 99)");

    let test = || Ok(ensure!(PhantomData::<u8> {} != PhantomData));
    assert_err(
        test,
        "Condition failed: `PhantomData::<u8>{} != PhantomData` (PhantomData vs PhantomData)",
    );

    let result = Ok::<_, Error>(1);
    let test = || Ok(ensure!(result? == 2));
    assert_err(test, "Condition failed: `result? == 2` (1 vs 2)");

    let test = || Ok(ensure!((2, 3).1 == 2));
    assert_err(test, "Condition failed: `(2, 3).1 == 2` (3 vs 2)");

    let err = anyhow!("");
    let test = || Ok(ensure!(err.is::<&str>() == false));
    assert_err(
        test,
        "Condition failed: `err.is::<&str>() == false` (true vs false)",
    );

    let test = || Ok(ensure!(err.is::<<str as ToOwned>::Owned>() == true));
    assert_err(
        test,
        "Condition failed: `err.is::<<str as ToOwned>::Owned>() == true` (false vs true)",
    );
}
<|endoftext|>


<commit_before>use neb::server::*;
use neb::ram::schema::*;
use neb::server::transactions;
use neb::ram::types::*;
use neb::server::transactions::*;
use std::rc::Rc;
use neb::ram::cell::*;
use super::*;

#[test]
pub fn basic_wr () {
    let server_addr = String::from("127.0.0.1:5200");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    server.meta.schemas.new_schema(&mut schema);
    let txn = transactions::new_client(&server_addr).unwrap();
    let txn_id = txn.begin().unwrap().unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map);
    let cell_1_w_res = txn.write(&txn_id, &cell_1).unwrap().unwrap();
    match cell_1_w_res {
        TransactionExecResult::Accepted(()) => {},
        _ => {panic!("write cell 1 not accepted {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TransactionExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
            assert_eq!(cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_w_res)}
    }
}
<commit_msg>test cell write twice<commit_after>use neb::server::*;
use neb::ram::schema::*;
use neb::server::transactions;
use neb::ram::types::*;
use neb::server::transactions::*;
use std::rc::Rc;
use neb::ram::cell::*;
use super::*;

#[test]
pub fn basic_wr () {
    let server_addr = String::from("127.0.0.1:5200");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    server.meta.schemas.new_schema(&mut schema);
    let txn = transactions::new_client(&server_addr).unwrap();
    let txn_id = txn.begin().unwrap().unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1).unwrap().unwrap();
    match cell_1_w_res {
        TransactionExecResult::Accepted(()) => {},
        _ => {panic!("write cell 1 not accepted {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TransactionExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
            assert_eq!(cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_w_res)}
    }
    data_map.insert(String::from("score"), Value::U64(90));
    let cell_1_w2 = Cell::new(schema.id, &cell_1.id(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_w_res {
        TransactionExecResult::Accepted(()) => {panic!("Write existed cell should fail")}
        TransactionExecResult::Error(WriteError::CellAlreadyExisted) => {}
        _ => {panic!("Wrong feedback {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TransactionExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_w_res)}
    }

}
<|endoftext|>


<commit_before>#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![allow(unused, clippy::let_and_return)]
#![warn(clippy::nonminimal_bool)]

macro_rules! blocky {
    () => {{
        true
    }};
}

macro_rules! blocky_too {
    () => {{
        let r = true;
        r
    }};
}

fn macro_if() {
    if blocky!() {}

    if blocky_too!() {}
}

fn condition_has_block() -> i32 {
    if {
        let x = 3;
        x == 3
    } {
        6
    } else {
        10
    }
}

fn condition_has_block_with_single_expression() -> i32 {
    if { true } {
        6
    } else {
        10
    }
}

fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val: T) -> bool {
    pfn(val)
}

fn pred_test() {
    let v = 3;
    let sky = "blue";
    // This is a sneaky case, where the block isn't directly in the condition,
    // but is actually nside a closure that the condition is using.
    // The same principle applies -- add some extra expressions to make sure
    // linter isn't confused by them.
    if v == 3
        && sky == "blue"
        && predicate(
            |x| {
                let target = 3;
                x == target
            },
            v,
        )
    {}

    if predicate(
        |x| {
            let target = 3;
            x == target
        },
        v,
    ) {}
}

fn condition_is_normal() -> i32 {
    let x = 3;
    if true && x == 3 {
        6
    } else {
        10
    }
}

fn closure_without_block() {
    if predicate(|x| x == 3, 6) {}
}

fn condition_is_unsafe_block() {
    let a: i32 = 1;

    // this should not warn because the condition is an unsafe block
    if unsafe { 1u32 == std::mem::transmute(a) } {
        println!("1u32 == a");
    }
}

fn main() {}

fn macro_in_closure() {
    let option = Some(true);

    if option.unwrap_or_else(|| unimplemented!()) {
        unimplemented!()
    }
}
<commit_msg>Add test for external macro<commit_after>#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![allow(unused, clippy::let_and_return)]
#![warn(clippy::nonminimal_bool)]

macro_rules! blocky {
    () => {{
        true
    }};
}

macro_rules! blocky_too {
    () => {{
        let r = true;
        r
    }};
}

fn macro_if() {
    if blocky!() {}

    if blocky_too!() {}
}

fn condition_has_block() -> i32 {
    if {
        let x = 3;
        x == 3
    } {
        6
    } else {
        10
    }
}

fn condition_has_block_with_single_expression() -> i32 {
    if { true } {
        6
    } else {
        10
    }
}

fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val: T) -> bool {
    pfn(val)
}

fn pred_test() {
    let v = 3;
    let sky = "blue";
    // This is a sneaky case, where the block isn't directly in the condition,
    // but is actually nside a closure that the condition is using.
    // The same principle applies -- add some extra expressions to make sure
    // linter isn't confused by them.
    if v == 3
        && sky == "blue"
        && predicate(
            |x| {
                let target = 3;
                x == target
            },
            v,
        )
    {}

    if predicate(
        |x| {
            let target = 3;
            x == target
        },
        v,
    ) {}
}

fn condition_is_normal() -> i32 {
    let x = 3;
    if true && x == 3 {
        6
    } else {
        10
    }
}

fn closure_without_block() {
    if predicate(|x| x == 3, 6) {}
}

fn condition_is_unsafe_block() {
    let a: i32 = 1;

    // this should not warn because the condition is an unsafe block
    if unsafe { 1u32 == std::mem::transmute(a) } {
        println!("1u32 == a");
    }
}

fn main() {}

fn macro_in_closure() {
    let option = Some(true);

    if option.unwrap_or_else(|| unimplemented!()) {
        unimplemented!()
    }
}

fn block_in_assert() {
    let opt = Some(42);
    assert!(opt
        .as_ref()
        .and_then(|val| {
            let mut v = val * 2;
            v -= 1;
            Some(v * 3)
        })
        .is_some());
}
<|endoftext|>


<commit_before>// vim: tw=80
extern crate proc_macro;

use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};

/// Generate a mock identifier from the regular one: eg "Foo" => "MockFoo"
fn mock_ident(ident: &syn::Ident) -> syn::Ident {
    syn::Ident::new(&format!("Mock{}", ident), ident.span())
}

/// Generate a mock path from a regular one:
/// eg "foo::bar::Baz" => "foo::bar::MockBaz"
fn mock_path(path: &syn::Path) -> syn::Path {
    let mut outsegs = path.segments.clone();
    let mut last_segment = outsegs.last_mut().unwrap();
    last_segment.value_mut().ident = mock_ident(&last_segment.value().ident);
    syn::Path{leading_colon: path.leading_colon, segments: outsegs}
}

/// Generate a mock method and its expectation method
fn mock_method(meth: &syn::ImplItemMethod) -> TokenStream {
    let mut output = TokenStream::new();
    // First the mock method
    if let Some(d) = meth.defaultness {
        d.to_tokens(&mut output);
    }
    meth.vis.to_tokens(&mut output);
    if let Some(c) = &meth.sig.constness {
        c.to_tokens(&mut output);
    }
    if let Some(u) = &meth.sig.unsafety {
        u.to_tokens(&mut output);
    }
    if let Some(a) = &meth.sig.asyncness {
        a.to_tokens(&mut output);
    }
    if let Some(a) = &meth.sig.abi {
        a.to_tokens(&mut output);
    }
    meth.sig.decl.fn_token.to_tokens(&mut output);
    meth.sig.ident.to_tokens(&mut output);
    meth.sig.decl.generics.to_tokens(&mut output);
    let mut inputs = TokenStream::new();
    meth.sig.decl.inputs.to_tokens(&mut inputs);
    quote!((#inputs)).to_tokens(&mut output);
    if let Some(v) = &meth.sig.decl.variadic {
        v.to_tokens(&mut output);
    }
    meth.sig.decl.output.to_tokens(&mut output);

    let mut input_type
        = syn::punctuated::Punctuated::<syn::Type, syn::Token![,]>::new();
    for fn_arg in meth.sig.decl.inputs.iter() {
        match fn_arg {
            syn::FnArg::Captured(arg) => input_type.push(arg.ty.clone()),
            syn::FnArg::SelfRef(_) => /* ignore */(),
            syn::FnArg::SelfValue(_) => /* ignore */(),
            _ => unimplemented!(),
        }
    }
    let output_type: syn::Type = match &meth.sig.decl.output {
        syn::ReturnType::Default => {
            let paren_token = syn::token::Paren{span: Span::call_site()};
            let elems = syn::punctuated::Punctuated::new();
            syn::Type::Tuple(syn::TypeTuple{paren_token, elems})
        },
        syn::ReturnType::Type(_, ty) => (**ty).clone()
    };
    let ident = format!("{}", meth.sig.ident);

    quote!({self.e.called::<(#input_type), #output_type>(#ident)})
        .to_tokens(&mut output);

    // Then the expectation method
    let expect_ident = syn::Ident::new(&format!("expect_{}", meth.sig.ident),
                                       meth.sig.ident.span());
    quote!(pub fn #expect_ident(&mut self)
           -> mockall::Expectation<(#input_type), #output_type> {
        self.e.expect::<(#input_type), #output_type>(#ident)
   }).to_tokens(&mut output);

    output
}

fn gen_impl(item: syn::ItemImpl) -> TokenStream {
    let mut output = TokenStream::new();
    item.unsafety.to_tokens(&mut output);
    item.impl_token.to_tokens(&mut output);
    item.generics.to_tokens(&mut output);
    if let Some(trait_) = item.trait_ {
        let (bang, path, for_) = trait_;
        if let Some(b) = bang {
            b.to_tokens(&mut output);
        }
        path.to_tokens(&mut output);
        for_.to_tokens(&mut output);
    }
    match *item.self_ty {
        syn::Type::Path(type_path) => {
            assert!(type_path.qself.is_none());
            mock_path(&type_path.path).to_tokens(&mut output);
        },
        _ => unimplemented!("This self type is not yet supported by MockAll")
    }

    let mut body = TokenStream::new();
    for impl_item in item.items {
        match impl_item {
            syn::ImplItem::Const(_) => {
                // const items can easily be added by the user in a separate
                // impl block
            },
            syn::ImplItem::Existential(ty) => ty.to_tokens(&mut body),
            syn::ImplItem::Type(ty) => ty.to_tokens(&mut body),
            syn::ImplItem::Method(meth) => {
                mock_method(&meth).to_tokens(&mut body)
            },
            _ => {
                unimplemented!("This impl item is not yet supported by MockAll")
            }
        }
    }
    quote!({#body}).to_tokens(&mut output);

    output
}

fn gen_struct(item: syn::ItemStruct) -> TokenStream {
    let mut output = TokenStream::new();
    item.vis.to_tokens(&mut output);
    item.struct_token.to_tokens(&mut output);
    let ident = mock_ident(&item.ident);
    ident.to_tokens(&mut output);
    item.generics.to_tokens(&mut output);

    let mut body: TokenStream = "e: mockall::Expectations,".parse().unwrap();
    let mut count = 0;
    for param in item.generics.params.iter() {
        if let syn::GenericParam::Type(tp) = param {
            let ty = &tp.ident;
            let phname = format!("_t{}", count);
            let phident = syn::Ident::new(&phname, tp.ident.span());
            let var = quote!(#phident: std::marker::PhantomData<#ty>,);
            var.to_tokens(&mut body);
            count += 1;
        }
    }
    quote!({#body}).to_tokens(&mut output);

    output
}

fn gen_mock(input: TokenStream) -> TokenStream {
    let item: syn::Item = match syn::parse(input.into()) {
        Ok(item) => item,
        Err(err) => {
            // TODO: use Span::call_site().error().emit once proc_macro_span is
            // stable
            // https://github.com/rust-lang/rust/issues/54725
            panic!("Failed to parse: {}", err);
        }
    };
    match item {
        syn::Item::Struct(item_struct) => gen_struct(item_struct),
        syn::Item::Impl(item_impl) => gen_impl(item_impl),
        _ => unimplemented!("TODO")
    }
}

/// Automatically generate mock types for Structs and Traits.
#[proc_macro_attribute]
pub fn mock(_attr: proc_macro::TokenStream, input: proc_macro::TokenStream)
    -> proc_macro::TokenStream
{
    let input: proc_macro2::TokenStream = input.into();
    let mut output = input.clone();
    output.extend(gen_mock(input));
    output.into()
}

#[cfg(feature = "internal_testing")]
#[proc_macro_attribute]
pub fn expect_mock(attr: proc_macro::TokenStream, item: proc_macro::TokenStream)
    -> proc_macro::TokenStream
{
    let expected = attr.to_string();
    let output = gen_mock(item.into()).to_string();
    assert_eq!(expected, output);
    proc_macro::TokenStream::new()
}

/// Test cases for `#[mock]`.
///
/// Proc macros cannot be tested at runtime like normal Rust code.  They can
/// only be tested at compile time.  Run the tests in doc test blocks so that a
/// compile failure by one does not stop the others from running.
///
#[allow(unused)]
#[cfg(feature = "internal_testing")]
mod t {
use super::*;

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// struct MockSimpleStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// struct SimpleStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockSimpleStruct {
///     fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl SimpleStruct {
///     fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type SimpleStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// struct MockGenericStruct<'a, T, V> {
///     e: mockall::Expectations,
///     _t0: std::marker::PhantomData<T>,
///     _t1: std::marker::PhantomData<V>,
/// }
/// )]
/// struct GenericStruct<'a, T, V> {
///     x: i16
/// }
/// #[expect_mock(
/// impl<'a, T, V> MockGenericStruct<'a, T, V> {
///     fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl<'a, T, V> GenericStruct<'a, T, V> {
///     fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type GenericStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// impl Foo for SomeStruct {
///     fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl SomeStruct {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl Foo for SomeStruct {
///     fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type ImplTrait = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// impl MockMethodByValue {
///     fn foo(self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl MethodByValue {
///     fn foo(self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type MethodByValue = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// pub struct MockPubStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// pub struct PubStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockPubStruct {
///     pub fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl PubStruct {
///     pub fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type PubStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// pub(crate) struct MockPubCrateStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// pub(crate) struct PubCrateStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockPubCrateStruct {
///     pub(crate) fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl PubCrateStruct {
///     pub(crate) fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type PubCrateStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// pub(super) struct MockPubSuperStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// pub(super) struct PubSuperStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockPubSuperStruct {
///     pub(super) fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl PubSuperStruct {
///     pub(super) fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type PubSuperStruct = ();
}
<commit_msg>Fix mocking "impl Trait for Type"<commit_after>// vim: tw=80
extern crate proc_macro;

use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};

/// Generate a mock identifier from the regular one: eg "Foo" => "MockFoo"
fn mock_ident(ident: &syn::Ident) -> syn::Ident {
    syn::Ident::new(&format!("Mock{}", ident), ident.span())
}

/// Generate a mock path from a regular one:
/// eg "foo::bar::Baz" => "foo::bar::MockBaz"
fn mock_path(path: &syn::Path) -> syn::Path {
    let mut outsegs = path.segments.clone();
    let mut last_segment = outsegs.last_mut().unwrap();
    last_segment.value_mut().ident = mock_ident(&last_segment.value().ident);
    syn::Path{leading_colon: path.leading_colon, segments: outsegs}
}

/// Generate a mock method and its expectation method
fn mock_method(meth: &syn::ImplItemMethod) -> (TokenStream, TokenStream) {
    let mut mock_output = TokenStream::new();
    // First the mock method
    if let Some(d) = meth.defaultness {
        d.to_tokens(&mut mock_output);
    }
    meth.vis.to_tokens(&mut mock_output);
    if let Some(c) = &meth.sig.constness {
        c.to_tokens(&mut mock_output);
    }
    if let Some(u) = &meth.sig.unsafety {
        u.to_tokens(&mut mock_output);
    }
    if let Some(a) = &meth.sig.asyncness {
        a.to_tokens(&mut mock_output);
    }
    if let Some(a) = &meth.sig.abi {
        a.to_tokens(&mut mock_output);
    }
    meth.sig.decl.fn_token.to_tokens(&mut mock_output);
    meth.sig.ident.to_tokens(&mut mock_output);
    meth.sig.decl.generics.to_tokens(&mut mock_output);
    let mut inputs = TokenStream::new();
    meth.sig.decl.inputs.to_tokens(&mut inputs);
    quote!((#inputs)).to_tokens(&mut mock_output);
    if let Some(v) = &meth.sig.decl.variadic {
        v.to_tokens(&mut mock_output);
    }
    meth.sig.decl.output.to_tokens(&mut mock_output);

    let mut input_type
        = syn::punctuated::Punctuated::<syn::Type, syn::Token![,]>::new();
    for fn_arg in meth.sig.decl.inputs.iter() {
        match fn_arg {
            syn::FnArg::Captured(arg) => input_type.push(arg.ty.clone()),
            syn::FnArg::SelfRef(_) => /* ignore */(),
            syn::FnArg::SelfValue(_) => /* ignore */(),
            _ => unimplemented!(),
        }
    }
    let output_type: syn::Type = match &meth.sig.decl.output {
        syn::ReturnType::Default => {
            let paren_token = syn::token::Paren{span: Span::call_site()};
            let elems = syn::punctuated::Punctuated::new();
            syn::Type::Tuple(syn::TypeTuple{paren_token, elems})
        },
        syn::ReturnType::Type(_, ty) => (**ty).clone()
    };
    let ident = format!("{}", meth.sig.ident);

    quote!({self.e.called::<(#input_type), #output_type>(#ident)})
        .to_tokens(&mut mock_output);

    // Then the expectation method
    let mut expect_output = TokenStream::new();
    let expect_ident = syn::Ident::new(&format!("expect_{}", meth.sig.ident),
                                       meth.sig.ident.span());
    quote!(pub fn #expect_ident(&mut self)
           -> mockall::Expectation<(#input_type), #output_type> {
        self.e.expect::<(#input_type), #output_type>(#ident)
   }).to_tokens(&mut expect_output);

    (mock_output, expect_output)
}

fn gen_impl(item: syn::ItemImpl) -> TokenStream {
    let mut output = TokenStream::new();
    let mut mock_body = TokenStream::new();
    let mut expect_body = TokenStream::new();

    let mock_type = match *item.self_ty {
        syn::Type::Path(type_path) => {
            assert!(type_path.qself.is_none(), "What is qself?");
            mock_path(&type_path.path)
        },
        _ => unimplemented!("This self type is not yet supported by MockAll")
    };

    for impl_item in item.items {
        match impl_item {
            syn::ImplItem::Const(_) => {
                // const items can easily be added by the user in a separate
                // impl block
            },
            syn::ImplItem::Existential(ty) => ty.to_tokens(&mut mock_body),
            syn::ImplItem::Type(ty) => ty.to_tokens(&mut mock_body),
            syn::ImplItem::Method(meth) => {
                let (mock_meth, expect_meth) = mock_method(&meth);
                mock_meth.to_tokens(&mut mock_body);
                expect_meth.to_tokens(&mut expect_body);
            },
            _ => {
                unimplemented!("This impl item is not yet supported by MockAll")
            }
        }
    }

    // Put all mock methods in one impl block
    item.unsafety.to_tokens(&mut output);
    item.impl_token.to_tokens(&mut output);
    item.generics.to_tokens(&mut output);
    if let Some(trait_) = item.trait_ {
        let (bang, path, for_) = trait_;
        if let Some(b) = bang {
            b.to_tokens(&mut output);
        }
        path.to_tokens(&mut output);
        for_.to_tokens(&mut output);
    }
    mock_type.to_tokens(&mut output);
    quote!({#mock_body}).to_tokens(&mut output);

    // Put all expect methods in a separate impl block.  This is necessary when
    // mocking a trait impl, where we can't add any new methods
    item.impl_token.to_tokens(&mut output);
    item.generics.to_tokens(&mut output);
    mock_type.to_tokens(&mut output);
    quote!({#expect_body}).to_tokens(&mut output);

    output
}

fn gen_struct(item: syn::ItemStruct) -> TokenStream {
    let mut output = TokenStream::new();
    item.vis.to_tokens(&mut output);
    item.struct_token.to_tokens(&mut output);
    let ident = mock_ident(&item.ident);
    ident.to_tokens(&mut output);
    item.generics.to_tokens(&mut output);

    let mut body: TokenStream = "e: mockall::Expectations,".parse().unwrap();
    let mut count = 0;
    for param in item.generics.params.iter() {
        if let syn::GenericParam::Type(tp) = param {
            let ty = &tp.ident;
            let phname = format!("_t{}", count);
            let phident = syn::Ident::new(&phname, tp.ident.span());
            let var = quote!(#phident: std::marker::PhantomData<#ty>,);
            var.to_tokens(&mut body);
            count += 1;
        }
    }
    quote!({#body}).to_tokens(&mut output);

    output
}

fn gen_mock(input: TokenStream) -> TokenStream {
    let item: syn::Item = match syn::parse(input.into()) {
        Ok(item) => item,
        Err(err) => {
            // TODO: use Span::call_site().error().emit once proc_macro_span is
            // stable
            // https://github.com/rust-lang/rust/issues/54725
            panic!("Failed to parse: {}", err);
        }
    };
    match item {
        syn::Item::Struct(item_struct) => gen_struct(item_struct),
        syn::Item::Impl(item_impl) => gen_impl(item_impl),
        _ => unimplemented!("TODO")
    }
}

/// Automatically generate mock types for Structs and Traits.
#[proc_macro_attribute]
pub fn mock(_attr: proc_macro::TokenStream, input: proc_macro::TokenStream)
    -> proc_macro::TokenStream
{
    let input: proc_macro2::TokenStream = input.into();
    let mut output = input.clone();
    output.extend(gen_mock(input));
    output.into()
}

#[cfg(feature = "internal_testing")]
#[proc_macro_attribute]
pub fn expect_mock(attr: proc_macro::TokenStream, item: proc_macro::TokenStream)
    -> proc_macro::TokenStream
{
    let expected = attr.to_string();
    let output = gen_mock(item.into()).to_string();
    assert_eq!(expected, output);
    proc_macro::TokenStream::new()
}

/// Test cases for `#[mock]`.
///
/// Proc macros cannot be tested at runtime like normal Rust code.  They can
/// only be tested at compile time.  Run the tests in doc test blocks so that a
/// compile failure by one does not stop the others from running.
///
#[allow(unused)]
#[cfg(feature = "internal_testing")]
mod t {
use super::*;

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// struct MockSimpleStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// struct SimpleStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockSimpleStruct {
///     fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl MockSimpleStruct {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl SimpleStruct {
///     fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type SimpleStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// struct MockGenericStruct<'a, T, V> {
///     e: mockall::Expectations,
///     _t0: std::marker::PhantomData<T>,
///     _t1: std::marker::PhantomData<V>,
/// }
/// )]
/// struct GenericStruct<'a, T, V> {
///     x: i16
/// }
/// #[expect_mock(
/// impl<'a, T, V> MockGenericStruct<'a, T, V> {
///     fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl<'a, T, V> MockGenericStruct<'a, T, V> {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl<'a, T, V> GenericStruct<'a, T, V> {
///     fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type GenericStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// impl Foo for MockSomeStruct {
///     fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl MockSomeStruct {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl Foo for SomeStruct {
///     fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type ImplTrait = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// impl MockMethodByValue {
///     fn foo(self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl MockMethodByValue {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl MethodByValue {
///     fn foo(self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type MethodByValue = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// pub struct MockPubStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// pub struct PubStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockPubStruct {
///     pub fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl MockPubStruct {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl PubStruct {
///     pub fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type PubStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// pub(crate) struct MockPubCrateStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// pub(crate) struct PubCrateStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockPubCrateStruct {
///     pub(crate) fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl MockPubCrateStruct {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl PubCrateStruct {
///     pub(crate) fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type PubCrateStruct = ();

/// ```no_run
/// # use mockall_derive::{mock, expect_mock};
/// #[expect_mock(
/// pub(super) struct MockPubSuperStruct {
///     e: mockall::Expectations,
/// }
/// )]
/// pub(super) struct PubSuperStruct {
///     x: i16
/// }
/// #[expect_mock(
/// impl MockPubSuperStruct {
///     pub(super) fn foo(&self, x: u32) -> i64 {
///         self.e.called::<(u32), i64>("foo")
///     }
/// }
/// impl MockPubSuperStruct {
///     pub fn expect_foo(&mut self) -> mockall::Expectation<(u32), i64> {
///         self.e.expect::<(u32), i64>("foo")
///     }
/// }
/// )]
/// impl PubSuperStruct {
///     pub(super) fn foo(&self, x: u32) -> i64 {
///         42
///     }
/// }
/// ```
type PubSuperStruct = ();
}
<|endoftext|>


<commit_before>//
// rslex - a lexer generator for rust
//
// regexp.rs
// Regexp parsing and representation
//
// Andrei de A. Formiga, 2013-08-09
//

extern mod std;

use buffer::LookaheadBuffer;

#[deriving(Eq, Clone)]
enum Token { LBrack, RBrack, Id(~str), LParen, RParen, Asterisk,
             Plus, Bar, Dash, String(~str), End, Eof, Error(char) }

pub enum Ast { Symb(~str), Str(~str), Union(~Ast, ~Ast),
           Conc(~Ast, ~Ast), Star(~Ast), OnePlus(~Ast),
           CharClass(char, char), Epsilon }

/// A token stream with capacity for lookahead of 1 token
struct TokenStream<'r> {
    buffer: &'r mut LookaheadBuffer<'r>,
    term: &'r [char],
    peek: Option<Token>
}

impl<'r> TokenStream<'r> {
    pub fn new(buffer: &'r mut LookaheadBuffer<'r>, term: &'r [char]) -> TokenStream<'r> {
        TokenStream { buffer: buffer, term: term, peek: None }
    }

    fn next_token(&mut self) -> Token {
        let res = match self.peek {
            None => self.next_token_raw(),
            Some(ref t) => (*t).clone()
        };
        self.peek = None;
        res
    }

    fn next_token_raw(&mut self) -> Token {
        self.buffer.skip_whitespace();
        match self.buffer.next_char() {
            Some('[') => LBrack,
            Some(']') => RBrack,
            Some('(') => LParen,
            Some(')') => RParen,
            Some('*') => Asterisk,
            Some('+') => Plus,
            Some('|') => Bar,
            Some('-') => Dash,
            Some('\'') => String(self.parse_string('\'')),
            Some('"') => String(self.parse_string('"')),
            Some(c) if std::char::is_alphabetic(c) => Id(self.parse_id(c)),
            Some(c) if is_terminator(c, self.term) => End,
            None => Eof,
            Some(c) => Error(c)
        }
    }

    fn return_token(&mut self, tok: Token) {
        self.peek = Some(tok);
    }

    fn parse_string(&mut self, delim: char) -> ~str {
        let mut res : ~str = ~"";
        loop {
            match self.buffer.next_char() {
                None => fail!("Unexpected end of file. Expected closing {}", delim),
                Some(c) if c == delim => break,
                Some(c) => res.push_char(c)
            }
        }
        res
    }

    fn parse_id(&mut self, first: char) -> ~str {
        let mut res : ~str = ~"";
        res.push_char(first);
        loop {
            match self.buffer.next_char() {
                Some(c) if is_id_char(c) => res.push_char(c),
                Some(c) => { self.buffer.return_char(c); break }
                None => break
            }
        }
        res
    }

}

#[inline]
fn is_id_char(c: char) -> bool {
    std::char::is_alphanumeric(c) || c == '_'
}

#[inline]
fn match_next_token(ts: &mut TokenStream, t: Token, term: &[char]) {
    let rt = ts.next_token();
    if rt != t {
        fail!("Unexpeced token: expected {:?}, got {:?}", t, rt);
    }
}

#[inline]
fn is_terminator(c: char, term: &[char]) -> bool {
    term.contains(&c)
}

// regexp := union
// union  := union '|' concat | concat
// concat := concat factor | factor
// factor := (regexp) | regexp'*' | regexp'+' | class | id | str
// class  := '[' (char | range)* ']'
// range  := char'-'char

// parse a regexp from the token stream until one of the terminators in term occurs
pub fn parse_regexp(ts: &mut TokenStream, term: &[char]) -> Ast {
    parse_union(ts, term)
}

// fn parse_unconc(buffer: &mut LookaheadBuffer, term: &[char]) -> Ast {
//     Epsilon
// }

fn parse_union(ts: &mut TokenStream, term: &[char]) -> Ast {
    let left = parse_concat(ts, term);
    if ts.next_token() == Bar {
        let right = parse_union(ts, term);
        Union(~left, ~right)
    }
    else {
        left
    }
}

fn parse_concat(ts: &mut TokenStream, term: &[char]) -> Ast {
    let first = parse_factor(ts, term);
    let right = parse_factor(ts, term);
    Conc(~first, ~right)
}

fn trailing_closure(ts: &mut TokenStream) -> Option<Token> {
    match ts.next_token() {
        Asterisk => Some(Asterisk),
        Plus => Some(Plus),
        t => { ts.return_token(t); None }
    }
}

fn parse_character_class(ts: &mut TokenStream) -> Ast {
    Epsilon         // TODO
}

#[inline]
fn parse_factor(ts: &mut TokenStream, term: &[char]) -> Ast {
    let tok = ts.next_token();
    parse_factor_token(ts, tok, term)
}

fn parse_factor_token(ts: &mut TokenStream, tok: Token, term: &[char]) -> Ast {
    let pre = match tok {
        LParen => { let e = parse_regexp(ts, term);
                    match_next_token(ts, RParen, term);
                    e }
        LBrack => parse_character_class(ts),
        Id(s) => Symb(s),
        String(s) => Str(s),  // TODO: check for END
        _ => Epsilon          // TODO: error
    };
    match trailing_closure(ts) {
        Some(Asterisk) => Star(~pre),
        Some(Plus) => OnePlus(~pre),
        Some(_) => fail!("Unexpected closure character"),
        None => pre
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::{LBrack, RBrack, Id, LParen, RParen, Asterisk, Bar, Dash, String, End, Eof, Error };
    use buffer::LookaheadBuffer;

    #[test]
    fn test_parse_string_ts() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("abc'* ");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.parse_string('\''), ~"abc");
        assert_eq!(ts1.buffer.next_char(), Some('*'));

        let mut b2 = LookaheadBuffer::new("abc'def\"  ");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(ts2.parse_string('"'), ~"abc'def");
        assert_eq!(ts2.buffer.next_char(), Some(' '));
    }

    #[test]
    #[should_fail]
    fn unclosed_string_ts() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("abc'def  ");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.parse_string('"'), ~"abc'def");
    }

    #[test]
    fn test_parse_id_ts() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("abc'* ");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.parse_id('x'), ~"xabc");
        assert_eq!(ts1.buffer.next_char(), Some('\''));

        let mut b2 = LookaheadBuffer::new("bc_def   ");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(ts2.parse_id('a'), ~"abc_def");

        let mut b3 = LookaheadBuffer::new("_times|'xy')*   ");
        let mut ts3 = TokenStream::new(&mut b3, term);
        assert_eq!(ts3.parse_id('n'), ~"n_times");
        assert_eq!(ts3.buffer.next_char(), Some('|'));

        let mut b4 = LookaheadBuffer::new(" +xy)*   ");
        let mut ts4 = TokenStream::new(&mut b4, term);
        assert_eq!(ts4.parse_id('n'), ~"n");
        assert_eq!(ts4.buffer.next_char(), Some(' '));
        assert_eq!(ts4.buffer.next_char(), Some('+'));
        assert_eq!(ts4.buffer.next_char(), Some('x'));
        assert_eq!(ts4.parse_id('x'), ~"xy");
    }

    #[test]
    fn test_next_token_raw() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("'return'");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.next_token(), String(~"return"));

        let mut b2 = LookaheadBuffer::new("return");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(ts2.next_token(), Id(~"return"));
        ts2.return_token(Id(~"return"));
        assert_eq!(ts2.next_token(), Id(~"return"));
        assert_eq!(ts2.next_token(), Eof);

        let mut b3 = LookaheadBuffer::new("(['a'-'z'])(['A'-'Z'])*");
        let mut ts3 = TokenStream::new(&mut b3, term);
        assert_eq!(ts3.next_token(), LParen);
        assert_eq!(ts3.next_token(), LBrack);
        assert_eq!(ts3.next_token(), String(~"a"));
        assert_eq!(ts3.next_token(), Dash);
        assert_eq!(ts3.next_token(), String(~"z"));
        assert_eq!(ts3.next_token(), RBrack);
        assert_eq!(ts3.next_token(), RParen);
        assert_eq!(ts3.next_token(), LParen);

        assert_eq!(ts3.peek, None);
        ts3.return_token(LParen);
        assert!(!ts3.peek.is_none());
        assert_eq!(ts3.next_token(), LParen);
        assert_eq!(ts3.peek, None);

        assert_eq!(ts3.next_token(), LBrack);
        assert_eq!(ts3.next_token(), String(~"A"));
        assert_eq!(ts3.next_token(), Dash);
        assert_eq!(ts3.next_token(), String(~"Z"));
        assert_eq!(ts3.next_token(), RBrack);
        assert_eq!(ts3.next_token(), RParen);
        assert_eq!(ts3.next_token(), Asterisk);
        assert_eq!(ts3.next_token(), Eof);

        let mut b4 = LookaheadBuffer::new("letter \t (letter | digit)*,");
        let mut ts4 = TokenStream::new(&mut b4, term);
        assert_eq!(ts4.next_token(), Id(~"letter"));
        assert_eq!(ts4.next_token(), LParen);
        assert_eq!(ts4.next_token(), Id(~"letter"));
        assert_eq!(ts4.next_token(), Bar);
        assert_eq!(ts4.next_token(), Id(~"digit"));
        assert_eq!(ts4.next_token(), RParen);
        assert_eq!(ts4.next_token(), Asterisk);
        assert_eq!(ts4.next_token(), End);

        let mut b5 = LookaheadBuffer::new("let  & dig,");
        let mut ts5 = TokenStream::new(&mut b5, term);
        assert_eq!(ts5.next_token(), Id(~"let"));
        assert_eq!(ts5.next_token(), Error('&'));
    }
}<commit_msg>Finished regexp parsing<commit_after>//
// rslex - a lexer generator for rust
//
// regexp.rs
// Regexp parsing and representation
//
// Andrei de A. Formiga, 2013-08-09
//

extern mod std;

use buffer::LookaheadBuffer;

#[deriving(Eq, Clone)]
enum Token { LBrack, RBrack, Id(~str), LParen, RParen, Asterisk,
             Plus, Bar, Dash, String(~str), End, Eof, Error(char) }

#[deriving(Eq)]
pub enum ClassItem { Singles(~str), Range(char, char) }

#[deriving(Eq)]
pub enum Ast { Symb(~str), Str(~str), Union(~Ast, ~Ast),
               Conc(~Ast, ~Ast), Star(~Ast), OnePlus(~Ast),
               CharClass(~[ClassItem]), Epsilon }

/// A token stream with capacity for lookahead of 1 token
struct TokenStream<'r> {
    buffer: &'r mut LookaheadBuffer<'r>,
    term: &'r [char],
    peek: Option<Token>
}

impl<'r> TokenStream<'r> {
    pub fn new(buffer: &'r mut LookaheadBuffer<'r>, term: &'r [char]) -> TokenStream<'r> {
        TokenStream { buffer: buffer, term: term, peek: None }
    }

    fn next_token(&mut self) -> Token {
        let res = match self.peek {
            None => self.next_token_raw(),
            Some(ref t) => (*t).clone()
        };
        self.peek = None;
        res
    }

    fn next_token_raw(&mut self) -> Token {
        self.buffer.skip_whitespace();
        match self.buffer.next_char() {
            Some('[') => LBrack,
            Some(']') => RBrack,
            Some('(') => LParen,
            Some(')') => RParen,
            Some('*') => Asterisk,
            Some('+') => Plus,
            Some('|') => Bar,
            Some('-') => Dash,
            Some('\'') => String(self.parse_string('\'')),
            Some('"') => String(self.parse_string('"')),
            Some(c) if std::char::is_alphabetic(c) => Id(self.parse_id(c)),
            Some(c) if is_terminator(c, self.term) => End,
            None => Eof,
            Some(c) => Error(c)
        }
    }

    fn return_token(&mut self, tok: Token) {
        self.peek = Some(tok);
    }

    fn parse_string(&mut self, delim: char) -> ~str {
        let mut res : ~str = ~"";
        loop {
            match self.buffer.next_char() {
                None => fail!("Unexpected end of file. Expected closing {}", delim),
                Some(c) if c == delim => break,
                Some(c) => res.push_char(c)
            }
        }
        res
    }

    fn parse_id(&mut self, first: char) -> ~str {
        let mut res : ~str = ~"";
        res.push_char(first);
        loop {
            match self.buffer.next_char() {
                Some(c) if is_id_char(c) => res.push_char(c),
                Some(c) => { self.buffer.return_char(c); break }
                None => break
            }
        }
        res
    }
}

#[inline]
fn is_id_char(c: char) -> bool {
    std::char::is_alphanumeric(c) || c == '_'
}

#[inline]
fn match_next_token(ts: &mut TokenStream, t: Token) {
    let rt = ts.next_token();
    if rt != t {
        fail!("Unexpeced token: expected {:?}, got {:?}", t, rt);
    }
}

#[inline]
fn is_terminator(c: char, term: &[char]) -> bool {
    term.contains(&c)
}

// regexp := union
// union  := union '|' concat | concat
// concat := concat factor | factor
// factor := (regexp) | regexp'*' | regexp'+' | class | id | str
// class  := '[' (char | range)* ']'
// range  := char'-'char

// parse a regexp from the token stream until one of the terminators in term occurs
pub fn parse_regexp(ts: &mut TokenStream) -> Ast {
    parse_union(ts)
}

fn parse_union(ts: &mut TokenStream) -> Ast {
    let left = parse_concat(ts);
    match ts.next_token() {
        Bar => {
            let right = parse_union(ts);
            Union(~left, ~right)
        }
        tok => {
            ts.return_token(tok);
            left
        }
    }
}

fn parse_concat(ts: &mut TokenStream) -> Ast {
    let left = parse_factor(ts);
    match ts.next_token() {
        Bar => {
            ts.return_token(Bar);
            left
        }
        End => {
            ts.return_token(End);
            left
        }
        RParen => {
            ts.return_token(RParen);
            left
        }
        tok => {
            ts.return_token(tok);
            let right = parse_concat(ts);
            Conc(~left, ~right)
        }
    }
}

fn trailing_closure(ts: &mut TokenStream) -> Option<Token> {
    match ts.next_token() {
        Asterisk => Some(Asterisk),
        Plus => Some(Plus),
        t => { ts.return_token(t); None }
    }
}

fn parse_character_class(ts: &mut TokenStream) -> Ast {
    let mut res = std::vec::with_capacity(2);
    loop {
        match ts.next_token() {
            String(s1) => {
                match ts.next_token() {
                    Dash => {
                        match ts.next_token() {
                            String(s2) => res.push(Range(s1.char_at(0), s2.char_at(0))),
                            _ => fail!("Ill-formed character class range")
                        }
                    }
                    tok => {
                        ts.return_token(tok);
                        res.push(Singles(s1))
                    }
                }
            }
            Dash => fail!("Ill-formed character class range"),
            RBrack => break,
            tok => fail!("Unexpected token in character class: {:?}", tok)
        }
    }
    CharClass(res)
}

#[inline]
fn parse_factor(ts: &mut TokenStream) -> Ast {
    let pre = match ts.next_token() {
        LParen => { let e = parse_regexp(ts);
                    match_next_token(ts, RParen);
                    e }
        LBrack => parse_character_class(ts),
        Id(s) => Symb(s),
        String(s) => Str(s),
        tok => fail!("Unexpected token in regexp: {:?}", tok)
    };
    match trailing_closure(ts) {
        Some(Asterisk) => Star(~pre),
        Some(Plus) => OnePlus(~pre),
        Some(_) => fail!("Unexpected closure character"),
        None => pre
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::{LBrack, RBrack, Id, LParen, RParen, Asterisk, Bar, Dash, String, End, Eof, Error };
    use super::{CharClass};
    use super::{parse_character_class};
    use buffer::LookaheadBuffer;

    #[test]
    fn test_parse_string_ts() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("abc'* ");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.parse_string('\''), ~"abc");
        assert_eq!(ts1.buffer.next_char(), Some('*'));

        let mut b2 = LookaheadBuffer::new("abc'def\"  ");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(ts2.parse_string('"'), ~"abc'def");
        assert_eq!(ts2.buffer.next_char(), Some(' '));
    }

    #[test]
    #[should_fail]
    fn unclosed_string_ts() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("abc'def  ");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.parse_string('"'), ~"abc'def");
    }

    #[test]
    fn test_parse_id_ts() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("abc'* ");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.parse_id('x'), ~"xabc");
        assert_eq!(ts1.buffer.next_char(), Some('\''));

        let mut b2 = LookaheadBuffer::new("bc_def   ");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(ts2.parse_id('a'), ~"abc_def");

        let mut b3 = LookaheadBuffer::new("_times|'xy')*   ");
        let mut ts3 = TokenStream::new(&mut b3, term);
        assert_eq!(ts3.parse_id('n'), ~"n_times");
        assert_eq!(ts3.buffer.next_char(), Some('|'));

        let mut b4 = LookaheadBuffer::new(" +xy)*   ");
        let mut ts4 = TokenStream::new(&mut b4, term);
        assert_eq!(ts4.parse_id('n'), ~"n");
        assert_eq!(ts4.buffer.next_char(), Some(' '));
        assert_eq!(ts4.buffer.next_char(), Some('+'));
        assert_eq!(ts4.buffer.next_char(), Some('x'));
        assert_eq!(ts4.parse_id('x'), ~"xy");
    }

    #[test]
    fn test_next_token_raw() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("'return'");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(ts1.next_token(), String(~"return"));

        let mut b2 = LookaheadBuffer::new("return");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(ts2.next_token(), Id(~"return"));
        ts2.return_token(Id(~"return"));
        assert_eq!(ts2.next_token(), Id(~"return"));
        assert_eq!(ts2.next_token(), Eof);

        let mut b3 = LookaheadBuffer::new("(['a'-'z'])(['A'-'Z'])*");
        let mut ts3 = TokenStream::new(&mut b3, term);
        assert_eq!(ts3.next_token(), LParen);
        assert_eq!(ts3.next_token(), LBrack);
        assert_eq!(ts3.next_token(), String(~"a"));
        assert_eq!(ts3.next_token(), Dash);
        assert_eq!(ts3.next_token(), String(~"z"));
        assert_eq!(ts3.next_token(), RBrack);
        assert_eq!(ts3.next_token(), RParen);
        assert_eq!(ts3.next_token(), LParen);

        assert_eq!(ts3.peek, None);
        ts3.return_token(LParen);
        assert!(!ts3.peek.is_none());
        assert_eq!(ts3.next_token(), LParen);
        assert_eq!(ts3.peek, None);

        assert_eq!(ts3.next_token(), LBrack);
        assert_eq!(ts3.next_token(), String(~"A"));
        assert_eq!(ts3.next_token(), Dash);
        assert_eq!(ts3.next_token(), String(~"Z"));
        assert_eq!(ts3.next_token(), RBrack);
        assert_eq!(ts3.next_token(), RParen);
        assert_eq!(ts3.next_token(), Asterisk);
        assert_eq!(ts3.next_token(), Eof);

        let mut b4 = LookaheadBuffer::new("letter \t (letter | digit)*,");
        let mut ts4 = TokenStream::new(&mut b4, term);
        assert_eq!(ts4.next_token(), Id(~"letter"));
        assert_eq!(ts4.next_token(), LParen);
        assert_eq!(ts4.next_token(), Id(~"letter"));
        assert_eq!(ts4.next_token(), Bar);
        assert_eq!(ts4.next_token(), Id(~"digit"));
        assert_eq!(ts4.next_token(), RParen);
        assert_eq!(ts4.next_token(), Asterisk);
        assert_eq!(ts4.next_token(), End);

        let mut b5 = LookaheadBuffer::new("let  & dig,");
        let mut ts5 = TokenStream::new(&mut b5, term);
        assert_eq!(ts5.next_token(), Id(~"let"));
        assert_eq!(ts5.next_token(), Error('&'));
    }

    #[test]
    fn test_parse_charclass() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("'A'-'Z'],");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(parse_character_class(&mut ts1), CharClass(~[Range('A', 'Z')]));
        assert_eq!(ts1.next_token(), End);

        let mut b2 = LookaheadBuffer::new("]");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(parse_character_class(&mut ts2), CharClass(~[]));

        let mut b3 = LookaheadBuffer::new("'abcABC']");
        let mut ts3 = TokenStream::new(&mut b3, term);
        assert_eq!(parse_character_class(&mut ts3), CharClass(~[Singles(~"abcABC")]));

        let mut b4 = LookaheadBuffer::new("'ab''cd''0'-'9''55']");
        let mut ts4 = TokenStream::new(&mut b4, term);
        assert_eq!(parse_character_class(&mut ts4),
                   CharClass(~[Singles(~"ab"), Singles(~"cd"),
                               Range('0', '9'), Singles(~"55")]));
    }

    #[test]
    #[should_fail]
    fn test_bad_charclass() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("'A'--'Z'],");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(parse_character_class(&mut ts1), CharClass(~[Range('A', 'Z')]));
    }

    #[test]
    #[should_fail]
    fn test_bad_charclass2() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("'A'*'Z'],");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(parse_character_class(&mut ts1), CharClass(~[Range('A', 'Z')]));
    }

    #[test]
    fn test_parse_regexp() {
        let term = [','];
        let mut b1 = LookaheadBuffer::new("letter,");
        let mut ts1 = TokenStream::new(&mut b1, term);
        assert_eq!(parse_regexp(&mut ts1), Symb(~"letter"));

        let mut b2 = LookaheadBuffer::new("letter*,");
        let mut ts2 = TokenStream::new(&mut b2, term);
        assert_eq!(parse_regexp(&mut ts2), Star(~Symb(~"letter")));

        let mut b3 = LookaheadBuffer::new("letter (letter | digit)*,");
        let mut ts3 = TokenStream::new(&mut b3, term);
        assert_eq!(parse_regexp(&mut ts3),
                   Conc(~Symb(~"letter"), ~Star(~Union(~Symb(~"letter"), ~Symb(~"digit")))));
        assert_eq!(ts3.next_token(), End);

        let mut b4 = LookaheadBuffer::new("['0'-'9']+ '.' ['0'-'9']+,");
        let mut ts4 = TokenStream::new(&mut b4, term);
        assert_eq!(parse_regexp(&mut ts4),
                   Conc(~OnePlus(~CharClass(~[Range('0', '9')])),
                        ~Conc(~Str(~"."), ~OnePlus(~CharClass(~[Range('0', '9')])))));
    }
}
<|endoftext|>