Skip to content

Instantly share code, notes, and snippets.

@skull-squadron
Created May 16, 2025 09:57
Show Gist options
  • Save skull-squadron/c68b583584446be237666a1b4d7be787 to your computer and use it in GitHub Desktop.
Save skull-squadron/c68b583584446be237666a1b4d7be787 to your computer and use it in GitHub Desktop.
make_loop! Ruby while and until, and C for loop syntactic sugar
#[macro_export]
macro_rules! make_loop {
// do { ... } while cond
(
do $body:block while $cond:expr
) => {
loop {
$body
if !$cond { break; }
}
};
// do ..., ...; while cond
(
do $($s:stmt),+ ; while $cond:expr
) => {
loop {
$($s)+
if !$cond { break; }
}
};
// do { ... } until cond
(
do $body:block until $cond:expr
) => {
loop {
$body
if $cond { break; }
}
};
// do ..., ...; until cond
(
do $($s:stmt),+; until $cond:expr
) => {
loop {
$($s)+
if $cond { break; }
}
};
// until cond => ..., ....
(
until $cond:expr => $($s:stmt),+
) => {
while !$cond {
$($s)+
}
};
// until cond => { ... }
(
until $cond:expr => $body:block
) => {
while !$cond $body
};
// body until cond
(
$body:block until $cond:expr
) => {
while !$cond $body
};
// body while cond
(
$body:block while $cond:expr
) => {
while $cond $body
};
// for init; cond; iter block
(
for $($init:stmt),+ ; $cond:expr ; $($next:stmt),+ => $body:block
) => {
$($init)+
while $cond {
$body
$($next)+
}
};
// for init; cond; iter ..., ...
(
for $($init:stmt),+ ; $cond:expr ; $($next:stmt),+ => $($s:stmt),+
) => {
$($init)+
while $cond {
$($s)+
$($next)+
}
};
// stmt+ until cond
(
$($s:stmt),+ => until $cond:expr
) => {
while !$cond { $($s)+ }
};
// stmt+ while cond
(
$($s:stmt),+ => while $cond:expr
) => {
while $cond { $($s)+ }
};
}
#[cfg(test)]
mod test {
#[test]
fn do_while_block() {
let mut n = 10;
make_loop!(do { n -= 1 } while n != 0);
assert_eq!(n, 0);
}
#[test]
fn do_while_stmt() {
let mut n = 10;
make_loop!(do n -= 1; while n != 0);
assert_eq!(n, 0);
}
#[test]
fn do_while_stmt2() {
let mut n = 10;
make_loop!(do n -= 1, n -= 1; while n != 0);
assert_eq!(n, 0);
}
#[test]
fn do_until_block() {
let mut n = 10;
make_loop!(do { n -= 1 } until n == 0);
assert_eq!(n, 0);
}
#[test]
fn do_until_stmt() {
let mut n = 10;
make_loop!(do n -= 1; until n == 0);
assert_eq!(n, 0);
}
#[test]
fn do_until_stmt2() {
let mut n = 10;
make_loop!(do n -= 1, n -= 1; until n == 0);
assert_eq!(n, 0);
}
#[test]
fn body_until_cond() {
let mut n = 10;
make_loop!({ n -= 1 } until n == 0);
assert_eq!(n, 0);
}
#[test]
fn body_while_cond() {
let mut n = 10;
make_loop!({ n -= 1 } while n != 0);
assert_eq!(n, 0);
}
#[test]
fn stmt_until_cond() {
let mut n = 10;
make_loop!(n -= 1 => until n == 0);
assert_eq!(n, 0);
}
#[test]
fn stmt_while_cond() {
let mut n = 10;
make_loop!(n -= 1 => while n != 0);
assert_eq!(n, 0);
}
#[test]
fn until_block() {
let mut n = 10;
make_loop!(until n == 0 => { n -= 1; n -= 1 });
assert_eq!(n, 0);
}
#[test]
fn until_stmt() {
let mut n = 10;
make_loop!(until n == 0 => n -= 1);
assert_eq!(n, 0);
}
#[test]
fn until_stmt2() {
let mut n = 10;
make_loop!(until n == 0 => n -= 1, n -= 1);
assert_eq!(n, 0);
}
#[test]
fn for_block() {
const N: usize = 10;
let mut n = 0;
make_loop!(for let mut i = 0; i < N; i += 1 => { n += i; } );
assert_eq!(n, N*(N-1)/2);
}
#[test]
fn for_stmt() {
const N: usize = 10;
let mut n = 0;
make_loop!(for let mut i = 0; i < N; i += 1 => n += i);
assert_eq!(n, N*(N-1)/2);
}
#[test]
fn for_stmt2() {
const N: usize = 10;
let mut n = 0;
make_loop!(for let mut i = 0; i < N; i += 1 => n += i, n += i);
assert_eq!(n, N*(N-1));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment