<commit_before>//! The filter implementation
//!

pub use ops::and::And;
pub use ops::not::Not;
pub use ops::or::Or;

/// Trait for converting something into a Filter
pub trait IntoFilter<N> {
    type IntoFilt: Filter<N>;

    fn into_filter(self) -> Self::IntoFilt;
}

/// All Filters can be turned into Filters
impl<N, I: Filter<N>> IntoFilter<N> for I {
    type IntoFilt = I;

    fn into_filter(self) -> I {
        self
    }
}

/// All closures that take a ref to something and return bool are filters
impl<I, T: Fn(&I) -> bool> Filter<I> for T {
    fn filter(&self, other: &I) -> bool {
        self(other)
    }
}

/// The filter trai
pub trait Filter<N> {

    /// The function which is used to filter something
    fn filter(&self, &N) -> bool;

    /// Helper to invert a filter.
    ///
    /// ```ignore
    /// (|&a: &usize| { a == 1 }).not() == (|&a: &usize| { a != 1 })
    /// ```
    fn not(self) -> Not<Self>
        where Self: Sized
    {
        Not::new(self)
    }

    /// Helper to connect two filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or(b) == (|&a: &usize| { a == 1 || a == 2 })
    /// ```
    fn or<F>(self, other: F) -> Or<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        Or::new(self, other.into_filter())
    }

    /// Helper to connect two filters via logical OR and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or_not(b) == (|&a: &usize| { a == 1 || !(a == 2) })
    /// ```
    fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
    {
        self.or(Not::new(other.into_filter()))
    }

    /// Helper to connect three filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.or3(b, c) == (|&a: &usize| { a == 1 || a == 2 || a == 3 })
    /// ```
    fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        Or::new(self, Or::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and(b) == (|&a: &usize| { a == 1 && a == 2 })
    /// ```
    fn and<F>(self, other: F) -> And<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        And::new(self, other.into_filter())
    }

    /// Helper to connect three filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.and3(b, c) == (|&a: &usize| { a == 1 && a == 2 && a == 3 })
    /// ```
    fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        And::new(self, And::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical AND and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and_not(b) == (|&a: &usize| { a == 1 && !(a == 2) })
    /// ```
    fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        self.and(Not::new(other.into_filter()))
    }

    /// Helper to connect two filters via logical NAND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nand(b) == (|&a: &usize| { !(a == 1 && a == 2) })
    /// ```
    fn nand<F>(self, other: F) -> Not<And<Self, F>>
        where Self: Sized,
    {
        Not::new(And::new(self, other))
    }

}

#[cfg(test)]
mod test {
    use filter::Filter;
    use ops::and::And;

    #[test]
    fn closures() {
        let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);

        assert_eq!(a.filter(&2), true);
    }

    #[test]
    fn and_filter() {
        let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3);

        assert_eq!(a.filter(&3),  true);
        assert_eq!(a.filter(&5),  false);
        assert_eq!(a.filter(&0), false);
    }

    #[test]
    fn complex_filter() {
        let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20) ) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_closured() {
        let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_named_closures() {
        let not_eq_to_one   = |&a: &usize| { a != 1 };
        let not_eq_to_two   = |&a: &usize| { a != 2 };
        let not_eq_to_three = |&a: &usize| { a != 3 };

        let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&1), false);
        assert_eq!(a.filter(&3), false);
    }

    struct EqTo {
        pub i: usize,
    }

    impl Filter<usize> for EqTo {
        fn filter(&self, n: &usize) -> bool {
            self.i == *n
        }
    }

    #[test]
    fn filter_with_eqto() {
        let eq = EqTo { i: 0 };
        assert_eq!(eq.filter(&0),  true);
        assert_eq!(eq.filter(&1),  false);
        assert_eq!(eq.filter(&17), false);
        assert_eq!(eq.filter(&42), false);
    }

    #[test]
    fn filter_with_combined_eqto() {
        let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 });

        assert_eq!(aeq.filter(&0),  true);
        assert_eq!(aeq.filter(&1),  false);
        assert_eq!(aeq.filter(&2),  true);
        assert_eq!(aeq.filter(&17), false);
    }

    #[test]
    fn filter_iterator() {
        let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

        let inrange        = (|&a: &usize| { a > 5 }).and(|&a: &usize| { a < 15 });

        let r : Vec<usize> = v.into_iter().filter(|x| inrange.filter(x)).collect();

        assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
    }
}
<commit_msg>Add Filter::nor()<commit_after>//! The filter implementation
//!

pub use ops::and::And;
pub use ops::not::Not;
pub use ops::or::Or;

/// Trait for converting something into a Filter
pub trait IntoFilter<N> {
    type IntoFilt: Filter<N>;

    fn into_filter(self) -> Self::IntoFilt;
}

/// All Filters can be turned into Filters
impl<N, I: Filter<N>> IntoFilter<N> for I {
    type IntoFilt = I;

    fn into_filter(self) -> I {
        self
    }
}

/// All closures that take a ref to something and return bool are filters
impl<I, T: Fn(&I) -> bool> Filter<I> for T {
    fn filter(&self, other: &I) -> bool {
        self(other)
    }
}

/// The filter trai
pub trait Filter<N> {

    /// The function which is used to filter something
    fn filter(&self, &N) -> bool;

    /// Helper to invert a filter.
    ///
    /// ```ignore
    /// (|&a: &usize| { a == 1 }).not() == (|&a: &usize| { a != 1 })
    /// ```
    fn not(self) -> Not<Self>
        where Self: Sized
    {
        Not::new(self)
    }

    /// Helper to connect two filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or(b) == (|&a: &usize| { a == 1 || a == 2 })
    /// ```
    fn or<F>(self, other: F) -> Or<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        Or::new(self, other.into_filter())
    }

    /// Helper to connect two filters via logical OR and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or_not(b) == (|&a: &usize| { a == 1 || !(a == 2) })
    /// ```
    fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
    {
        self.or(Not::new(other.into_filter()))
    }

    /// Helper to connect three filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.or3(b, c) == (|&a: &usize| { a == 1 || a == 2 || a == 3 })
    /// ```
    fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        Or::new(self, Or::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical NOR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nor(b) == (|&a: &usize| { !(a == 1 || a == 2) })
    /// ```
    fn nor<F>(self, other: F) -> Not<Or<Self, F>>
        where Self: Sized,
    {
        Not::new(Or::new(self, other))
    }

    /// Helper to connect two filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and(b) == (|&a: &usize| { a == 1 && a == 2 })
    /// ```
    fn and<F>(self, other: F) -> And<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        And::new(self, other.into_filter())
    }

    /// Helper to connect three filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.and3(b, c) == (|&a: &usize| { a == 1 && a == 2 && a == 3 })
    /// ```
    fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        And::new(self, And::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical AND and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and_not(b) == (|&a: &usize| { a == 1 && !(a == 2) })
    /// ```
    fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        self.and(Not::new(other.into_filter()))
    }

    /// Helper to connect two filters via logical NAND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nand(b) == (|&a: &usize| { !(a == 1 && a == 2) })
    /// ```
    fn nand<F>(self, other: F) -> Not<And<Self, F>>
        where Self: Sized,
    {
        Not::new(And::new(self, other))
    }

}

#[cfg(test)]
mod test {
    use filter::Filter;
    use ops::and::And;

    #[test]
    fn closures() {
        let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);

