<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use arbitrary::*;

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: &[u8]) {
//      let mut g = create_generator!();
//
//      // Invoke everything you need.
//      //
//      // You should use g.g() to get an arbitrary value of any type that
//      // implements Arbitrary [1]. This is how fuzzer affects the
//      // execution—by feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.2.0/arbitrary/trait.Arbitrary.html
//      //
//      // Print out the structures you create with arbitrary data with
//      // debug!().
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

// A helper for generating arbitrary data.
struct Generator<'a> {
  buffer: RingBuffer<'a>,
}

impl<'a> Generator<'a> {
  fn new(data: &'a [u8]) -> Result<Self, BufferError> {
    Ok(Self { buffer: RingBuffer::new(data, data.len())? })
  }

  fn g<T: Arbitrary>(&mut self) -> T {
    <T as Arbitrary>::arbitrary(&mut self.buffer).unwrap()
  }
}

macro_rules! create_generator {
  ($data:expr) => {{
    let g = Generator::new($data);
    if g.is_err() {
      return;
    }
    g.unwrap()
  }};
}

pub fn fuzz_construct_context(data: &[u8]) {
  let mut g = create_generator!(data);

  let mut config = Config::default();
  config.threads = 1;
  config.enc.width = g.g();
  config.enc.height = g.g();
  config.enc.bit_depth = (g.g::<u8>() % 17) as usize;
  config.enc.still_picture = g.g();
  config.enc.time_base = Rational::new(g.g(), g.g());
  config.enc.min_key_frame_interval = g.g();
  config.enc.max_key_frame_interval = g.g();
  config.enc.reservoir_frame_delay = g.g();
  config.enc.low_latency = g.g();
  config.enc.quantizer = g.g();
  config.enc.min_quantizer = g.g();
  config.enc.bitrate = g.g();
  config.enc.tile_cols = g.g();
  config.enc.tile_rows = g.g();
  config.enc.tiles = g.g();
  config.enc.rdo_lookahead_frames = g.g();
  config.enc.speed_settings = SpeedSettings::from_preset(g.g());
  config.enc.show_psnr = g.g();
  config.enc.train_rdo = g.g();

  debug!("config = {:#?}", config);

  let _: Result<Context<u16>, _> = config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

pub fn fuzz_encode(data: &[u8]) {
  let mut g = create_generator!(data);

  let mut config = Config::default();
  config.threads = 1;
  config.enc.width = g.g::<u8>() as usize + 1;
  config.enc.height = g.g::<u8>() as usize + 1;
  config.enc.still_picture = g.g();
  config.enc.time_base = Rational::new(g.g(), g.g());
  config.enc.min_key_frame_interval = (g.g::<u8>() % 4) as u64;
  config.enc.max_key_frame_interval = (g.g::<u8>() % 4) as u64 + 1;
  config.enc.low_latency = g.g();
  config.enc.quantizer = g.g();
  config.enc.min_quantizer = g.g();
  config.enc.bitrate = g.g();
  // config.enc.tile_cols = g.g();
  // config.enc.tile_rows = g.g();
  // config.enc.tiles = g.g();
  config.enc.rdo_lookahead_frames = g.g();
  config.enc.speed_settings = SpeedSettings::from_preset(10);

  debug!("config = {:#?}", config);

  let res = config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let frame_count = g.g::<u8>() % 3 + 1;
  let frames = (0..frame_count).map(|_| {
    let mut frame = Frame::new(
      config.enc.width,
      config.enc.height,
      config.enc.chroma_sampling,
    );

    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = g.g();
        }
      }
    }

    frame
  });

  let _ = encode_frames(&mut context, frames);
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(data: &[u8]) {
  use crate::test_encode_decode::*;

  let mut g = create_generator!(data);

  let w = g.g::<u8>() as usize + 1;
  let h = g.g::<u8>() as usize + 1;
  let speed = 10;
  let q = g.g();
  let limit = (g.g::<u8>() % 3) as usize + 1;
  let min_keyint = g.g::<u64>() % 4;
  let max_keyint = g.g::<u64>() % 4 + 1;
  let low_latency = g.g();
  let bitrate = g.g();

  debug!(
    "w = {:#?}\n\
     h = {:#?}\n\
     speed = {:#?}\n\
     q = {:#?}\n\
     limit = {:#?}\n\
     min_keyint = {:#?}\n\
     max_keyint = {:#?}\n\
     low_latency = {:#?}\n\
     bitrate = {:#?}",
    w, h, speed, q, limit, min_keyint, max_keyint, low_latency, bitrate
  );

  let mut dec = get_decoder::<u8>("dav1d", w, h);
  dec.encode_decode(
    w,
    h,
    speed,
    q,
    limit,
    8,
    Default::default(),
    min_keyint,
    max_keyint,
    low_latency,
    bitrate,
    1,
    1,
  );
}
<commit_msg>Resolve build errors for fuzzer<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use arbitrary::*;

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: &[u8]) {
//      let mut g = create_generator!();
//
//      // Invoke everything you need.
//      //
//      // You should use g.g() to get an arbitrary value of any type that
//      // implements Arbitrary [1]. This is how fuzzer affects the
//      // execution—by feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.2.0/arbitrary/trait.Arbitrary.html
//      //
//      // Print out the structures you create with arbitrary data with
//      // debug!().
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

// A helper for generating arbitrary data.
struct Generator<'a> {
  buffer: RingBuffer<'a>,
}

impl<'a> Generator<'a> {
  fn new(data: &'a [u8]) -> Result<Self, BufferError> {
    Ok(Self { buffer: RingBuffer::new(data, data.len())? })
  }

  fn g<T: Arbitrary>(&mut self) -> T {
    <T as Arbitrary>::arbitrary(&mut self.buffer).unwrap()
  }
}

macro_rules! create_generator {
  ($data:expr) => {{
    let g = Generator::new($data);
    if g.is_err() {
      return;
    }
    g.unwrap()
  }};
}

