#![recursion_limit = "512"]
use rukt::rukt;
#[test]
fn expand() {
let mut value = 1;
rukt! {
expand {
value += 2;
}
expand {
value *= 3;
}
}
assert_eq!(value, 9);
}
#[test]
fn let_bool() {
rukt! {
let a = true;
let b = false;
expand {
const A: bool = $a;
const B: bool = $b;
}
}
assert_eq!(A, true);
assert_eq!(B, false);
}
#[test]
fn let_literal() {
rukt! {
let a = 123;
let b = "hello";
expand {
const A: u32 = $a;
const B: &str = $b;
}
}
assert_eq!(A, 123);
assert_eq!(B, "hello");
}
#[test]
fn let_token_tree() {
rukt! {
let a = (^here);
let b = {
[ARBITRARY SYNTAX] in $a
where "nothing" => match
};
let {[$($c:ident)*] $($_:tt)*} = b;
expand {
$(const $c: &str = stringify!($b);)*
}
}
assert_eq!(ARBITRARY, SYNTAX);
assert_eq!(
SYNTAX,
"{ [ARBITRARY SYNTAX] in (^ here) where \"nothing\" => match }"
);
}
#[test]
fn let_export() {
rukt! {
pub(self) let value = [1, 2, 3];
}
rukt! {
let [$($number:tt),*] = value;
expand {
const VALUE: u32 = 0 $(+ $number)*;
}
}
assert_eq!(VALUE, 6);
assert_eq!(value!(), [1, 2, 3]);
}
#[test]
fn parse_regular_macro() {
rukt! {
let value = { 7 [arbitrary] stuff ... };
pub(self) let string = rukt::builtins::parse::<expr>(stringify!($value));
}
assert_eq!(string!(), "{ 7 [arbitrary] stuff ... }");
}
#[test]
fn comparison() {
rukt! {
let a = "foo" == "bar";
let b = false == a;
let c = a != b;
expand {
assert_eq!($a, false);
assert_eq!($b, true);
assert_eq!($c, true);
}
}
}
#[test]
fn comparison_escape() {
rukt! {
let a = ($dummy:tt) == (anything);
let b = (anything) == ($dummy:tt);
let c = ($dummy:tt) == ($dummy:tt) ;
expand {
assert_eq!($a, false);
assert_eq!($b, false);
assert_eq!($c, true);
}
}
}
#[test]
fn boolean() {
rukt! {
let p0 = true && true && true;
let p1 = true && true && false;
let p2 = true && false && true;
let p3 = true && false && false;
let p4 = false && true && true;
let p5 = false && true && false;
let p6 = false && false && true;
let p7 = false && false && false;
expand {
assert_eq!($p0, true);
assert_eq!($p1, false);
assert_eq!($p2, false);
assert_eq!($p3, false);
assert_eq!($p4, false);
assert_eq!($p5, false);
assert_eq!($p6, false);
assert_eq!($p7, false);
}
};
rukt! {
let p0 = true || true || true;
let p1 = true || true || false;
let p2 = true || false || true;
let p3 = true || false || false;
let p4 = false || true || true;
let p5 = false || true || false;
let p6 = false || false || true;
let p7 = false || false || false;
expand {
assert_eq!($p0, true);
assert_eq!($p1, true);
assert_eq!($p2, true);
assert_eq!($p3, true);
assert_eq!($p4, true);
assert_eq!($p5, true);
assert_eq!($p6, true);
assert_eq!($p7, false);
}
}
rukt! {
let p1 = false && true || true;
let p2 = true || true && false;
expand {
assert_eq!($p1, true);
assert_eq!($p2, true);
}
}
}
#[test]
fn starts_with() {
use rukt::builtins::starts_with;
rukt! {
let a = [1 2 3].starts_with(1 2);
let b = [1 2 3].starts_with(2 2);
let c = [1 2 3].starts_with(1 2 3 4);
expand {
assert_eq!($a, true);
assert_eq!($b, false);
assert_eq!($c, false);
}
}
}
#[test]
fn starts_with_escape() {
use rukt::builtins::starts_with;
rukt! {
let D = $;
let a = [1 2 $D($_:tt)*].starts_with($D($_:tt)*);
let b = [1 2 $D($_:tt)*].starts_with(1 2);
let c = [1 2 $D($_:tt)*].starts_with(2 2);
let d = [1 2 $D($_:tt)*].starts_with(1 2 $D($T:tt)*);
let e = [1 2 $D($_:tt)*].starts_with(1 2 $D($_:tt)*);
let f = [1 2 $D($_:tt)*].starts_with(1 2 3 4);
expand {
assert_eq!($a, false);
assert_eq!($b, true);
assert_eq!($c, false);
assert_eq!($d, false);
assert_eq!($e, true);
assert_eq!($f, false);
}
}
}
#[test]
fn user_function() {
rukt! {
fn foo($n:expr) {
let inner = (123 * $n);
inner
}
let value = foo(2);
expand {
assert_eq!($value, 246);
assert_eq!(stringify!($inner), "$inner");
}
}
}
#[test]
fn user_function_value() {
rukt! {
fn double($($args:tt)*) {
($($args)* $($args)*)
}
fn apply($f:tt $($args:tt)*) {
f($($args)*)
}
let d = apply($double mind blown);
expand {
assert_eq!(stringify!($d), "(mind blown mind blown)");
}
}
}
#[test]
fn user_function_expand() {
rukt! {
fn define($name:ident, $n:expr) {
expand {
const $name: u32 = $n;
}
}
define(SEVEN, 7);
let result = define(NINE, 9);
expand {
assert_eq!($result, ());
}
}
assert_eq!(SEVEN, 7);
assert_eq!(NINE, 9);
}
#[test]
fn manual_function() {
rukt! {
let ($name:ident) = (test);
let manual_fn = {
fn $name() {
$name
}
};
let a = manual_fn();
let b = manual_fn()();
let equal = a == b && b()()() == b;
expand {
assert_eq!(stringify!($a), "{ fn test () { test } }");
assert_eq!(stringify!($b), "{ fn test () { test } }");
assert_eq!($equal, true);
}
}
}
#[test]
fn condition() {
use rukt::builtins::starts_with;
rukt! {
let value = if [1 2 3].starts_with(-1 2) {
expand {
compile_error!("invalid");
}
} else {
42
};
let unit = if false {} else {};
let result = if true == false {
1
} else if "something" == "other thing" {
2
} else if true == (42).starts_with($value) && value == 42 {
if true {
let inner = 3;
inner
} else {
9999
}
} else {
4
};
fn total() {
if true {
8
} else {
9
}
}
let total_result = total();
fn partial() {
if true {
8
}
}
let partial_result = partial();
fn with_semi() {
if true {
8
} else {
9
};
}
let with_semi_result = with_semi();
expand {
assert_eq!($value, 42);
assert_eq!($unit, ());
assert_eq!($result, 3);
assert_eq!(stringify!($inner), "$inner");
assert_eq!($total_result, 8);
assert_eq!($partial_result, ());
assert_eq!($with_semi_result, ());
}
}
}
#[test]
fn condition_function() {
rukt! {
let result = true && if true {
fn f($n:tt) {
n
}
f
} else {
fn f($n:tt) {
}
f
}(123) == 123;
expand {
assert_eq!($result, true);
}
}
}
#[test]
fn recursion() {
use rukt::builtins::starts_with;
rukt! {
let [$($start:tt)*] = [
123
456
];
fn f($a:tt $($remaining:tt)*) {
if a == "stop" {
[start $($start)*]
} else {
let [$($prefix:tt)*] = if [$($remaining)*].starts_with(2) {
[double it]
} else if [$($remaining)*].starts_with(3) {
[just wait]
} else {
[]
};
let [$($result:tt)*] = f($($remaining)*);
[$($result)* -> $($prefix)* $a]
}
}
let result = f(1 2 3 "stop" ignored);
expand {
assert_eq!(stringify!($result), "[start 123 456 -> 3 -> just wait 2 -> double it 1]");
}
}
}