        assert_eq!(a.filter(&2), true);
    }

    #[test]
    fn and_filter() {
        let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3);

        assert_eq!(a.filter(&3),  true);
        assert_eq!(a.filter(&5),  false);
        assert_eq!(a.filter(&0), false);
    }

    #[test]
    fn complex_filter() {
        let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20) ) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_closured() {
        let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_named_closures() {
        let not_eq_to_one   = |&a: &usize| { a != 1 };
        let not_eq_to_two   = |&a: &usize| { a != 2 };
        let not_eq_to_three = |&a: &usize| { a != 3 };

        let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&1), false);
        assert_eq!(a.filter(&3), false);
    }

    struct EqTo {
        pub i: usize,
    }

    impl Filter<usize> for EqTo {
        fn filter(&self, n: &usize) -> bool {
            self.i == *n
        }
    }

    #[test]
    fn filter_with_eqto() {
        let eq = EqTo { i: 0 };
        assert_eq!(eq.filter(&0),  true);
        assert_eq!(eq.filter(&1),  false);
        assert_eq!(eq.filter(&17), false);
        assert_eq!(eq.filter(&42), false);
    }

    #[test]
    fn filter_with_combined_eqto() {
        let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 });

        assert_eq!(aeq.filter(&0),  true);
        assert_eq!(aeq.filter(&1),  false);
        assert_eq!(aeq.filter(&2),  true);
        assert_eq!(aeq.filter(&17), false);
    }

    #[test]
    fn filter_iterator() {
        let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

        let inrange        = (|&a: &usize| { a > 5 }).and(|&a: &usize| { a < 15 });

        let r : Vec<usize> = v.into_iter().filter(|x| inrange.filter(x)).collect();

        assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;

use constant::*;
use self::walkdir::{WalkDir, WalkDirIterator};
use std::collections::BTreeSet;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::Error as IoError;
use std::path::{Path, PathBuf};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),*) => {
        PathBuf::new()
            $(.join($x))*
    };
}

pub fn extract_file_name(full_path: &PathBuf) -> Option<&str> {
    full_path
        .file_name()
        .and_then(OsStr::to_str)
}

pub fn ls<P: AsRef<Path>>(path: &P) -> Result<BTreeSet<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .map(|d| d.file_name())
        .map(OsString::into_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>();
    Ok(dirs)
}

fn is_hidden(entry: &walkdir::DirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s.starts_with(".") && s.len() > 1 && s != "..")
}

fn is_pinned(entry: &walkdir::DirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s == WORKING_DIR_NAME || s == KEEPED_FILE_NAME)
}

fn is_target(entry: &walkdir::DirEntry) -> bool {
    !is_hidden(entry) && !is_pinned(entry)
}

fn to_string(entry: walkdir::DirEntry) -> Result<String, OsString> {
    entry
        .path()
        .as_os_str()
        .to_os_string()
        .into_string()
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<walkdir::DirEntry>>();

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>()
}

pub fn dirs_ordered_by_descending_depth<P: AsRef<Path>>(root: P) -> Vec<String> {
    let mut walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_entry(|e| e.file_type().is_dir())
        .filter_map(Result::ok)
        .collect::<Vec<walkdir::DirEntry>>();

    walker.sort_by(|l, r| {
        let l_depth = &l.depth();
        let r_depth = &r.depth();
        r_depth.cmp(l_depth)
    });

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<Vec<String>>()
}
<commit_msg>[Refactoring] Use alias "WalkDirEntry"<commit_after>extern crate walkdir;

use constant::*;
use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};
use std::collections::BTreeSet;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::Error as IoError;
use std::path::{Path, PathBuf};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),*) => {
        PathBuf::new()
            $(.join($x))*
    };
}

pub fn extract_file_name(full_path: &PathBuf) -> Option<&str> {
    full_path
        .file_name()
        .and_then(OsStr::to_str)
}

pub fn ls<P: AsRef<Path>>(path: &P) -> Result<BTreeSet<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .map(|d| d.file_name())
        .map(OsString::into_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>();
    Ok(dirs)
}

fn is_hidden(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s.starts_with(".") && s.len() > 1 && s != "..")
}

fn is_pinned(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s == WORKING_DIR_NAME || s == KEEPED_FILE_NAME)
}

fn is_target(entry: &WalkDirEntry) -> bool {
    !is_hidden(entry) && !is_pinned(entry)
}

fn to_string(entry: WalkDirEntry) -> Result<String, OsString> {
    entry
        .path()
        .as_os_str()
        .to_os_string()
        .into_string()
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>()
}

pub fn dirs_ordered_by_descending_depth<P: AsRef<Path>>(root: P) -> Vec<String> {
    let mut walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_entry(|e| e.file_type().is_dir())
        .filter_map(Result::ok)
        .collect::<Vec<WalkDirEntry>>();

    walker.sort_by(|l, r| {
        let l_depth = &l.depth();
        let r_depth = &r.depth();
        r_depth.cmp(l_depth)
    });

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<Vec<String>>()
}
<|endoftext|>


<commit_before>//! Aperture Macros.

use ::{GerberCode, GerberError, GerberResult};

#[derive(Debug)]
pub struct ApertureMacro {
    pub name: String,
}

#[derive(Debug)]
pub enum Primitive {
    Comment(String),
    Circle(CirclePrimitive),
    VectorLine(VectorLinePrimitive),
    CenterLine(CenterLinePrimitive),
    Outline(OutlinePrimitive),
    Polygon(PolygonPrimitive),
    Moire(MoirePrimitive),
}

impl GerberCode for Primitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = match *self {
            Primitive::Comment(ref s) => s.clone(),
            Primitive::Circle(ref c) => try!(c.to_code()),
            Primitive::VectorLine(ref vl) => try!(vl.to_code()),
            Primitive::CenterLine(ref cl) => try!(cl.to_code()),
            Primitive::Outline(ref o) => try!(o.to_code()),
            Primitive::Polygon(ref p) => try!(p.to_code()),
            Primitive::Moire(ref m) => try!(m.to_code()),
        };
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CirclePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Diameter, a decimal >= 0
    pub diameter: f64,

    /// X and Y coordinates of center position, decimals
    pub center: (f64, f64),

    /// Rotation angle.
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    ///
    /// The rotation modifier is optional. The default is no rotation. (We
    /// recommend always to set the angle explicitly.
    pub angle: Option<f64>,
}

impl GerberCode for CirclePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let mut code = "1,".to_string();
        code.push_str(&try!(self.exposure.to_code()));
        code.push_str(&format!(",{},{},{}", self.diameter, self.center.0, self.center.1));
        if let Some(a) = self.angle {
            code.push_str(&format!(",{}", a));
        }
        code.push_str("*");
        Ok(code)
    }
}

#[derive(Debug)]
pub struct VectorLinePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Line width, a decimal >= 0
    pub width: f64,

    /// X and Y coordinates of start point, decimals
    pub start: (f64, f64),

    /// X and Y coordinates of end point, decimals
    pub end: (f64, f64),

    /// Rotation angle of the vector line primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    pub angle: f64,
}

impl GerberCode for VectorLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "20,{},{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.width,
            self.start.0, self.start.1, self.end.0, self.end.1,
            self.angle
        );
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CenterLinePrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Rectangle dimensions (width/height)
    pub dimensions: (f64, f64),

    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Rotation angle
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. (0, 0) point
    /// of macro coordinates.
    pub angle: f64,
}

impl GerberCode for CenterLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "21,{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.dimensions.0, self.dimensions.1,
            self.center.0, self.center.1,
            self.angle
        );
        Ok(code)
    }
}