pub fn fuzz_construct_context(data: &[u8]) {
  let mut g = create_generator!(data);

  let mut config = Config::default();
  config.threads = 1;
  config.enc.width = g.g();
  config.enc.height = g.g();
  config.enc.bit_depth = (g.g::<u8>() % 17) as usize;
  config.enc.still_picture = g.g();
  config.enc.time_base = Rational::new(g.g(), g.g());
  config.enc.min_key_frame_interval = g.g();
  config.enc.max_key_frame_interval = g.g();
  config.enc.reservoir_frame_delay = g.g();
  config.enc.low_latency = g.g();
  config.enc.quantizer = g.g();
  config.enc.min_quantizer = g.g();
  config.enc.bitrate = g.g();
  config.enc.tile_cols = g.g();
  config.enc.tile_rows = g.g();
  config.enc.tiles = g.g();
  config.enc.rdo_lookahead_frames = g.g();
  config.enc.speed_settings = SpeedSettings::from_preset(g.g());

  debug!("config = {:#?}", config);

  let _: Result<Context<u16>, _> = config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

pub fn fuzz_encode(data: &[u8]) {
  let mut g = create_generator!(data);

  let mut config = Config::default();
  config.threads = 1;
  config.enc.width = g.g::<u8>() as usize + 1;
  config.enc.height = g.g::<u8>() as usize + 1;
  config.enc.still_picture = g.g();
  config.enc.time_base = Rational::new(g.g(), g.g());
  config.enc.min_key_frame_interval = (g.g::<u8>() % 4) as u64;
  config.enc.max_key_frame_interval = (g.g::<u8>() % 4) as u64 + 1;
  config.enc.low_latency = g.g();
  config.enc.quantizer = g.g();
  config.enc.min_quantizer = g.g();
  config.enc.bitrate = g.g();
  // config.enc.tile_cols = g.g();
  // config.enc.tile_rows = g.g();
  // config.enc.tiles = g.g();
  config.enc.rdo_lookahead_frames = g.g();
  config.enc.speed_settings = SpeedSettings::from_preset(10);

  debug!("config = {:#?}", config);

  let res = config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let frame_count = g.g::<u8>() % 3 + 1;
  let frames = (0..frame_count).map(|_| {
    let mut frame = Frame::new(
      config.enc.width,
      config.enc.height,
      config.enc.chroma_sampling,
    );

    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = g.g();
        }
      }
    }

    frame
  });

  let _ = encode_frames(&mut context, frames);
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(data: &[u8]) {
  use crate::test_encode_decode::*;

  let mut g = create_generator!(data);

  let w = g.g::<u8>() as usize + 1;
  let h = g.g::<u8>() as usize + 1;
  let speed = 10;
  let q = g.g();
  let limit = (g.g::<u8>() % 3) as usize + 1;
  let min_keyint = g.g::<u64>() % 4;
  let max_keyint = g.g::<u64>() % 4 + 1;
  let switch_frame_interval = 0;
  let low_latency = g.g();
  let error_resilient = false;
  let bitrate = g.g();
  let still_picture = false;

  debug!(
    "w = {:#?}\n\
     h = {:#?}\n\
     speed = {:#?}\n\
     q = {:#?}\n\
     limit = {:#?}\n\
     min_keyint = {:#?}\n\
     max_keyint = {:#?}\n\
     low_latency = {:#?}\n\
     bitrate = {:#?}",
    w, h, speed, q, limit, min_keyint, max_keyint, low_latency, bitrate
  );

  let mut dec = get_decoder::<u8>("dav1d", w, h);
  dec.encode_decode(
    w,
    h,
    speed,
    q,
    limit,
    8,
    Default::default(),
    min_keyint,
    max_keyint,
    switch_frame_interval,
    low_latency,
    error_resilient,
    bitrate,
    1,
    1,
    still_picture,
  );
}
<|endoftext|>


<commit_before>use failure::Error;
use postgres::Connection;

#[derive(Debug, Fail)]
enum BlacklistError {
    #[fail(display = "crate {} is already on the blacklist", _0)]
    CrateAlreadyOnBlacklist(String),

    #[fail(display = "crate {} is not on the blacklist", _0)]
    CrateNotOnBlacklist(String),
}

pub fn is_blacklisted(conn: &Connection, name: &str) -> Result<bool, Error> {
    let rows = conn.query(
        "SELECT COUNT(*) FROM blacklisted_crates WHERE crate_name = $1;",
        &[&name],
    )?;
    let count: i64 = rows.get(0).get(0);

    Ok(count != 0)
}

pub fn list_crates(conn: &Connection) -> Result<Vec<String>, Error> {
    let rows = conn.query(
        "SELECT crate_name FROM blacklisted_crates ORDER BY crate_name asc;",
        &[],
    )?;

    Ok(rows.into_iter().map(|row| row.get(0)).collect())
}

pub fn add_crate(conn: &Connection, name: &str) -> Result<(), Error> {
    if is_blacklisted(conn, name)? {
        return Err(BlacklistError::CrateAlreadyOnBlacklist(name.into()).into());
    }

    conn.execute(
        "INSERT INTO blacklisted_crates (crate_name) VALUES ($1);",
        &[&name],
    )?;

    Ok(())
}

pub fn remove_crate(conn: &Connection, name: &str) -> Result<(), Error> {
    if !is_blacklisted(conn, name)? {
        return Err(BlacklistError::CrateNotOnBlacklist(name.into()).into());
    }

    conn.execute(
        "DELETE FROM blacklisted_crates WHERE crate_name = $1;",
        &[&name],
    )?;

    Ok(())
}

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

    #[test]
    fn test_add_to_and_remove_from_blacklist() {
        crate::test::with_database(|db| {
            assert!(is_blacklisted(db.conn(), "crate foo")? == false);
            add_crate(db.conn(), "crate foo")?;
            assert!(is_blacklisted(db.conn(), "crate foo")? == true);
            remove_crate(db.conn(), "crate foo")?;
            assert!(is_blacklisted(db.conn(), "crate foo")? == false);
            Ok(())
        });
    }

    #[test]
    fn test_add_twice_to_blacklist() {
        crate::test::with_database(|db| {
            add_crate(db.conn(), "crate foo")?;
            assert!(add_crate(db.conn(), "crate foo").is_err());
            add_crate(db.conn(), "crate bar")?;

            Ok(())
        });
    }

    #[test]
    fn test_remove_non_existing_crate() {
        crate::test::with_database(|db| {
            assert!(remove_crate(db.conn(), "crate foo").is_err());

            Ok(())
        });
    }
}
<commit_msg>Add test for list_blacklist<commit_after>use failure::Error;
use postgres::Connection;

#[derive(Debug, Fail)]
enum BlacklistError {
    #[fail(display = "crate {} is already on the blacklist", _0)]
    CrateAlreadyOnBlacklist(String),

    #[fail(display = "crate {} is not on the blacklist", _0)]
    CrateNotOnBlacklist(String),
}

pub fn is_blacklisted(conn: &Connection, name: &str) -> Result<bool, Error> {
    let rows = conn.query(
        "SELECT COUNT(*) FROM blacklisted_crates WHERE crate_name = $1;",
        &[&name],
    )?;
    let count: i64 = rows.get(0).get(0);

    Ok(count != 0)
}

pub fn list_crates(conn: &Connection) -> Result<Vec<String>, Error> {
    let rows = conn.query(
        "SELECT crate_name FROM blacklisted_crates ORDER BY crate_name asc;",
        &[],
    )?;

    Ok(rows.into_iter().map(|row| row.get(0)).collect())
}

pub fn add_crate(conn: &Connection, name: &str) -> Result<(), Error> {
    if is_blacklisted(conn, name)? {
        return Err(BlacklistError::CrateAlreadyOnBlacklist(name.into()).into());
    }

    conn.execute(
        "INSERT INTO blacklisted_crates (crate_name) VALUES ($1);",
        &[&name],
    )?;

    Ok(())
}

pub fn remove_crate(conn: &Connection, name: &str) -> Result<(), Error> {
    if !is_blacklisted(conn, name)? {
        return Err(BlacklistError::CrateNotOnBlacklist(name.into()).into());
    }

    conn.execute(
        "DELETE FROM blacklisted_crates WHERE crate_name = $1;",
        &[&name],
    )?;

    Ok(())
}

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

    #[test]
    fn test_list_blacklist() {
        crate::test::with_database(|db| {
            // crates are added out of order to verify sorting
            add_crate(db.conn(), "crate A")?;
            add_crate(db.conn(), "crate C")?;
            add_crate(db.conn(), "crate B")?;

            assert!(list_crates(db.conn())? == vec!["crate A", "crate B", "crate C"]);
            Ok(())
        });
    }

    #[test]
    fn test_add_to_and_remove_from_blacklist() {
        crate::test::with_database(|db| {
            assert!(is_blacklisted(db.conn(), "crate foo")? == false);
            add_crate(db.conn(), "crate foo")?;
            assert!(is_blacklisted(db.conn(), "crate foo")? == true);
            remove_crate(db.conn(), "crate foo")?;
            assert!(is_blacklisted(db.conn(), "crate foo")? == false);
            Ok(())
        });
    }

    #[test]
    fn test_add_twice_to_blacklist() {
        crate::test::with_database(|db| {
            add_crate(db.conn(), "crate foo")?;
            assert!(add_crate(db.conn(), "crate foo").is_err());
            add_crate(db.conn(), "crate bar")?;

            Ok(())
        });
    }

    #[test]
    fn test_remove_non_existing_crate() {
        crate::test::with_database(|db| {
            assert!(remove_crate(db.conn(), "crate foo").is_err());

            Ok(())
        });
    }
}
<|endoftext|>


