Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for comprehensions over iterators over tuples. #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 102 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! allowing for conditionals and nested comprehensions.
//!
//! # Python Syntax
//! ```
//! ```python
//! squares = [x*x for x in range(10)]
//!
//! even_squares = [x*x for x in range(10) if x % 2 == 0]
Expand All @@ -17,13 +17,13 @@
//! ```
//! #[macro_use(c)]
//! extern crate cute;
//!
//! # fn main() { // needed to include macro
//! let squares = c![x*x, for x in 0..10];
//!
//! let even_squares = c![x*x, for x in 0..10, if x % 2 == 0];
//!
//! let squares_hashmap = c!{key => key*key, for key in 0..10};
//!
//! # }
//! ```
//!
//! `c!`'s has the comprehension's parts, comma-separated.
Expand All @@ -33,66 +33,116 @@
//! Simple comprehension
//!
//! ```
//! let v = [1,2,3,4];
//! # #[macro_use(c)]
//! # extern crate cute;
//! # // otherwise its implicitly put in a function, so you can't `use`
//! # fn main() {
//! let v = vec![1,2,3,4];
//! let v_squared = c![x*x, for x in v];
//!
//! # }
//! ```
//! Conditional filtering
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let squares = c![x*x, for x in 0..10, if x % 2 == 0];
//! assert_eq!(squares, vec![0, 4, 16, 36, 64]);
//! # }
//! ```
//!
//! Comprehensions over tuples
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let v1 = vec![1, 2, 3];
//! let v2 = vec![10, 11, 12];
//! let sums = c![x+y, for (x,y) in v1.iter().zip(v2)];
//! assert_eq!(sums, vec![11, 13, 15]);
//! # }
//! ```
//!
//! Nested Comprehensions
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let nested = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]];
//! let flat: Vec<usize> = c![x, for x in y, for y in nested];
//! assert_eq!(flat, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
//! # }
//! ```
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let nested = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]];
//! let even_flat: Vec<usize> = c![x, for x in y, for y in nested, if x % 2 == 0];
//! assert_eq!(even_flat, vec![2, 4, 6, 8]);
//! # }
//! ```
//!
//! Comprehensions over Iterators
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let vec: Vec<i32> = vec![-4, -2, 0, 2, 4];
//! let output: Vec<i32> = c![x*2, for x in vec.iter()];
//! assert_eq!(output, vec![-8, -4, 0, 4, 8]);
//! # }
//! ```
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let vec: Vec<i32> = vec![-4, -2, 0, 2, 4];
//! let output: Vec<i32> = c![x, for x in vec.iter(), if *x >= 0i32];
//! assert_eq!(output, vec![0, 2, 4]);
//! # }
//! ```
//!

//! Function Application
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! let vec: Vec<i32> = vec![-4, -2, 0, 2, 4];
//! let output: Vec<i32> = c![x.abs(), for x in vec.iter()];
//! assert_eq!(output, vec![4, 2, 0, 2, 4]);
//! # }
//! ```
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # fn main() {
//! fn square(x:i32) -> i32 {
//! x*x
//! }
//!
//! let vec: Vec<i32> = vec![-4, -2, 0, 2, 4];
//! let squares: Vec<i32> = c![square(x), for x in vec];
//! assert_eq!(squares, vec![16, 4, 0, 4, 16]);
//! # }
//! ```
//!
//! Hashmap Comprehensions
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # use std::collections::HashMap;
//! # fn main() {
//! let v = vec!["one", "two", "three"];
//! let map = c!{key => key.to_uppercase(), for key in v};
//!
Expand All @@ -102,9 +152,14 @@
//! expected.insert("three", String::from("THREE"));
//!
//! assert_eq!(map, expected);
//! # }
//! ```
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # use std::collections::HashMap;
//! # fn main() {
//! let v: Vec<(&str, i32)> = vec![("one", 1), ("two", 2), ("three", 3)];
//! let map = c!{key => val, for (key, val) in v};
//!
Expand All @@ -114,9 +169,14 @@
//! expected.insert("three", 3);
//!
//! assert_eq!(map, expected);
//! # }
//! ```
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # use std::collections::HashMap;
//! # fn main() {
//! // conditional hashmap comprehension
//! let v: Vec<(&str, i32)> = vec![("one", 1), ("two", 2), ("three", 3)];
//! let map = c! {key => val, for (key, val) in v, if val == 1 || val == 2};
Expand All @@ -126,35 +186,42 @@
//! expected.insert("two", 2);
//!
//! assert_eq!(map, expected);
//! # }
//! ```
//!
//! ```
//! # #[macro_use(c)]
//! # extern crate cute;
//! # use std::collections::HashMap;
//! # fn main() {
//! // conditional hashmap comprehension from an Iterator
//! let map = c! {*key => key*key, for key in vec![1,2].iter(), if *key % 2 == 0};
//! let mut e: HashMap<i32, i32> = HashMap::new();
//! e.insert(2, 4);
//!
//! assert_eq!(map, e);
//! # }
//! ```