#[derive(Debug)]
pub struct OutlinePrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Vector of coordinate pairs.
    ///
    /// The last coordinate pair must be equal to the first coordinate pair!
    pub points: Vec<(f64, f64)>,

    /// Rotation angle of the outline primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    pub angle: f64,
}

impl GerberCode for OutlinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Points invariants
        if self.points.len() < 2 {
            return Err(GerberError::RangeError("There must be at least 1 subsequent point in an outline".into()));
        }
        if self.points.len() > 5001 {
            return Err(GerberError::RangeError("The maximum number of subsequent points in an outline is 5000".into()));
        }
        if self.points[0] != self.points[self.points.len() - 1] {
            return Err(GerberError::RangeError("The maximum number of subsequent points n is 5000".into()));
        }

        let mut code = format!("4,{},{},\n", try!(self.exposure.to_code()), self.points.len() - 1);
        code.push_str(
            &self.points.iter()
                        .map(|&(x, y)| format!("{},{},", x, y))
                        .collect::<Vec<String>>()
                        .join("\n")
        );
        code.push_str(&format!("\n{}*", self.angle));
        Ok(code)
    }
}

#[derive(Debug)]
/// A polygon primitive is a regular polygon defined by the number of vertices,
/// the center point and the diameter of the circumscribed circle.
pub struct PolygonPrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Number of vertices n, 3 <= n <= 12
    pub vertices: u8,

    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Diameter of the circumscribed circle, a decimal >= 0
    pub diameter: f64,

    /// Rotation angle of the polygon primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates. The first vertex is on the positive X-axis
    /// through the center point when the rotation angle is zero.
    ///
    /// Note: Rotation is only allowed if the primitive center point coincides
    /// with the origin of the macro definition.
    pub angle: f64,
}

impl GerberCode for PolygonPrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Vertice count invariants
        if self.vertices < 3 {
            return Err(GerberError::RangeError("There must be at least 3 vertices in a polygon".into()));
        }
        if self.vertices > 12 {
            return Err(GerberError::RangeError("The maximum number of vertices in a polygon is 12".into()));
        }
        if self.diameter < 0.0 {
            return Err(GerberError::RangeError("The diameter must not be negative".into()));
        }
        let code = format!(
            "5,{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.vertices,
            self.center.0, self.center.1,
            self.diameter,
            self.angle
        );
        Ok(code)
    }
}

/// The moiré primitive is a cross hair centered on concentric rings (annuli).
/// Exposure is always on.
#[derive(Debug)]
pub struct MoirePrimitive {
    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Outer diameter of outer concentric ring, a decimal >= 0
    pub diameter: f64,

    /// Ring thickness, a decimal >= 0
    pub ring_thickness: f64,

    /// Gap between rings, a decimal >= 0
    pub gap: f64,

    /// Maximum number of rings
    pub max_rings: u32,

    /// Cross hair thickness, a decimal >= 0
    pub cross_hair_thickness: f64,

    /// Cross hair length, a decimal >= 0
    pub cross_hair_length: f64,

    /// Rotation angle of the moiré primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    ///
    /// Note: Rotation is only allowed if the primitive center point coincides
    /// with the origin of the macro definition.
    pub angle: f64,
}

impl GerberCode for MoirePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Decimal invariants
        if self.diameter < 0.0 {
            return Err(GerberError::RangeError("Outer diameter of a moiré may not be negative".into()));
        }
        if self.ring_thickness < 0.0 {
            return Err(GerberError::RangeError("Ring thickness of a moiré may not be negative".into()));
        }
        if self.gap < 0.0 {
            return Err(GerberError::RangeError("Gap of a moiré may not be negative".into()));
        }
        if self.cross_hair_thickness < 0.0 {
            return Err(GerberError::RangeError("Cross hair thickness of a moiré may not be negative".into()));
        }
        if self.cross_hair_length < 0.0 {
            return Err(GerberError::RangeError("Cross hair length of a moiré may not be negative".into()));
        }
        let code = format!(
            "6,{},{},{},{},{},{},{},{},{}*",
            self.center.0, self.center.1,
            self.diameter,
            self.ring_thickness,
            self.gap,
            self.max_rings,
            self.cross_hair_thickness, self.cross_hair_length,
            self.angle
        );
        Ok(code)
    }
}

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

    #[test]
    fn test_circle_primitive_codegen() {
        let with_angle = CirclePrimitive {
            exposure: true,
            diameter: 1.5,
            center: (0., 0.),
            angle: Some(0.),
        };
        assert_eq!(with_angle.to_code().unwrap(), "1,1,1.5,0,0,0*".to_string());
        let no_angle = CirclePrimitive {
            exposure: false,
            diameter: 99.9,
            center: (1.1, 2.2),
            angle: None,
        };
        assert_eq!(no_angle.to_code().unwrap(), "1,0,99.9,1.1,2.2*".to_string());
    }

    #[test]
    fn test_vector_line_primitive_codegen() {
        let line = VectorLinePrimitive {
            exposure: true,
            width: 0.9,
            start: (0., 0.45),
            end: (12., 0.45),
            angle: 0.,
        };
        assert_eq!(line.to_code().unwrap(), "20,1,0.9,0,0.45,12,0.45,0*".to_string());
    }

    #[test]
    fn test_center_line_primitive_codegen() {
        let line = CenterLinePrimitive {
            exposure: true,
            dimensions: (6.8, 1.2),
            center: (3.4, 0.6),
            angle: 30.0,
        };
        assert_eq!(line.to_code().unwrap(), "21,1,6.8,1.2,3.4,0.6,30*".to_string());
    }

    #[test]
    fn test_outline_primitive_codegen() {
        let line = OutlinePrimitive {
            exposure: true,
            points: vec![
                (0.1, 0.1),
                (0.5, 0.1),
                (0.5, 0.5),
                (0.1, 0.5),
                (0.1, 0.1),
            ],
            angle: 0.0,
        };
        assert_eq!(line.to_code().unwrap(), "4,1,4,\n0.1,0.1,\n0.5,0.1,\n0.5,0.5,\n0.1,0.5,\n0.1,0.1,\n0*".to_string());
    }

    #[test]
    fn test_polygon_primitive_codegen() {
        let line = PolygonPrimitive {
            exposure: true,
            vertices: 8,
            center: (1.5, 2.0),
            diameter: 8.0,
            angle: 0.0,
        };
        assert_eq!(line.to_code().unwrap(), "5,1,8,1.5,2,8,0*".to_string());
    }

    #[test]
    fn test_moire_primitive_codegen() {
        let line = MoirePrimitive {
            center: (0.0, 0.0),
            diameter: 5.0,
            ring_thickness: 0.5,
            gap: 0.5,
            max_rings: 2,
            cross_hair_thickness: 0.1,
            cross_hair_length: 6.0,
            angle: 0.0,
        };
        assert_eq!(line.to_code().unwrap(), "6,0,0,5,0.5,0.5,2,0.1,6,0*".to_string());
    }
}
<commit_msg>Add ThermalPrimitive<commit_after>//! Aperture Macros.

use ::{GerberCode, GerberError, GerberResult};

#[derive(Debug)]
pub struct ApertureMacro {
    pub name: String,
}

#[derive(Debug)]
pub enum Primitive {
    Comment(String),
    Circle(CirclePrimitive),
    VectorLine(VectorLinePrimitive),
    CenterLine(CenterLinePrimitive),
    Outline(OutlinePrimitive),
    Polygon(PolygonPrimitive),
    Moire(MoirePrimitive),
    Thermal(ThermalPrimitive),
}