<commit_before>pub use mat::{Mat2, Mat3, Mat4};
pub use vec::{Vec2, Vec3, Vec4};
pub use quat::Quat;

use vec::{Vector, NumericVector};
use mat::{NumericMatrix, NumericMatrix_NxN};

// Vector aliases

pub type vec2  = Vec2<f32>;             /// a two-component single-precision floating-point vector
pub type vec3  = Vec3<f32>;             /// a three-component single-precision floating-point vector
pub type vec4  = Vec4<f32>;             /// a four-component single-precision floating-point vector

pub type dvec2 = Vec2<f64>;             /// a two-component double-precision floating-point vector
pub type dvec3 = Vec3<f64>;             /// a three-component double-precision floating-point vector
pub type dvec4 = Vec4<f64>;             /// a four-component double-precision floating-point vector

pub type bvec2 = Vec2<bool>;            /// a two-component Boolean vector
pub type bvec3 = Vec3<bool>;            /// a three-component Boolean vector
pub type bvec4 = Vec4<bool>;            /// a four-component Boolean vector

pub type ivec2 = Vec2<i32>;             /// a two-component signed integer vector
pub type ivec3 = Vec3<i32>;             /// a three-component signed integer vector
pub type ivec4 = Vec4<i32>;             /// a four-component signed integer vector

pub type uvec2 = Vec2<u32>;             /// a two-component unsigned integer vector
pub type uvec3 = Vec3<u32>;             /// a three-component unsigned integer vector
pub type uvec4 = Vec4<u32>;             /// a four-component unsigned integer vector

//
// Wrappers to make working with static functions cleaner
//
// For example:   let v = dvec::identity();
// as opposed to: let v: dvec4 = NumericVector::identity();
//

pub impl vec2 {
    #[inline(always)] static pure fn new(x: f32, y: f32) -> vec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: f32) -> vec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> vec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> vec2 { NumericVector::zero()     }
}

pub impl vec3 {
    #[inline(always)] static pure fn new(x: f32, y: f32, z: f32) -> vec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: f32) -> vec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> vec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> vec3 { NumericVector::zero()     }
}

pub impl vec4 {
    #[inline(always)] static pure fn new(x: f32, y: f32, z: f32, w: f32) -> vec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: f32) -> vec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> vec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> vec4 { NumericVector::zero()     }
}

pub impl dvec2 {
    #[inline(always)] static pure fn new(x: f64, y: f64) -> dvec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: f64) -> dvec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> dvec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> dvec2 { NumericVector::zero()     }
}

pub impl dvec3 {
    #[inline(always)] static pure fn new(x: f64, y: f64, z: f64) -> dvec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: f64) -> dvec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> dvec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> dvec3 { NumericVector::zero()     }
}

pub impl dvec4 {
    #[inline(always)] static pure fn new(x: f64, y: f64, z: f64, w: f64) -> dvec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: f64) -> dvec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> dvec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> dvec4 { NumericVector::zero()     }
}

pub impl bvec2 {
    #[inline(always)] static pure fn new(x: bool, y: bool) -> bvec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: bool) -> bvec2 { Vector::from_value(v) }
    // #[inline(always)] static pure fn identity() -> bvec2 { NumericVector::identity() }
    // #[inline(always)] static pure fn zero() -> bvec2 { NumericVector::zero()     }
}

pub impl bvec3 {
    #[inline(always)] static pure fn new(x: bool, y: bool, z: bool) -> bvec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: bool) -> bvec3 { Vector::from_value(v) }
    // #[inline(always)] static pure fn identity() -> bvec3 { NumericVector::identity() }
    // #[inline(always)] static pure fn zero() -> bvec3 { NumericVector::zero()     }
}

pub impl bvec4 {
    #[inline(always)] static pure fn new(x: bool, y: bool, z: bool, w: bool) -> bvec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: bool) -> bvec4 { Vector::from_value(v) }
    // #[inline(always)] static pure fn identity() -> bvec4 { NumericVector::identity() }
    // #[inline(always)] static pure fn zero() -> bvec4 { NumericVector::zero()     }
}

pub impl ivec2 {
    #[inline(always)] static pure fn new(x: i32, y: i32) -> ivec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: i32) -> ivec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> ivec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero()     -> ivec2 { NumericVector::zero()     }
}

pub impl ivec3 {
    #[inline(always)] static pure fn new(x: i32, y: i32, z: i32) -> ivec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: i32) -> ivec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> ivec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero()     -> ivec3 { NumericVector::zero()     }
}

pub impl ivec4 {
    #[inline(always)] static pure fn new(x: i32, y: i32, z: i32, w: i32) -> ivec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: i32) -> ivec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> ivec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero()     -> ivec4 { NumericVector::zero()     }
}

pub impl uvec2 {
    #[inline(always)] static pure fn new(x: u32, y: u32) -> uvec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: u32) -> uvec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> uvec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero()     -> uvec2 { NumericVector::zero()     }
}

pub impl uvec3 {
    #[inline(always)] static pure fn new(x: u32, y: u32, z: u32) -> uvec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: u32) -> uvec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> uvec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero()     -> uvec3 { NumericVector::zero()     }
}

pub impl uvec4 {
    #[inline(always)] static pure fn new(x: u32, y: u32, z: u32, w: u32) -> uvec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: u32) -> uvec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> uvec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero()     -> uvec4 { NumericVector::zero()     }
}

// Matrix aliases

pub type mat2 = Mat2<f32>;              /// a 2×2 single-precision floating-point matrix
pub type mat3 = Mat3<f32>;              /// a 3×3 single-precision floating-point matrix
pub type mat4 = Mat4<f32>;              /// a 4×4 single-precision floating-point matrix
pub type mat2x2 = Mat2<f32>;            /// same as a `mat2`
// pub type mat2x3 =                    /// a single-precision floating-point matrix with 2 columns and 3 rows
// pub type mat2x4 =                    /// a single-precision floating-point matrix with 2 columns and 4 rows
// pub type mat3x2 =                    /// a single-precision floating-point matrix with 3 columns and 2 rows
pub type mat3x3 = Mat3<f32>;            /// same as a `mat3`
// pub type mat3x4 =                    /// a single-precision floating-point matrix with 3 columns and 4 rows
// pub type mat4x2 =                    /// a single-precision floating-point matrix with 4 columns and 2 rows
// pub type mat4x3 =                    /// a single-precision floating-point matrix with 4 columns and 3 rows
pub type mat4x4 = Mat4<f32>;            /// same as a `mat4`

pub type dmat2 = Mat2<f64>;             /// a 2×2 double-precision floating-point matrix
pub type dmat3 = Mat3<f64>;             /// a 3×3 double-precision floating-point matrix
pub type dmat4 = Mat4<f64>;             /// a 4×4 double-precision floating-point matrix
pub type dmat2x2 = Mat2<f64>;           /// same as a `dmat2`
// pub type dmat2x3 =                   /// a double-precision floating-point matrix with 2 columns and 3 rows
// pub type dmat2x4 =                   /// a double-precision floating-point matrix with 2 columns and 4 rows
// pub type dmat3x2 =                   /// a double-precision floating-point matrix with 3 columns and 2 rows
pub type dmat3x3 = Mat3<f64>;           /// same as a `dmat3`
// pub type dmat3x4 =                   /// a double-precision floating-point matrix with 3 columns and 4 rows
// pub type dmat4x2 =                   /// a double-precision floating-point matrix with 4 columns and 2 rows
// pub type dmat4x3 =                   /// a double-precision floating-point matrix with 4 columns and 3 rows
pub type dmat4x4 = Mat4<f64>;           /// same as a `dmat4`

//
// Wrappers to make working with static functions cleaner
//
// For example:   let m = dmat::identity();
// as opposed to: let m: dmat4 = NumericMatrix_NxN::identity();
//