#[macro_export]
macro_rules! c {

($exp:expr, for $i:ident in $iter:expr) => (
($exp:expr, for $p:pat in $iter:expr) => (
{
let mut r = vec![];
for $i in $iter {
for $p in $iter {
r.push($exp);
}
r
}
);

($exp:expr, for $i:ident in $iter:expr, if $cond:expr) => (
($exp:expr, for $p:pat in $iter:expr, if $cond:expr) => (
{
let mut r = vec![];
for $i in $iter {
for $p in $iter {
if $cond {
r.push($exp.clone());
}
Expand All @@ -163,23 +230,23 @@ macro_rules! c {
}
);

($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr) => (
($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr) => (
{
let mut r = vec![];
for $i2 in $iter2 {
for $i in $iter {
for $p2 in $iter2 {
for $p in $iter {
r.push($exp);
}
}
r
}
);

($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, if $cond:expr) => (
($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr, if $cond:expr) => (
{
let mut r = vec![];
for $i2 in $iter2 {
for $i in $iter {
for $p2 in $iter2 {
for $p in $iter {
if $cond{
r.push($exp);
}
Expand All @@ -189,12 +256,12 @@ macro_rules! c {
}
);

($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, for $i3:ident in $iter3:expr, if $cond:expr) => (
($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr, for $p3:pat in $iter3:expr, if $cond:expr) => (
{
let mut r = vec![];
for $i in $iter {
for $i2 in $iter2 {
for $i3 in $iter3 {
for $p in $iter {
for $p2 in $iter2 {
for $p3 in $iter3 {
if $cond {
r.push($exp);
}
Expand All @@ -205,12 +272,12 @@ macro_rules! c {
}
);

($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, for $i3:ident in $iter3:expr) => (
($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr, for $p3:pat in $iter3:expr) => (
{
let mut r = vec![];
for $i in $iter {
for $i2 in $iter2 {
for $i3 in $iter3 {
for $p in $iter {
for $p2 in $iter2 {
for $p3 in $iter3 {
r.push($exp);
}
}
Expand Down Expand Up @@ -277,12 +344,24 @@ mod tests {
assert_eq!(squares, vec![0, 1, 4, 9, 16, 25, 36, 49, 64, 81]);
}

#[test]
fn tuple_comprehension() {
let pairs = c![(x,y), for (x, y) in (0..3).zip(100..103)];
assert_eq!(pairs, vec![(0, 100), (1, 101), (2, 102)]);
}

#[test]
fn filter_comprehension() {
let squares = c![x*x, for x in 0..10, if x % 2 == 0];
assert_eq!(squares, vec![0, 4, 16, 36, 64]);
}

#[test]
fn filter_tuple_comprehension() {
let matches = c![x, for (x,y) in vec![0,1,2].iter().zip(vec![0,3,2]), if x == &y];
assert_eq!(matches, vec![0, 2]);
}

#[test]
fn simple_nested_comprehension() {
let nested = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
Expand Down