impl GerberCode for Primitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = match *self {
            Primitive::Comment(ref s) => s.clone(),
            Primitive::Circle(ref c) => try!(c.to_code()),
            Primitive::VectorLine(ref vl) => try!(vl.to_code()),
            Primitive::CenterLine(ref cl) => try!(cl.to_code()),
            Primitive::Outline(ref o) => try!(o.to_code()),
            Primitive::Polygon(ref p) => try!(p.to_code()),
            Primitive::Moire(ref m) => try!(m.to_code()),
            Primitive::Thermal(ref t) => try!(t.to_code()),
        };
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CirclePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Diameter, a decimal >= 0
    pub diameter: f64,

    /// X and Y coordinates of center position, decimals
    pub center: (f64, f64),

    /// Rotation angle.
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    ///
    /// The rotation modifier is optional. The default is no rotation. (We
    /// recommend always to set the angle explicitly.
    pub angle: Option<f64>,
}

impl GerberCode for CirclePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let mut code = "1,".to_string();
        code.push_str(&try!(self.exposure.to_code()));
        code.push_str(&format!(",{},{},{}", self.diameter, self.center.0, self.center.1));
        if let Some(a) = self.angle {
            code.push_str(&format!(",{}", a));
        }
        code.push_str("*");
        Ok(code)
    }
}

#[derive(Debug)]
pub struct VectorLinePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Line width, a decimal >= 0
    pub width: f64,

    /// X and Y coordinates of start point, decimals
    pub start: (f64, f64),

    /// X and Y coordinates of end point, decimals
    pub end: (f64, f64),

    /// Rotation angle of the vector line primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    pub angle: f64,
}

impl GerberCode for VectorLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "20,{},{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.width,
            self.start.0, self.start.1, self.end.0, self.end.1,
            self.angle
        );
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CenterLinePrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Rectangle dimensions (width/height)
    pub dimensions: (f64, f64),

    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Rotation angle
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. (0, 0) point
    /// of macro coordinates.
    pub angle: f64,
}

impl GerberCode for CenterLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "21,{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.dimensions.0, self.dimensions.1,
            self.center.0, self.center.1,
            self.angle
        );
        Ok(code)
    }
}

#[derive(Debug)]
pub struct OutlinePrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Vector of coordinate pairs.
    ///
    /// The last coordinate pair must be equal to the first coordinate pair!
    pub points: Vec<(f64, f64)>,

    /// Rotation angle of the outline primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    pub angle: f64,
}

impl GerberCode for OutlinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Points invariants
        if self.points.len() < 2 {
            return Err(GerberError::RangeError("There must be at least 1 subsequent point in an outline".into()));
        }
        if self.points.len() > 5001 {
            return Err(GerberError::RangeError("The maximum number of subsequent points in an outline is 5000".into()));
        }
        if self.points[0] != self.points[self.points.len() - 1] {
            return Err(GerberError::RangeError("The maximum number of subsequent points n is 5000".into()));
        }

        let mut code = format!("4,{},{},\n", try!(self.exposure.to_code()), self.points.len() - 1);
        code.push_str(
            &self.points.iter()
                        .map(|&(x, y)| format!("{},{},", x, y))
                        .collect::<Vec<String>>()
                        .join("\n")
        );
        code.push_str(&format!("\n{}*", self.angle));
        Ok(code)
    }
}

#[derive(Debug)]
/// A polygon primitive is a regular polygon defined by the number of vertices,
/// the center point and the diameter of the circumscribed circle.
pub struct PolygonPrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Number of vertices n, 3 <= n <= 12
    pub vertices: u8,

    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Diameter of the circumscribed circle, a decimal >= 0
    pub diameter: f64,

    /// Rotation angle of the polygon primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates. The first vertex is on the positive X-axis
    /// through the center point when the rotation angle is zero.
    ///
    /// Note: Rotation is only allowed if the primitive center point coincides
    /// with the origin of the macro definition.
    pub angle: f64,
}

impl GerberCode for PolygonPrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Vertice count invariants
        if self.vertices < 3 {
            return Err(GerberError::RangeError("There must be at least 3 vertices in a polygon".into()));
        }
        if self.vertices > 12 {
            return Err(GerberError::RangeError("The maximum number of vertices in a polygon is 12".into()));
        }
        if self.diameter < 0.0 {
            return Err(GerberError::RangeError("The diameter must not be negative".into()));
        }
        let code = format!(
            "5,{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.vertices,
            self.center.0, self.center.1,
            self.diameter,
            self.angle
        );
        Ok(code)
    }
}

/// The moiré primitive is a cross hair centered on concentric rings (annuli).
/// Exposure is always on.
#[derive(Debug)]
pub struct MoirePrimitive {
    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Outer diameter of outer concentric ring, a decimal >= 0
    pub diameter: f64,

    /// Ring thickness, a decimal >= 0
    pub ring_thickness: f64,

    /// Gap between rings, a decimal >= 0
    pub gap: f64,

    /// Maximum number of rings
    pub max_rings: u32,

    /// Cross hair thickness, a decimal >= 0
    pub cross_hair_thickness: f64,

    /// Cross hair length, a decimal >= 0
    pub cross_hair_length: f64,

    /// Rotation angle of the moiré primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    ///
    /// Note: Rotation is only allowed if the primitive center point coincides
    /// with the origin of the macro definition.
    pub angle: f64,
}

impl GerberCode for MoirePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Decimal invariants
        if self.diameter < 0.0 {
            return Err(GerberError::RangeError("Outer diameter of a moiré may not be negative".into()));
        }
        if self.ring_thickness < 0.0 {
            return Err(GerberError::RangeError("Ring thickness of a moiré may not be negative".into()));
        }
        if self.gap < 0.0 {
            return Err(GerberError::RangeError("Gap of a moiré may not be negative".into()));
        }
        if self.cross_hair_thickness < 0.0 {
            return Err(GerberError::RangeError("Cross hair thickness of a moiré may not be negative".into()));
        }
        if self.cross_hair_length < 0.0 {
            return Err(GerberError::RangeError("Cross hair length of a moiré may not be negative".into()));
        }
        let code = format!(
            "6,{},{},{},{},{},{},{},{},{}*",
            self.center.0, self.center.1,
            self.diameter,
            self.ring_thickness,
            self.gap,
            self.max_rings,
            self.cross_hair_thickness, self.cross_hair_length,
            self.angle
        );
        Ok(code)
    }
}

/// The thermal primitive is a ring (annulus) interrupted by four gaps.
/// Exposure is always on.
#[derive(Debug)]
pub struct ThermalPrimitive {
    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Outer diameter, a decimal > inner diameter
    pub outer_diameter: f64,

    /// Inner diameter, a decimal >= 0
    pub inner_diameter: f64,

    /// Gap thickness, a decimal < (outer diameter) / sqrt(2)
    pub gap: f64,

    /// Rotation angle of the thermal primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates. The gaps are on the X and Y axes through
    /// the center when the rotation angle is zero
    ///
    /// Note: Rotation is only allowed if the primitive center point coincides
    /// with the origin of the macro definition.
    pub angle: f64,
}