pub impl mat2  {
    #[inline(always)] static pure fn identity() -> mat2  { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero()     -> mat2  { NumericMatrix::zero()         }
}

pub impl mat3  {
    #[inline(always)] static pure fn identity() -> mat3  { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero()     -> mat3  { NumericMatrix::zero()         }
}

pub impl mat4  {
    #[inline(always)] static pure fn identity() -> mat4  { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero()     -> mat4  { NumericMatrix::zero()         }
}

pub impl dmat2 {
    #[inline(always)] static pure fn identity() -> dmat2 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero()     -> dmat2 { NumericMatrix::zero()         }
}

pub impl dmat3 {
    #[inline(always)] static pure fn identity() -> dmat3 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero()     -> dmat3 { NumericMatrix::zero()         }
}

pub impl dmat4 {
    #[inline(always)] static pure fn identity() -> dmat4 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero()     -> dmat4 { NumericMatrix::zero()         }
}

// Quaternion types

// These quaternion type aliases are not actually specified in the GLSL spec
// but they follow the same nomenclature

pub type quat4  = Quat<f32>;             /// a single-precision floating-point quaternion
pub type dquat4 = Quat<f64>;             /// a double-precision floating-point quaternion

// prevents "error: expected item"
priv fn hack() {}<commit_msg>Formatting<commit_after>pub use mat::{Mat2, Mat3, Mat4};
pub use vec::{Vec2, Vec3, Vec4};
pub use quat::Quat;

use vec::{Vector, NumericVector};
use mat::{NumericMatrix, NumericMatrix_NxN};

// Vector aliases

pub type vec2  = Vec2<f32>;             /// a two-component single-precision floating-point vector
pub type vec3  = Vec3<f32>;             /// a three-component single-precision floating-point vector
pub type vec4  = Vec4<f32>;             /// a four-component single-precision floating-point vector

pub type dvec2 = Vec2<f64>;             /// a two-component double-precision floating-point vector
pub type dvec3 = Vec3<f64>;             /// a three-component double-precision floating-point vector
pub type dvec4 = Vec4<f64>;             /// a four-component double-precision floating-point vector

pub type bvec2 = Vec2<bool>;            /// a two-component Boolean vector
pub type bvec3 = Vec3<bool>;            /// a three-component Boolean vector
pub type bvec4 = Vec4<bool>;            /// a four-component Boolean vector

pub type ivec2 = Vec2<i32>;             /// a two-component signed integer vector
pub type ivec3 = Vec3<i32>;             /// a three-component signed integer vector
pub type ivec4 = Vec4<i32>;             /// a four-component signed integer vector

pub type uvec2 = Vec2<u32>;             /// a two-component unsigned integer vector
pub type uvec3 = Vec3<u32>;             /// a three-component unsigned integer vector
pub type uvec4 = Vec4<u32>;             /// a four-component unsigned integer vector

//
// Wrappers to make working with static functions cleaner
//
// For example:   let v = dvec::identity();
// as opposed to: let v: dvec4 = NumericVector::identity();
//

pub impl vec2 {
    #[inline(always)] static pure fn new(x: f32, y: f32) -> vec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: f32) -> vec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> vec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> vec2 { NumericVector::zero() }
}

pub impl vec3 {
    #[inline(always)] static pure fn new(x: f32, y: f32, z: f32) -> vec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: f32) -> vec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> vec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> vec3 { NumericVector::zero() }
}

pub impl vec4 {
    #[inline(always)] static pure fn new(x: f32, y: f32, z: f32, w: f32) -> vec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: f32) -> vec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> vec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> vec4 { NumericVector::zero() }
}

pub impl dvec2 {
    #[inline(always)] static pure fn new(x: f64, y: f64) -> dvec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: f64) -> dvec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> dvec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> dvec2 { NumericVector::zero() }
}

pub impl dvec3 {
    #[inline(always)] static pure fn new(x: f64, y: f64, z: f64) -> dvec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: f64) -> dvec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> dvec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> dvec3 { NumericVector::zero() }
}

pub impl dvec4 {
    #[inline(always)] static pure fn new(x: f64, y: f64, z: f64, w: f64) -> dvec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: f64) -> dvec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> dvec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> dvec4 { NumericVector::zero() }
}

pub impl bvec2 {
    #[inline(always)] static pure fn new(x: bool, y: bool) -> bvec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: bool) -> bvec2 { Vector::from_value(v) }
    // #[inline(always)] static pure fn identity() -> bvec2 { NumericVector::identity() }
    // #[inline(always)] static pure fn zero() -> bvec2 { NumericVector::zero() }
}

pub impl bvec3 {
    #[inline(always)] static pure fn new(x: bool, y: bool, z: bool) -> bvec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: bool) -> bvec3 { Vector::from_value(v) }
    // #[inline(always)] static pure fn identity() -> bvec3 { NumericVector::identity() }
    // #[inline(always)] static pure fn zero() -> bvec3 { NumericVector::zero() }
}

pub impl bvec4 {
    #[inline(always)] static pure fn new(x: bool, y: bool, z: bool, w: bool) -> bvec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: bool) -> bvec4 { Vector::from_value(v) }
    // #[inline(always)] static pure fn identity() -> bvec4 { NumericVector::identity() }
    // #[inline(always)] static pure fn zero() -> bvec4 { NumericVector::zero() }
}

pub impl ivec2 {
    #[inline(always)] static pure fn new(x: i32, y: i32) -> ivec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: i32) -> ivec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> ivec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> ivec2 { NumericVector::zero() }
}

pub impl ivec3 {
    #[inline(always)] static pure fn new(x: i32, y: i32, z: i32) -> ivec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: i32) -> ivec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> ivec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> ivec3 { NumericVector::zero() }
}

pub impl ivec4 {
    #[inline(always)] static pure fn new(x: i32, y: i32, z: i32, w: i32) -> ivec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: i32) -> ivec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> ivec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> ivec4 { NumericVector::zero() }
}

pub impl uvec2 {
    #[inline(always)] static pure fn new(x: u32, y: u32) -> uvec2 { Vec2::new(x, y) }
    #[inline(always)] static pure fn from_value(v: u32) -> uvec2 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> uvec2 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> uvec2 { NumericVector::zero() }
}

pub impl uvec3 {
    #[inline(always)] static pure fn new(x: u32, y: u32, z: u32) -> uvec3 { Vec3::new(x, y, z) }
    #[inline(always)] static pure fn from_value(v: u32) -> uvec3 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> uvec3 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> uvec3 { NumericVector::zero() }
}

pub impl uvec4 {
    #[inline(always)] static pure fn new(x: u32, y: u32, z: u32, w: u32) -> uvec4 { Vec4::new(x, y, z, w) }
    #[inline(always)] static pure fn from_value(v: u32) -> uvec4 { Vector::from_value(v) }
    #[inline(always)] static pure fn identity() -> uvec4 { NumericVector::identity() }
    #[inline(always)] static pure fn zero() -> uvec4 { NumericVector::zero() }
}

// Matrix aliases

pub type mat2 = Mat2<f32>;              /// a 2×2 single-precision floating-point matrix
pub type mat3 = Mat3<f32>;              /// a 3×3 single-precision floating-point matrix
pub type mat4 = Mat4<f32>;              /// a 4×4 single-precision floating-point matrix
pub type mat2x2 = Mat2<f32>;            /// same as a `mat2`
// pub type mat2x3 =                    /// a single-precision floating-point matrix with 2 columns and 3 rows
// pub type mat2x4 =                    /// a single-precision floating-point matrix with 2 columns and 4 rows
// pub type mat3x2 =                    /// a single-precision floating-point matrix with 3 columns and 2 rows
pub type mat3x3 = Mat3<f32>;            /// same as a `mat3`
// pub type mat3x4 =                    /// a single-precision floating-point matrix with 3 columns and 4 rows
// pub type mat4x2 =                    /// a single-precision floating-point matrix with 4 columns and 2 rows
// pub type mat4x3 =                    /// a single-precision floating-point matrix with 4 columns and 3 rows
pub type mat4x4 = Mat4<f32>;            /// same as a `mat4`

pub type dmat2 = Mat2<f64>;             /// a 2×2 double-precision floating-point matrix
pub type dmat3 = Mat3<f64>;             /// a 3×3 double-precision floating-point matrix
pub type dmat4 = Mat4<f64>;             /// a 4×4 double-precision floating-point matrix
pub type dmat2x2 = Mat2<f64>;           /// same as a `dmat2`
// pub type dmat2x3 =                   /// a double-precision floating-point matrix with 2 columns and 3 rows
// pub type dmat2x4 =                   /// a double-precision floating-point matrix with 2 columns and 4 rows
// pub type dmat3x2 =                   /// a double-precision floating-point matrix with 3 columns and 2 rows
pub type dmat3x3 = Mat3<f64>;           /// same as a `dmat3`
// pub type dmat3x4 =                   /// a double-precision floating-point matrix with 3 columns and 4 rows
// pub type dmat4x2 =                   /// a double-precision floating-point matrix with 4 columns and 2 rows
// pub type dmat4x3 =                   /// a double-precision floating-point matrix with 4 columns and 3 rows
pub type dmat4x4 = Mat4<f64>;           /// same as a `dmat4`

//
// Wrappers to make working with static functions cleaner
//
// For example:   let m = dmat::identity();
// as opposed to: let m: dmat4 = NumericMatrix_NxN::identity();
//

pub impl mat2  {
    #[inline(always)] static pure fn identity() -> mat2 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero() -> mat2  { NumericMatrix::zero() }
}

pub impl mat3  {
    #[inline(always)] static pure fn identity() -> mat3 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero() -> mat3  { NumericMatrix::zero() }
}

pub impl mat4  {
    #[inline(always)] static pure fn identity() -> mat4 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero() -> mat4  { NumericMatrix::zero() }
}

pub impl dmat2 {
    #[inline(always)] static pure fn identity() -> dmat2 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero() -> dmat2 { NumericMatrix::zero() }
}

pub impl dmat3 {
    #[inline(always)] static pure fn identity() -> dmat3 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero() -> dmat3 { NumericMatrix::zero() }
}

pub impl dmat4 {
    #[inline(always)] static pure fn identity() -> dmat4 { NumericMatrix_NxN::identity() }
    #[inline(always)] static pure fn zero() -> dmat4 { NumericMatrix::zero() }
}

// Quaternion types

// These quaternion type aliases are not actually specified in the GLSL spec
// but they follow the same nomenclature

pub type quat4  = Quat<f32>;             /// a single-precision floating-point quaternion
pub type dquat4 = Quat<f64>;             /// a double-precision floating-point quaternion

// prevents "error: expected item"
priv fn hack() {}<|endoftext|>


<commit_before>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )* }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = { string_literal |
                    array_literal |
                    object_literal |
                    number_literal |
                    null_literal |
                    boolean_literal }

        null_literal = { ["null"] }
        boolean_literal = { ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["<"]|[">"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
        name = _{ subexpression | identifier }

        param = { literal | reference | subexpression }
        hash = { identifier ~ ["="] ~ param }
        exp_line = _{ identifier ~ (hash|param)* }

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        pre_whitespace_omitter = { ["~"] }
        pro_whitespace_omitter = { ["~"] }

        expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
                        pro_whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ pre_whitespace_omitter? ~ name ~
                                      pro_whitespace_omitter? ~ ["}}}"] }

        helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        pro_whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                      pro_whitespace_omitter? ~ ["}}"] }
        helper_block = _{ helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                         helper_block_end }

        raw_block_start = { ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                                       pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                     pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

        hbs_comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_expression |
            helper_block |
            raw_block |
            hbs_comment )*
        }

        parameter = _{ param ~ eoi }
        handlebars = _{ template ~ eoi }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]",
                 "some-name"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hbs_comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.subexpression());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_expression() {
    let s = vec!["{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}",
                 "{{exp key=1}}",
                 "{{exp key=ref}}",
                 "{{exp key=(sub)}}",
                 "{{exp key=(sub 0)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}
<commit_msg>allow identifiers to contain "-"<commit_after>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )* }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = { string_literal |
                    array_literal |
                    object_literal |
                    number_literal |
                    null_literal |
                    boolean_literal }

        null_literal = { ["null"] }
        boolean_literal = { ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["<"]|[">"]|["-"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
        name = _{ subexpression | identifier }

        param = { literal | reference | subexpression }
        hash = { identifier ~ ["="] ~ param }
        exp_line = _{ identifier ~ (hash|param)* }

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        pre_whitespace_omitter = { ["~"] }
        pro_whitespace_omitter = { ["~"] }

        expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
                        pro_whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ pre_whitespace_omitter? ~ name ~
                                      pro_whitespace_omitter? ~ ["}}}"] }

        helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        pro_whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                      pro_whitespace_omitter? ~ ["}}"] }
        helper_block = _{ helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                         helper_block_end }

        raw_block_start = { ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                                       pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                     pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

        hbs_comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_expression |
            helper_block |
            raw_block |
            hbs_comment )*
        }

        parameter = _{ param ~ eoi }
        handlebars = _{ template ~ eoi }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]",
                 "some-name"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hbs_comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.subexpression());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_expression() {
    let s = vec!["{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}",
                 "{{exp key=1}}",
                 "{{exp key=ref}}",
                 "{{exp key=(sub)}}",
                 "{{exp key=(sub 0)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

use parsers::*;
use regex::{Captures, Regex};

pub enum AddOp {
  Add,
  Subtract,
}

pub enum MultOp {
  Multiply,
  Divide,
}

type AddTerm = (AddOp, Expr);
type MultTerm = (MultOp, Expr);

#[deriving(Show)]
pub enum Expr {
  Variable(String),
  Num(int),
  AddSub(Vec<AddTerm>), //a + b - c + d becomes [(+ a) (+ b) (- c) (+ d)]
  MultDiv(Vec<MultTerm>),
}

pub enum Statement {
  Assign(String, Expr),
  Output(Expr),
}

#[deriving(Show)]
#[deriving(Eq)]
#[deriving(PartialEq)]
#[deriving(Clone)]
pub enum Token {
  Equals,
  Ident(String),
  Number(int),
  PlusSign,
  MinusSign,
  MultSign,
  DivideSign,
  OutputCmd,
  NewLine,
  OpenParen,
  CloseParen,
}

pub macro_rules! or {
  ($a: expr, $b: expr) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| $b,
    }
  };
  ($a: expr, $b: expr, $c: expr) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| or!($b, $c),
    }
  }
}

pub macro_rules! map {
  ($a: expr, $b: expr) => {
    box MapParser{
      parser: $a,
      mapper: box $b
    }
  }
}

pub macro_rules! link {
  ($a: expr, $b: expr) => {
    box DualParser{
      first: $a,
      second: $b,
    }
  }
}

pub macro_rules! repsep {
  ($rep: expr, $sep: expr) => {
    box RepSepParser{
      rep: $rep,
      sep: $sep,
    }
  }
}

type Lexer<'a> = Box<Parser<'a, &'a str, Token> + 'a>;