impl GerberCode for ThermalPrimitive {
    fn to_code(&self) -> GerberResult<String> {
        // Decimal invariants
        if self.inner_diameter < 0.0 {
            return Err(GerberError::RangeError("Inner diameter of a thermal may not be negative".into()));
        }
        if self.outer_diameter <= self.inner_diameter {
            return Err(GerberError::RangeError("Outer diameter of a thermal must be larger than inner diameter".into()));
        }
        if self.gap > (self.outer_diameter / 2f64.sqrt()) {
            return Err(GerberError::RangeError("Gap of a thermal must be smaller than outer_diameter/sqrt(2)".into()));
        }
        let code = format!(
            "7,{},{},{},{},{},{}*",
            self.center.0, self.center.1,
            self.outer_diameter,
            self.inner_diameter,
            self.gap,
            self.angle
        );
        Ok(code)
    }
}

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

    #[test]
    fn test_circle_primitive_codegen() {
        let with_angle = CirclePrimitive {
            exposure: true,
            diameter: 1.5,
            center: (0., 0.),
            angle: Some(0.),
        };
        assert_eq!(with_angle.to_code().unwrap(), "1,1,1.5,0,0,0*".to_string());
        let no_angle = CirclePrimitive {
            exposure: false,
            diameter: 99.9,
            center: (1.1, 2.2),
            angle: None,
        };
        assert_eq!(no_angle.to_code().unwrap(), "1,0,99.9,1.1,2.2*".to_string());
    }

    #[test]
    fn test_vector_line_primitive_codegen() {
        let line = VectorLinePrimitive {
            exposure: true,
            width: 0.9,
            start: (0., 0.45),
            end: (12., 0.45),
            angle: 0.,
        };
        assert_eq!(line.to_code().unwrap(), "20,1,0.9,0,0.45,12,0.45,0*".to_string());
    }

    #[test]
    fn test_center_line_primitive_codegen() {
        let line = CenterLinePrimitive {
            exposure: true,
            dimensions: (6.8, 1.2),
            center: (3.4, 0.6),
            angle: 30.0,
        };
        assert_eq!(line.to_code().unwrap(), "21,1,6.8,1.2,3.4,0.6,30*".to_string());
    }

    #[test]
    fn test_outline_primitive_codegen() {
        let line = OutlinePrimitive {
            exposure: true,
            points: vec![
                (0.1, 0.1),
                (0.5, 0.1),
                (0.5, 0.5),
                (0.1, 0.5),
                (0.1, 0.1),
            ],
            angle: 0.0,
        };
        assert_eq!(line.to_code().unwrap(), "4,1,4,\n0.1,0.1,\n0.5,0.1,\n0.5,0.5,\n0.1,0.5,\n0.1,0.1,\n0*".to_string());
    }

    #[test]
    fn test_polygon_primitive_codegen() {
        let line = PolygonPrimitive {
            exposure: true,
            vertices: 8,
            center: (1.5, 2.0),
            diameter: 8.0,
            angle: 0.0,
        };
        assert_eq!(line.to_code().unwrap(), "5,1,8,1.5,2,8,0*".to_string());
    }

    #[test]
    fn test_moire_primitive_codegen() {
        let line = MoirePrimitive {
            center: (0.0, 0.0),
            diameter: 5.0,
            ring_thickness: 0.5,
            gap: 0.5,
            max_rings: 2,
            cross_hair_thickness: 0.1,
            cross_hair_length: 6.0,
            angle: 0.0,
        };
        assert_eq!(line.to_code().unwrap(), "6,0,0,5,0.5,0.5,2,0.1,6,0*".to_string());
    }

    #[test]
    fn test_thermal_primitive_codegen() {
        let line = ThermalPrimitive {
            center: (0.0, 0.0),
            outer_diameter: 8.0,
            inner_diameter: 6.5,
            gap: 1.0,
            angle: 45.0,
        };
        assert_eq!(line.to_code().unwrap(), "7,0,0,8,6.5,1,45*".to_string());
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

include!("../relm-state/src/macros.rs");
<commit_msg>Temporary fix to publish the crate<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/// Connect events to sending a message.
///
/// Rule #1:
/// Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// Rule #2:
/// Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// Rule #3:
/// Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// Rule #4:
/// Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// Rule #1:
/// Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// Rule #2:
/// Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}
<|endoftext|>


<commit_before>/// Create and populate a router.
///
/// ```ignore
/// let router = router!(index: get  "/"       => index,
///                      query: get  "/:query" => queryHandler,
///                      post:  post "/"       => postHandler);
/// ```
///
/// Is equivalent to:
///
/// ```ignore
/// let mut router = Router::new();
/// router.get("/", index, "index");
/// router.get("/:query", queryHandler, "query");
/// router.post("/", postHandler, "post");
/// ```
///
/// The method name must be lowercase, supported methods:
///
/// `get`, `post`, `put`, `delete`, `head`, `patch`, `options` and `any`.
#[macro_export]
macro_rules! router {
    ($($route_id:ident: $method:ident $glob:expr => $handler:expr),+ $(,)*) => ({
        let mut router = $crate::Router::new();
        $(router.$method($glob, $handler, stringify!($route_id));)*
        router
    });
}

/// Generate a URL based off of the requested one.
///
/// ```ignore
/// url_for!(request, "foo",
///          "query" => "test",
///          "extraparam" => "foo")
/// ```
///
/// Is equivalent to:
///
/// ```ignore
/// router::url_for(request, "foo", {
///     let mut rv = ::std::collections::HashMap::new();
///     rv.insert("query".to_owned(), "test".to_owned());
///     rv.insert("extraparam".to_owned(), "foo".to_owned());
///     rv
/// })
/// ```
#[macro_export]
macro_rules! url_for {
    ($request:expr, $route_id:expr $(,$key:expr => $value:expr)* $(,)*) => (
        $crate::url_for($request, $route_id, {
            let mut params = ::std::collections::HashMap::<String, String>::new();
            $(params.insert($key.into(), $value.into());)*
            params
        })
    )
}

#[cfg(test)]
mod tests {
    use iron::{Response, Request, IronResult};

    //simple test to check that all methods expand without error
    #[test]
    fn methods() {
        fn handler(_: &mut Request) -> IronResult<Response> {Ok(Response::new())}
        let _ = router!(a: get     "/foo" => handler,
                        b: post    "/bar/" => handler,
                        c: put     "/bar/baz" => handler,
                        d: delete  "/bar/baz" => handler,
                        e: head    "/foo" => handler,
                        f: patch   "/bar/baz" => handler,
                        g: options "/foo" => handler,
                        h: any     "/" => handler);
    }
}
<commit_msg>(fix) Ignore unused_mut in url_for macro<commit_after>/// Create and populate a router.
///
/// ```ignore
/// let router = router!(index: get  "/"       => index,
///                      query: get  "/:query" => queryHandler,
///                      post:  post "/"       => postHandler);
/// ```
///
/// Is equivalent to:
///
/// ```ignore
/// let mut router = Router::new();
/// router.get("/", index, "index");
/// router.get("/:query", queryHandler, "query");
/// router.post("/", postHandler, "post");
/// ```
///
/// The method name must be lowercase, supported methods:
///
/// `get`, `post`, `put`, `delete`, `head`, `patch`, `options` and `any`.
#[macro_export]
macro_rules! router {
    ($($route_id:ident: $method:ident $glob:expr => $handler:expr),+ $(,)*) => ({
        let mut router = $crate::Router::new();
        $(router.$method($glob, $handler, stringify!($route_id));)*
        router
    });
}

/// Generate a URL based off of the requested one.
///
/// ```ignore
/// url_for!(request, "foo",
///          "query" => "test",
///          "extraparam" => "foo")
/// ```
///
/// Is equivalent to:
///
/// ```ignore
/// router::url_for(request, "foo", {
///     let mut rv = ::std::collections::HashMap::new();
///     rv.insert("query".to_owned(), "test".to_owned());
///     rv.insert("extraparam".to_owned(), "foo".to_owned());
///     rv
/// })
/// ```
#[macro_export]
macro_rules! url_for {
    ($request:expr, $route_id:expr $(,$key:expr => $value:expr)* $(,)*) => (
        $crate::url_for($request, $route_id, {
            // Underscore-prefix suppresses `unused_mut` warning
            // Also works on stable rust!
            let mut _params = ::std::collections::HashMap::<String, String>::new();
            $(_params.insert($key.into(), $value.into());)*
            _params
        })
    )
}

#[cfg(test)]
mod tests {
    use iron::{Response, Request, IronResult};

    //simple test to check that all methods expand without error
    #[test]
    fn methods() {
        fn handler(_: &mut Request) -> IronResult<Response> {Ok(Response::new())}
        let _ = router!(a: get     "/foo" => handler,
                        b: post    "/bar/" => handler,
                        c: put     "/bar/baz" => handler,
                        d: delete  "/bar/baz" => handler,
                        e: head    "/foo" => handler,
                        f: patch   "/bar/baz" => handler,
                        g: options "/foo" => handler,
                        h: any     "/" => handler);
    }
}
<|endoftext|>


<commit_before>#![macro_use]

use ndarray::{DataMut, ArrayBase, Ix, Ixs};
use lapack::c::{Layout};

/// enum for symmetric matrix inputs
#[repr(u8)]
pub enum Symmetric {
    /// Read elements from the upper-triangular portion of the matrix
    Upper = b'U',

    /// Read elements from the lower-triangular portion of the matrix
    Lower =  b'L'
}

#[macro_export]
macro_rules! assert_in_tol {
    ($e1:expr, $e2:expr, $tol:expr) => (
        match (&$e1, &$e2, $tol) {
            (x, y, tol) => {
                assert_eq!(x.dim(), y.dim());
                for ((i, a), b) in x.indexed_iter().zip(y.iter()) {
                    if ((*a-*b) as f64).abs() > tol as f64 {
                        panic!(format!("Elements at {:?} not within tolerance: |{} - {}| > {}",
                                       i, a, b, tol));
                    }
                }
            }
        })
}

/// Return true if an array can be used as a matrix input.
///
/// For now, we just require a standard layout. However, this is stricter than necessary.
pub fn slice_and_layout_mut<D, S: DataMut<Elem=D>>(mat: &mut ArrayBase<S, (Ix, Ix)>) -> Option<(&mut [S::Elem], Layout, Ixs)> {
    let strides = {
        let s = mat.strides();
        (s[0], s[1])
    };

    match mat.as_slice_memory_order_mut() {
        Some(slice) => {
            // one of the stides, must be 1
            if strides.1 == 1 {
                let m = strides.0;
                Some((slice, Layout::RowMajor, m))
            }
            else if strides.0 == 0 {
                let n = strides.1;
                Some((slice, Layout::ColumnMajor, n))
            }
            else {
                None
            }
        },
        None => None
    }
}
<commit_msg>slice_and_layout_mut improvements<commit_after>#![macro_use]

use ndarray::{DataMut, ArrayBase, Ix, Ixs};
use lapack::c::{Layout};
use std::slice;

/// enum for symmetric matrix inputs
#[repr(u8)]
pub enum Symmetric {
    /// Read elements from the upper-triangular portion of the matrix
    Upper = b'U',

    /// Read elements from the lower-triangular portion of the matrix
    Lower =  b'L'
}

#[macro_export]
macro_rules! assert_in_tol {
    ($e1:expr, $e2:expr, $tol:expr) => (
        match (&$e1, &$e2, $tol) {
            (x, y, tol) => {
                assert_eq!(x.dim(), y.dim());
                for ((i, a), b) in x.indexed_iter().zip(y.iter()) {
                    if ((*a-*b) as f64).abs() > tol as f64 {
                        panic!(format!("Elements at {:?} not within tolerance: |{} - {}| > {}",
                                       i, a, b, tol));
                    }
                }
            }
        })
}

/// Return true if an array can be used as a matrix input.
///
/// For LAPACKE methods, the memory layout does not need to be
/// contiguous. We only required that either rows or columns are
/// contiguous.
pub fn slice_and_layout_mut<D, S: DataMut<Elem=D>>(mat: &mut ArrayBase<S, (Ix, Ix)>) -> Option<(&mut [S::Elem], Layout, Ixs)> {
    let strides = {
        let s = mat.strides();
        (s[0], s[1])
    };

    if strides.0 < 0 || strides.1 < 0 {
        return None;
    }

    let dim = mat.dim();

    // One of the stides, must be 1
    if strides.1 == 1 {
        let m = strides.0;
        let s = unsafe {
            let nelem: usize = (dim.0 - 1) * m as usize + dim.1;
            slice::from_raw_parts_mut(mat.as_mut_ptr(), nelem)
        };
        Some((s, Layout::RowMajor, m))
    }
    else if strides.0 == 0 {
        let n = strides.1;
        let s = unsafe {
            let nelem: usize = (dim.1 - 1) * n as usize + dim.0;
            slice::from_raw_parts_mut(mat.as_mut_ptr(), nelem)
        };
        Some((s, Layout::ColumnMajor, n))
    }
    else {
        None
    }
}
<|endoftext|>


<commit_before>//! The parser is based on the following grammar
//!
//! Equation ==> Term { "+" Term }
//!           |  Term { "-" Term }
//!
//! Term     ==> Function Product
//!           |  Product
//!
//! Product  ==> Factor { "*" Factor }
//!           |  Factor { "/" Factor }
//!
//! Factor   ==> "-" Factor
//!           |  Exponent { "^" Factor }
//!
//! Exponent ==> Number { "!" }
//!
//! Number   ==> "(" Equation ")"
//!           |  "|" Equation "|"
//!           |  Constant
//!           |  Digit { Digit } | Digit { Digit } "." { Digit }
//!
//! Function ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!           |  "ln" | "log"
//!
//! Constant ==> "pi" | "e" | "phi"
//!
//! Digit    ==> "0".."9"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use ast::OpKind::*;
use token::Token;
use token::TokVal;

pub fn parse_equation(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_equation()
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_term());
        while self.peek_tok_val() == Some(TokVal::Op(Plus)) ||
              self.peek_tok_val() == Some(TokVal::Op(Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_term());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            }
        }
        if self.peek_tok_val() == Some(TokVal::ParenClose) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.peek_tok_val() == Some(TokVal::AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_term(&mut self) -> CalcrResult<Ast> {
        // check if we have a function
        let func_opt = match self.peek_tok_val() {
            // TODO: Make this not horrible, since the compiler kept bugging me
            Some(TokVal::Name(ref name)) if *name == "cos".to_string() => Some(Cos),
            Some(TokVal::Name(ref name)) if *name == "sin".to_string() => Some(Sin),
            Some(TokVal::Name(ref name)) if *name == "tan".to_string() => Some(Tan),
            Some(TokVal::Name(ref name)) if *name == "asin".to_string() => Some(Asin),
            Some(TokVal::Name(ref name)) if *name == "acos".to_string() => Some(Acos),
            Some(TokVal::Name(ref name)) if *name == "atan".to_string() => Some(Atan),
            Some(TokVal::Name(ref name)) if *name == "sqrt".to_string() => Some(Sqrt),
            Some(TokVal::Name(ref name)) if *name == "abs".to_string() => Some(Abs),
            Some(TokVal::Name(ref name)) if *name == "exp".to_string() => Some(Exp),
            Some(TokVal::Name(ref name)) if *name == "ln".to_string() => Some(Ln),
            Some(TokVal::Name(ref name)) if *name == "log".to_string() => Some(Log),
            _ => None,
        };

        if let Some(func) = func_opt {
            let Token { val: _, span: tok_span } = self.consume_tok();
            let arg = try!(self.parse_product());
            Ok(Ast {
                val: AstVal::Func(func),
                span: tok_span,
                branches: Unary(Box::new(arg)),
            })
        } else {
            self.parse_product()
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.peek_tok_val() == Some(TokVal::Op(Mult)) ||
              self.peek_tok_val() == Some(TokVal::Op(Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.peek_tok_val() == Some(TokVal::Op(Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(Neg),
                span: tok_span,
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.peek_tok_val() == Some(TokVal::Op(Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(Pow),
                    span: tok_span,
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.peek_tok_val() == Some(TokVal::Op(Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(Fact),
                span: tok_span,
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        match self.peek_tok_val() {
            Some(TokVal::ParenOpen) => {
                // store the current pos in case we need to report a paren error
                let open_paren_span = self.consume_tok().span;
                self.paren_level += 1;
                let eq = try!(self.parse_equation());

                if self.peek_tok_val() != Some(TokVal::ParenClose) {
                    Err(CalcrError {
                        desc: "Missing closing parentheses".to_string(),
                        span: Some(open_paren_span),
                    })
                } else {
                    self.paren_level -= 1;
                    let close_paren_span = self.consume_tok().span;
                    Ok(Ast {
                        val: AstVal::Paren,
                        span: (open_paren_span.0, close_paren_span.1),
                        branches: Unary(Box::new(eq)),
                    })
                }
            },
            Some(TokVal::AbsDelim) => {
                // store the current pos in case we need to report a paren error
                let open_delim_span = self.consume_tok().span;
                self.abs_level += 1;
                let eq = try!(self.parse_equation());

                if self.peek_tok_val() != Some(TokVal::AbsDelim) {
                    Err(CalcrError {
                        desc: "Missing closing abs delimiter".to_string(),
                        span: Some(open_delim_span),
                    })
                } else {
                    self.abs_level -= 1;
                    let close_delim_span = self.consume_tok().span;
                    Ok(Ast {
                        val: AstVal::Func(Abs),
                        span: (open_delim_span.0, close_delim_span.1),
                        branches: Unary(Box::new(eq)),
                    })
                }
            },
            Some(TokVal::Name(ref name)) => {
                // at this point any Name, HAS to be a known constant
                let cnst = match name.as_ref() {
                    "pi" => Pi,
                    "e" => E,
                    "phi" => Phi,
                    _ => return Err(CalcrError {
                        desc: format!("Invalid function or constant: {}", name),
                        span: Some(self.consume_tok().span),
                    }),
                };
                let span = self.consume_tok().span;
                Ok(Ast {
                    val: AstVal::Const(cnst),
                    span: span,
                    branches: Leaf,
                })
            },
            Some(TokVal::Num(num)) => {
                let span = self.consume_tok().span;
                Ok(Ast {
                    val: AstVal::Num(num),
                    span: span,
                    branches: Leaf,
                })
            },
            Some(_) => Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some(self.consume_tok().span),
            }),
            None => Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            }),
        }
    }

    /// Peeks at the next `Token` and returns `Some` if one was found, or `None` if none are left
    fn peek_tok_val(&mut self) -> Option<TokVal> {
        self.iter.peek().and_then(|ref tok| Some(tok.val.clone()))
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}<commit_msg>Fix bug in the parser<commit_after>//! The parser is based on the following grammar
//!
//! Equation ==> Term { "+" Term }
//!           |  Term { "-" Term }
//!
//! Term     ==> Function Product
//!           |  Product
//!
//! Product  ==> Factor { "*" Term }
//!           |  Factor { "/" Term }
//!
//! Factor   ==> "-" Factor
//!           |  Exponent { "^" Factor }
//!
//! Exponent ==> Number { "!" }
//!
//! Number   ==> "(" Equation ")"
//!           |  "|" Equation "|"
//!           |  Constant
//!           |  Digit { Digit } | Digit { Digit } "." { Digit }
//!
//! Function ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!           |  "ln" | "log"
//!
//! Constant ==> "pi" | "e" | "phi"
//!
//! Digit    ==> "0".."9"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use ast::OpKind::*;
use token::Token;
use token::TokVal;

pub fn parse_equation(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_equation()
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_term());
        while self.peek_tok_val() == Some(TokVal::Op(Plus)) ||
              self.peek_tok_val() == Some(TokVal::Op(Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_term());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            }
        }
        if self.peek_tok_val() == Some(TokVal::ParenClose) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.peek_tok_val() == Some(TokVal::AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_term(&mut self) -> CalcrResult<Ast> {
        // check if we have a function
        let func_opt = match self.peek_tok_val() {
            // TODO: Make this not horrible, since the compiler kept bugging me
            Some(TokVal::Name(ref name)) if *name == "cos".to_string() => Some(Cos),
            Some(TokVal::Name(ref name)) if *name == "sin".to_string() => Some(Sin),
            Some(TokVal::Name(ref name)) if *name == "tan".to_string() => Some(Tan),
            Some(TokVal::Name(ref name)) if *name == "asin".to_string() => Some(Asin),
            Some(TokVal::Name(ref name)) if *name == "acos".to_string() => Some(Acos),
            Some(TokVal::Name(ref name)) if *name == "atan".to_string() => Some(Atan),
            Some(TokVal::Name(ref name)) if *name == "sqrt".to_string() => Some(Sqrt),
            Some(TokVal::Name(ref name)) if *name == "abs".to_string() => Some(Abs),
            Some(TokVal::Name(ref name)) if *name == "exp".to_string() => Some(Exp),
            Some(TokVal::Name(ref name)) if *name == "ln".to_string() => Some(Ln),
            Some(TokVal::Name(ref name)) if *name == "log".to_string() => Some(Log),
            _ => None,
        };

        if let Some(func) = func_opt {
            let Token { val: _, span: tok_span } = self.consume_tok();
            let arg = try!(self.parse_product());
            Ok(Ast {
                val: AstVal::Func(func),
                span: tok_span,
                branches: Unary(Box::new(arg)),
            })
        } else {
            self.parse_product()
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.peek_tok_val() == Some(TokVal::Op(Mult)) ||
              self.peek_tok_val() == Some(TokVal::Op(Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_term());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.peek_tok_val() == Some(TokVal::Op(Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(Neg),
                span: tok_span,
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.peek_tok_val() == Some(TokVal::Op(Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(Pow),
                    span: tok_span,
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.peek_tok_val() == Some(TokVal::Op(Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(Fact),
                span: tok_span,
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        match self.peek_tok_val() {
            Some(TokVal::ParenOpen) => {
                // store the current pos in case we need to report a paren error
                let open_paren_span = self.consume_tok().span;
                self.paren_level += 1;
                let eq = try!(self.parse_equation());

                if self.peek_tok_val() != Some(TokVal::ParenClose) {
                    Err(CalcrError {
                        desc: "Missing closing parentheses".to_string(),
                        span: Some(open_paren_span),
                    })
                } else {
                    self.paren_level -= 1;
                    let close_paren_span = self.consume_tok().span;
                    Ok(Ast {
                        val: AstVal::Paren,
                        span: (open_paren_span.0, close_paren_span.1),
                        branches: Unary(Box::new(eq)),
                    })
                }
            },
            Some(TokVal::AbsDelim) => {
                // store the current pos in case we need to report a paren error
                let open_delim_span = self.consume_tok().span;
                self.abs_level += 1;
                let eq = try!(self.parse_equation());

                if self.peek_tok_val() != Some(TokVal::AbsDelim) {
                    Err(CalcrError {
                        desc: "Missing closing abs delimiter".to_string(),
                        span: Some(open_delim_span),
                    })
                } else {
                    self.abs_level -= 1;
                    let close_delim_span = self.consume_tok().span;
                    Ok(Ast {
                        val: AstVal::Func(Abs),
                        span: (open_delim_span.0, close_delim_span.1),
                        branches: Unary(Box::new(eq)),
                    })
                }
            },
            Some(TokVal::Name(ref name)) => {
                // at this point any Name, HAS to be a known constant
                let cnst = match name.as_ref() {
                    "pi" => Pi,
                    "e" => E,
                    "phi" => Phi,
                    _ => return Err(CalcrError {
                        desc: format!("Invalid function or constant: {}", name),
                        span: Some(self.consume_tok().span),
                    }),
                };
                let span = self.consume_tok().span;
                Ok(Ast {
                    val: AstVal::Const(cnst),
                    span: span,
                    branches: Leaf,
                })
            },
            Some(TokVal::Num(num)) => {
                let span = self.consume_tok().span;
                Ok(Ast {
                    val: AstVal::Num(num),
                    span: span,
                    branches: Leaf,
                })
            },
            Some(_) => Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some(self.consume_tok().span),
            }),
            None => Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            }),
        }
    }

    /// Peeks at the next `Token` and returns `Some` if one was found, or `None` if none are left
    fn peek_tok_val(&mut self) -> Option<TokVal> {
        self.iter.peek().and_then(|ref tok| Some(tok.val.clone()))
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}<|endoftext|>


<commit_before>use codemap::Spanned;
use lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;
use self::ParseErrorKind::*;

type ParseIter<'a> = Peekable<Iter<'a, Spanned<Token>>>;
type Parse = Result<Node, ParseErrorKind>;

#[derive(Debug, Clone, PartialEq)]
pub enum Node {
  Block(Vec<Node>),
  If{cond: Box<Node>},
  Stmt(Box<Node>),
  Break,
  Continue,
  Expr,
  Pass,

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),
  Table,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ParseErrorKind {
  UnexpectedToken(Token),
  UnexpectedEOF,
}

// Return true if the next token in `it` is `kind`
fn peek_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    c.node == kind
  }
  else {
    false
  }
}

// Return true if the next token in `it` is `kind` *and* consume the token
fn use_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    if c.node == kind {
      it.next();
    }
    c.node == kind
  }
  else {
    false
  }
}

// Panic if the next token in `it` is *not* `kind`
fn require_token(it: &mut ParseIter, kind: Token) -> Result<(), ParseErrorKind> {
  if let Some(&c) = it.peek() {
    it.next();

    if c.node == kind {
      return Ok(());
    }

    return Err(UnexpectedToken(c.node.clone()));
  }

  return Err(UnexpectedEOF);
}

fn parse_expr(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Null => {it.next(); Ok(Node::Null)},
      Token::Bool(x) => {it.next(); Ok(Node::Bool(x))},
      Token::Float(x) => {it.next(); Ok(Node::Float(x))},
      Token::Int(x) => {it.next(); Ok(Node::Int(x))},
      Token::Str(ref x) => {it.next(); Ok(Node::Str(x.clone()))},
      Token::Name(ref x) => {it.next(); Ok(Node::Name(x.clone()))},
      _ => Err(UnexpectedToken(c.node.clone())),
    }
  }

  Err(UnexpectedEOF)
}

fn parse_stmt(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Break => {
        it.next();
        Ok(Node::Break)
      }

      Token::Continue => {
        it.next();
        Ok(Node::Continue)
      }

      Token::Pass => {
        it.next();
        Ok(Node::Pass)
      }

      Token::If => {
        it.next();
        parse_expr(it).map(|expr| Node::If{cond: Box::new(expr)})
      }

      _ => {
        parse_expr(it).map(|expr| Node::Stmt(Box::new(expr)))
      }
    }
  }

  Err(UnexpectedEOF)
}

pub fn parse(tokens: Vec<Spanned<Token>>) -> Parse {
  let mut it: ParseIter = tokens.iter().peekable();
  let mut nodes: Vec<Node> = vec![];

  while !peek_token(&mut it, Token::EOF) {
    nodes.push(parse_stmt(&mut it)?);
    require_token(&mut it, Token::End)?;
  }

  Ok(Node::Block(nodes))
}
<commit_msg>parser: Add BinExpr / UnExpr nodes<commit_after>use codemap::Spanned;
use lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;
use self::ParseErrorKind::*;

type ParseIter<'a> = Peekable<Iter<'a, Spanned<Token>>>;
type Parse = Result<Node, ParseErrorKind>;

#[derive(Debug, Clone, PartialEq)]
pub enum Node {
  Block(Vec<Node>),
  If{cond: Box<Node>},
  Stmt(Box<Node>),
  Break,
  Continue,
  Expr,
  Pass,

  BinExpr {
    lhs: Box<Node>,
    operator: Token,
    rhs: Box<Node>,
  },

  UnExpr {
    val: Box<Node>,
    operator: Token,
  },

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),
  Table,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ParseErrorKind {
  UnexpectedToken(Token),
  UnexpectedEOF,
  UnknownBinaryOperator,
  UnknownUnaryOperator,
}

// Return true if the next token in `it` is `kind`
fn peek_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    c.node == kind
  }
  else {
    false
  }
}