pub fn token<'a>() -> Box<Parser<'a, &'a str, Vec<Token>> + 'a> {

  macro_rules! literal{
    ($reg: expr, $lit: expr ) => {map!(
      box RegexLiteralParser{regex : Regex::new($reg).unwrap()},
      |&: ()| $lit
    ) as Lexer<'a>}
  }

  macro_rules! lor{
    ($a: expr, $b: expr) => (or!($a,$b) as Lexer<'a>)
  }

  fn ident<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*([a-z]+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Ident(from_str(caps.at(1)).unwrap())
  )}

  fn number<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*(\d+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Number(from_str(caps.at(1)).unwrap())
  )}

  box RepParser{
    parser: lor!(
      literal!(r"^[ \t]*out", OutputCmd),
      lor!(
      literal!(r"^[ \t]*\r?\n[ \t]*", NewLine),
      lor!(
      literal!(r"^[ \t]*\(", OpenParen),
      lor!(
      literal!(r"^[ \t]*\)", CloseParen),
      lor!(
      number(),
      lor!(
      literal!(r"^[ \t]*\+", PlusSign),
      lor!(
      literal!(r"^[ \t]*=", Equals),
      lor!(
      ident(),
      literal!(r"^[ \t]*\*", MultSign)
      ))))))))
  }

}

type LParser<'a> = Box<Parser<'a, &'a [Token], Expr> + 'a>;

fn assign<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser: box DualParser {
      first: box DualParser {
        first: variable(),
        second: literal(Equals),
      },
      second: expr()
    },
    mapper: box |&: ((var, eq), expr): ((Expr, Token), Expr)| -> Statement match var{
      Variable(name) => Assign(name, expr),
      _ => panic!("FUCK")
    }
  }
}

fn output<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser : box DualParser {
      first: literal(OutputCmd),
      second: expr(),
    },
    mapper: box |&: (out, var): (Token, Expr)| Output(var)
  }
}

pub fn statement<'a>() -> Box<Parser<'a, &'a [Token], Vec<Statement>> + 'a> {
  box RepParser{
    parser: box MapParser{
      parser: box DualParser {
        first: or!(output(), assign()),
        second: literal(NewLine),
      },
      mapper: box |&: (stmt, nl): (Statement, Token)| stmt
    }
  }
}

fn variable<'a>() -> LParser<'a> {
  box MatchParser{
    matcher: box |&: input: &Token| match input {
      &Ident(ref str) => Ok(Variable(str.clone())),
      other => Err(format!("Expected variable, got {}", other))
    }
  }
}

fn expr<'a>() -> LParser<'a> {

  fn match_num<'a>() -> Box<Parser<'a, &'a[Token], Expr> + 'a> {
    box MatchParser{matcher: box |&: input: &Token| -> Result<Expr, String> match input {
      &Number(num) => Ok(Num(num)),
      other => Err(format!("wrong type, expected number, got {}", other))
    }}
  }

  fn term<'a>() -> LParser<'a> {
    box OrParser{
      a: box |&:| paren_expr(),
      b: box |&:| box OrParser {
        a: box |&:| variable(),
        b: box |&:| match_num(),
      } as LParser<'a>
    }
  }

  fn mult<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: term(),
        sep: literal(MultSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Mult(ops)
    }
  }

  //nope - need way of encoding x * y / z * w, maybe Vec<(term, op)> where op is * or /
  fn divide<'a>() -> LParser<'a> {
    map!(repsep!(term(), literal(DivideSign)), |&: ops: Vec<Expr>| Divide(ops))
  }

  fn simple_expr<'a>() -> LParser<'a> {
    box OrParser{
      b: box |&:| term(),
      a: box |&:| mult()
    }
  }

  fn plus<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: simple_expr(),
        sep: literal(PlusSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Plus(ops)
    }
  }

  fn paren_expr<'a>() -> LParser<'a> {
    box MapParser {
      parser: box DualParser {
        first: box DualParser {
          first: literal(OpenParen),
          second: expr(),
        },
        second: literal(CloseParen),
      },
      mapper: box |&: ((o, e), c): ((Token, Expr), Token)| e
    }
  }

  let expr = box OrParser{
      a: box |&:| plus(),
      b: box |&:| simple_expr(),
  };

  expr
}
<commit_msg>cleaning up macros<commit_after>#![feature(macro_rules)]

use parsers::*;
use regex::{Captures, Regex};

/*
pub enum AddOp {
  Add,
  Subtract,
}

pub enum MultOp {
  Multiply,
  Divide,
}
*/

//type AddTerm = (AddOp, Expr);
//type MultTerm = (MultOp, Expr);

#[deriving(Show)]
pub enum Expr {
  Variable(String),
  Num(int),
  Plus(Vec<Expr>),
  //Minus(Vec<Expr>),
  Mult(Vec<Expr>),
  //Divide(Vec<Expr>),
  //AddSub(Vec<AddTerm>), //a + b - c + d becomes [(+ a) (+ b) (- c) (+ d)]
  //MultDiv(Vec<MultTerm>),
}

pub enum Statement {
  Assign(String, Expr),
  Output(Expr),
}

#[deriving(Show)]
#[deriving(Eq)]
#[deriving(PartialEq)]
#[deriving(Clone)]
pub enum Token {
  Equals,
  Ident(String),
  Number(int),
  PlusSign,
  MinusSign,
  MultSign,
  DivideSign,
  OutputCmd,
  NewLine,
  OpenParen,
  CloseParen,
}

pub macro_rules! or {
  ($a: expr, $b: expr ) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| $b,
    }
  };
  ($a: expr, $b: expr $(, $c: expr)*) => {
    box OrParser{
      a: box |&:| $a,
      b: box |&:| or!($b, $($c),*),
    }
  }
}

pub macro_rules! seq {
  ($a: expr, $b: expr ) => {
    box DualParser{
      a: $a,
      b: $b,
    }
  };
  ($a: expr, $b: expr $(, $c: expr)*) => {
    box DualParser{
      a: $a,
      b: seq!($b, $($c),*),
    }
  }
}

pub macro_rules! map {
  ($a: expr, $b: expr) => {
    box MapParser{
      parser: $a,
      mapper: box $b
    }
  }
}

pub macro_rules! link {
  ($a: expr, $b: expr) => {
    box DualParser{
      first: $a,
      second: $b,
    }
  }
}

pub macro_rules! repsep {
  ($rep: expr, $sep: expr, $min: expr) => {
    box RepSepParser{
      rep: $rep,
      sep: $sep,
      min_reps: $min,
    }
  }
}

type Lexer<'a> = Box<Parser<'a, &'a str, Token> + 'a>;

pub fn token<'a>() -> Box<Parser<'a, &'a str, Vec<Token>> + 'a> {

  macro_rules! literal{
    ($reg: expr, $lit: expr ) => {map!(
      box RegexLiteralParser{regex : Regex::new($reg).unwrap()},
      |&: ()| $lit
    ) as Lexer<'a>}
  }

  macro_rules! lor{
    ($a: expr, $b: expr) => (or!($a,$b) as Lexer<'a>)
  }

  fn ident<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*([a-z]+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Ident(from_str(caps.at(1)).unwrap())
  )}

  fn number<'a>() -> Lexer<'a> { map!(
    box RegexCapturesParser{regex : Regex::new(r"^[ \t]*(\d+)[ \t]*").unwrap()},
    |&: caps: Captures<'a>| Number(from_str(caps.at(1)).unwrap())
  )}

  box RepParser{
    parser: lor!(
      literal!(r"^[ \t]*out", OutputCmd),
      lor!(
      literal!(r"^[ \t]*\r?\n[ \t]*", NewLine),
      lor!(
      literal!(r"^[ \t]*\(", OpenParen),
      lor!(
      literal!(r"^[ \t]*\)", CloseParen),
      lor!(
      number(),
      lor!(
      literal!(r"^[ \t]*\+", PlusSign),
      lor!(
      literal!(r"^[ \t]*=", Equals),
      lor!(
      ident(),
      literal!(r"^[ \t]*\*", MultSign)
      ))))))))
  }

}

type LParser<'a> = Box<Parser<'a, &'a [Token], Expr> + 'a>;

fn assign<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser: box DualParser {
      first: box DualParser {
        first: variable(),
        second: literal(Equals),
      },
      second: expr()
    },
    mapper: box |&: ((var, eq), expr): ((Expr, Token), Expr)| -> Statement match var{
      Variable(name) => Assign(name, expr),
      _ => panic!("FUCK")
    }
  }
}

fn output<'a>() -> Box<Parser<'a, &'a [Token], Statement> + 'a> {
  box MapParser {
    parser : box DualParser {
      first: literal(OutputCmd),
      second: expr(),
    },
    mapper: box |&: (out, var): (Token, Expr)| Output(var)
  }
}

pub fn statement<'a>() -> Box<Parser<'a, &'a [Token], Vec<Statement>> + 'a> {
  box RepParser{
    parser: box MapParser{
      parser: box DualParser {
        first: or!(output(), assign()),
        second: literal(NewLine),
      },
      mapper: box |&: (stmt, nl): (Statement, Token)| stmt
    }
  }
}

fn variable<'a>() -> LParser<'a> {
  box MatchParser{
    matcher: box |&: input: &Token| match input {
      &Ident(ref str) => Ok(Variable(str.clone())),
      other => Err(format!("Expected variable, got {}", other))
    }
  }
}

fn expr<'a>() -> LParser<'a> {

  fn match_num<'a>() -> Box<Parser<'a, &'a[Token], Expr> + 'a> {
    box MatchParser{matcher: box |&: input: &Token| -> Result<Expr, String> match input {
      &Number(num) => Ok(Num(num)),
      other => Err(format!("wrong type, expected number, got {}", other))
    }}
  }

  fn term<'a>() -> LParser<'a> {
    box OrParser{
      a: box |&:| paren_expr(),
      b: box |&:| box OrParser {
        a: box |&:| variable(),
        b: box |&:| match_num(),
      } as LParser<'a>
    }
  }

  fn mult<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: term(),
        sep: literal(MultSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Mult(ops)
    }
  }

  fn simple_expr<'a>() -> LParser<'a> {
    box OrParser{
      b: box |&:| term(),
      a: box |&:| mult()
    }
  }

  fn plus<'a>() -> LParser<'a> {
    box MapParser{
      parser: box RepSepParser{
        rep: simple_expr(),
        sep: literal(PlusSign),
        min_reps : 2
      },
      mapper: box |&: ops: Vec<Expr>| Plus(ops)
    }
  }

  fn paren_expr<'a>() -> LParser<'a> {
    box MapParser {
      parser: box DualParser {
        first: box DualParser {
          first: literal(OpenParen),
          second: expr(),
        },
        second: literal(CloseParen),
      },
      mapper: box |&: ((o, e), c): ((Token, Expr), Token)| e
    }
  }

  let expr = box OrParser{
      a: box |&:| plus(),
      b: box |&:| simple_expr(),
  };

  expr
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::sync::Arc;
use std::sync::mpsc::{channel, sync_channel};
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::net::TcpStream;
use irc::stream::{IrcConnector, RegisterReqBuilder};

use url::{
    Url, SchemeType, Host,
    ParseResult, UrlParser
};

use irc::{BundlerManager, JoinBundlerTrigger};
use irc::parse::IrcMsg;
use irc::message_types::{client, server};

use command_mapper::PluginContainer;

use plugins::{
    DeerPlugin,
    GreedPlugin,
    SeenPlugin,
    RadioPlugin,
    PingPlugin,
    WserverPlugin,
    WhoAmIPlugin,
    LoggerPlugin,
};

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct BotConfig {
    pub server: String,
    pub command_prefixes: Vec<String>,
    pub nickname: String,
    pub channels: Vec<String>,
    pub enabled_plugins: HashSet<String>,
}

pub fn irc_scheme_type_mapper(scheme: &str) -> SchemeType {
    match scheme {
        "irc" => SchemeType::Relative(6667),
        "ircs" => SchemeType::Relative(6697),
        _ => SchemeType::NonRelative,
    }
}

impl BotConfig {
    fn get_url(&self) -> ParseResult<Url> {
        let mut parser = UrlParser::new();
        parser.scheme_type_mapper(irc_scheme_type_mapper);
        parser.parse(self.server.as_slice())
    }

    fn get_host(&self) -> String {
        let server = self.get_url().unwrap();
        match server.host() {
            Some(&Host::Domain(ref string)) => string.clone(),
            Some(&Host::Ipv6(ref addr)) => addr.serialize(),
            None => panic!()
        }
    }

    fn get_port(&self) -> u16 {
        let server = self.get_url().unwrap();
        server.port().unwrap_or(6667)
    }
}

pub struct BotConnection {
    foo: usize
    //
}

impl BotConnection {
    pub fn new(conf: &BotConfig) -> io::Result<BotConnection> {
        let (tx, rx) = sync_channel::<IrcMsg>(100);
        let (event_queue_txu, event_queue_rxu) = channel::<IrcMsg>();

        let conn = try!(TcpStream::connect(&(
            conf.get_host().as_slice(),
            conf.get_port()
        )));

        let mut reg_req = RegisterReqBuilder::new()
            .nick(&conf.nickname)
            .user("rustirc")
            .realname("https://github.com/infinityb/rust-irc-bot")
            .mode_invisible(true)
            .build().ok().unwrap();

        let mut connector = IrcConnector::from_pair(
            Box::new(BufReader::new(conn.try_clone().ok().unwrap())),
            Box::new(conn.try_clone().ok().unwrap()));

        let mut state;
        loop {
            match connector.register(&reg_req) {
                Ok(s) => {
                    state = s;
                    break
                },
                Err(err) => {
                    println!("Registration Error: {:?}", err);
                    reg_req.get_mut_nick().push_str("`");
                }
            }
        }
        let (mut reader, mut writer) = connector.split();

        let _ = ::std::thread::Builder::new().name("bot-reader".to_string()).spawn(move || {
            for msg in reader.iter() {
                let msg = match msg {
                    Ok(msg) => msg,
                    Err(err) => panic!("Error parsing message: {:?}", err),
                };
                if let Err(err) = event_queue_txu.send(msg) {
                    panic!("Error sending message: {:?}", err);
                }
            }
        });

        let mut bundler_man = BundlerManager::with_defaults();

        bundler_man.add_bundler_trigger(Box::new(
            JoinBundlerTrigger::new(state.get_self_nick().as_bytes())));

        for channel in conf.channels.iter() {
            info!("want join: {}", channel);
        }

        for channel in conf.channels.iter() {
            let join_msg = client::Join::new(channel.as_slice());
            writer.write_irc_msg(join_msg.to_irc_msg()).ok().unwrap();
        }

        let mut container = PluginContainer::new(conf.command_prefixes.clone());
        if conf.enabled_plugins.contains(PingPlugin::get_plugin_name()) {
            container.register(PingPlugin::new());
        }
        if conf.enabled_plugins.contains(GreedPlugin::get_plugin_name()) {
            container.register(GreedPlugin::new());
        }
        if conf.enabled_plugins.contains(SeenPlugin::get_plugin_name()) {
            container.register(SeenPlugin::new());
        }
        if conf.enabled_plugins.contains(DeerPlugin::get_plugin_name()) {
            container.register(DeerPlugin::new());
        }
        if conf.enabled_plugins.contains(RadioPlugin::get_plugin_name()) {
            container.register(RadioPlugin::new());
        }
        if conf.enabled_plugins.contains(WserverPlugin::get_plugin_name()) {
            container.register(WserverPlugin::new());
        }
        if conf.enabled_plugins.contains(WhoAmIPlugin::get_plugin_name()) {
            container.register(WhoAmIPlugin::new());
        }
        if conf.enabled_plugins.contains(LoggerPlugin::get_plugin_name()) {
            container.register(LoggerPlugin::new());
        }

        let _ = ::std::thread::Builder::new().name("bot-writer".to_string()).spawn(move || {
            for irc_msg in rx.iter() {
                println!("bot-sender::irc_msg = {:?}", irc_msg);
                writer.write_irc_msg(&irc_msg).ok().unwrap();
            }
        });

        for msg in event_queue_rxu.iter() {
            if let server::IncomingMsg::Ping(ping) = server::IncomingMsg::from_msg(msg.clone()) {
                if let Ok(pong) = ping.get_response() {
                    tx.send(pong.into_irc_msg()).ok().unwrap();
                }
            }

            if let Some(join) = state.is_self_join(&msg) {
                tx.send(client::Who::new(join.get_channel()).into_irc_msg()).ok().expect("send fail");
            }
            for event in bundler_man.on_irc_msg(&msg).into_iter() {
                state.on_event(&event);
                println!("emit-event {:?} => state = {:?}", event, state);
            }
            container.dispatch(Arc::new(state.clone_frozen()), &tx, &msg);
        }
        println!("Finished popping from event_queue_rxu");

        Ok(BotConnection { foo: 0 })
    }
}
<commit_msg>Join auto-join channels on invite<commit_after>use std::collections::HashSet;
use std::sync::Arc;
use std::sync::mpsc::{channel, sync_channel};
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::net::TcpStream;
use irc::stream::{IrcConnector, RegisterReqBuilder};