// Return true if the next token in `it` is `kind` *and* consume the token
fn use_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    if c.node == kind {
      it.next();
    }
    c.node == kind
  }
  else {
    false
  }
}

// Panic if the next token in `it` is *not* `kind`
fn require_token(it: &mut ParseIter, kind: Token) -> Result<(), ParseErrorKind> {
  if let Some(&c) = it.peek() {
    it.next();

    if c.node == kind {
      return Ok(());
    }

    return Err(UnexpectedToken(c.node.clone()));
  }

  return Err(UnexpectedEOF);
}

fn parse_expr(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Null => {it.next(); Ok(Node::Null)},
      Token::Bool(x) => {it.next(); Ok(Node::Bool(x))},
      Token::Float(x) => {it.next(); Ok(Node::Float(x))},
      Token::Int(x) => {it.next(); Ok(Node::Int(x))},
      Token::Str(ref x) => {it.next(); Ok(Node::Str(x.clone()))},
      Token::Name(ref x) => {it.next(); Ok(Node::Name(x.clone()))},
      _ => Err(UnexpectedToken(c.node.clone())),
    }
  }

  Err(UnexpectedEOF)
}

fn parse_stmt(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Break => {
        it.next();
        Ok(Node::Break)
      }

      Token::Continue => {
        it.next();
        Ok(Node::Continue)
      }

      Token::Pass => {
        it.next();
        Ok(Node::Pass)
      }

      Token::If => {
        it.next();
        parse_expr(it).map(|expr| Node::If{cond: Box::new(expr)})
      }

      _ => {
        parse_expr(it).map(|expr| Node::Stmt(Box::new(expr)))
      }
    }
  }

  Err(UnexpectedEOF)
}

pub fn parse(tokens: Vec<Spanned<Token>>) -> Parse {
  let mut it: ParseIter = tokens.iter().peekable();
  let mut nodes: Vec<Node> = vec![];

  while !peek_token(&mut it, Token::EOF) {
    nodes.push(parse_stmt(&mut it)?);
    require_token(&mut it, Token::End)?;
  }

  Ok(Node::Block(nodes))
}
<|endoftext|>