use url::{
    Url, SchemeType, Host,
    ParseResult, UrlParser
};

use irc::{BundlerManager, JoinBundlerTrigger};
use irc::parse::IrcMsg;
use irc::message_types::{client, server};

use command_mapper::PluginContainer;

use plugins::{
    DeerPlugin,
    GreedPlugin,
    SeenPlugin,
    RadioPlugin,
    PingPlugin,
    WserverPlugin,
    WhoAmIPlugin,
    LoggerPlugin,
};

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct BotConfig {
    pub server: String,
    pub command_prefixes: Vec<String>,
    pub nickname: String,
    pub channels: Vec<String>,
    pub enabled_plugins: HashSet<String>,
}

pub fn irc_scheme_type_mapper(scheme: &str) -> SchemeType {
    match scheme {
        "irc" => SchemeType::Relative(6667),
        "ircs" => SchemeType::Relative(6697),
        _ => SchemeType::NonRelative,
    }
}

impl BotConfig {
    fn get_url(&self) -> ParseResult<Url> {
        let mut parser = UrlParser::new();
        parser.scheme_type_mapper(irc_scheme_type_mapper);
        parser.parse(self.server.as_slice())
    }

    fn get_host(&self) -> String {
        let server = self.get_url().unwrap();
        match server.host() {
            Some(&Host::Domain(ref string)) => string.clone(),
            Some(&Host::Ipv6(ref addr)) => addr.serialize(),
            None => panic!()
        }
    }

    fn get_port(&self) -> u16 {
        let server = self.get_url().unwrap();
        server.port().unwrap_or(6667)
    }
}

pub struct BotConnection {
    foo: usize
    //
}

impl BotConnection {
    pub fn new(conf: &BotConfig) -> io::Result<BotConnection> {
        let (tx, rx) = sync_channel::<IrcMsg>(100);
        let (event_queue_txu, event_queue_rxu) = channel::<IrcMsg>();

        let conn = try!(TcpStream::connect(&(
            conf.get_host().as_slice(),
            conf.get_port()
        )));

        let mut reg_req = RegisterReqBuilder::new()
            .nick(&conf.nickname)
            .user("rustirc")
            .realname("https://github.com/infinityb/rust-irc-bot")
            .mode_invisible(true)
            .build().ok().unwrap();

        let mut connector = IrcConnector::from_pair(
            Box::new(BufReader::new(conn.try_clone().ok().unwrap())),
            Box::new(conn.try_clone().ok().unwrap()));

        let mut state;
        loop {
            match connector.register(&reg_req) {
                Ok(s) => {
                    state = s;
                    break
                },
                Err(err) => {
                    println!("Registration Error: {:?}", err);
                    reg_req.get_mut_nick().push_str("`");
                }
            }
        }
        let (mut reader, mut writer) = connector.split();

        let _ = ::std::thread::Builder::new().name("bot-reader".to_string()).spawn(move || {
            for msg in reader.iter() {
                let msg = match msg {
                    Ok(msg) => msg,
                    Err(err) => panic!("Error parsing message: {:?}", err),
                };
                if let Err(err) = event_queue_txu.send(msg) {
                    panic!("Error sending message: {:?}", err);
                }
            }
        });

        let mut bundler_man = BundlerManager::with_defaults();

        bundler_man.add_bundler_trigger(Box::new(
            JoinBundlerTrigger::new(state.get_self_nick().as_bytes())));

        for channel in conf.channels.iter() {
            info!("want join: {}", channel);
        }

        for channel in conf.channels.iter() {
            let join_msg = client::Join::new(channel.as_slice());
            writer.write_irc_msg(join_msg.to_irc_msg()).ok().unwrap();
        }

        let mut container = PluginContainer::new(conf.command_prefixes.clone());
        if conf.enabled_plugins.contains(PingPlugin::get_plugin_name()) {
            container.register(PingPlugin::new());
        }
        if conf.enabled_plugins.contains(GreedPlugin::get_plugin_name()) {
            container.register(GreedPlugin::new());
        }
        if conf.enabled_plugins.contains(SeenPlugin::get_plugin_name()) {
            container.register(SeenPlugin::new());
        }
        if conf.enabled_plugins.contains(DeerPlugin::get_plugin_name()) {
            container.register(DeerPlugin::new());
        }
        if conf.enabled_plugins.contains(RadioPlugin::get_plugin_name()) {
            container.register(RadioPlugin::new());
        }
        if conf.enabled_plugins.contains(WserverPlugin::get_plugin_name()) {
            container.register(WserverPlugin::new());
        }
        if conf.enabled_plugins.contains(WhoAmIPlugin::get_plugin_name()) {
            container.register(WhoAmIPlugin::new());
        }
        if conf.enabled_plugins.contains(LoggerPlugin::get_plugin_name()) {
            container.register(LoggerPlugin::new());
        }

        let _ = ::std::thread::Builder::new().name("bot-writer".to_string()).spawn(move || {
            for irc_msg in rx.iter() {
                println!("bot-sender::irc_msg = {:?}", irc_msg);
                writer.write_irc_msg(&irc_msg).ok().unwrap();
            }
        });

        let autojoin_invited: HashSet<String> = conf.channels.iter().cloned().collect();

        for msg in event_queue_rxu.iter() {
            if let server::IncomingMsg::Ping(ping) = server::IncomingMsg::from_msg(msg.clone()) {
                if let Ok(pong) = ping.get_response() {
                    tx.send(pong.into_irc_msg()).ok().unwrap();
                }
            }

            if let server::IncomingMsg::Invite(invite) = server::IncomingMsg::from_msg(msg.clone()) {
                if autojoin_invited.contains(invite.get_target()) {
                    let join_msg = client::Join::new(invite.get_target());
                    tx.send(join_msg.into_irc_msg()).ok().unwrap();
                }
            }

            if let Some(join) = state.is_self_join(&msg) {
                tx.send(client::Who::new(join.get_channel()).into_irc_msg()).ok().expect("send fail");
            }
            for event in bundler_man.on_irc_msg(&msg).into_iter() {
                state.on_event(&event);
                println!("emit-event {:?} => state = {:?}", event, state);
            }
            container.dispatch(Arc::new(state.clone_frozen()), &tx, &msg);
        }
        println!("Finished popping from event_queue_rxu");

        Ok(BotConnection { foo: 0 })
    }
}
<|endoftext|>