diff --git a/agb-macros/src/lib.rs b/agb-macros/src/lib.rs index 40cc44aa..a00985eb 100644 --- a/agb-macros/src/lib.rs +++ b/agb-macros/src/lib.rs @@ -45,6 +45,19 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { .into() } +#[proc_macro] +pub fn num(input: TokenStream) -> TokenStream { + let f = syn::parse_macro_input!(input as syn::LitFloat); + let v: f64 = f.base10_parse().expect("The number should be parsable"); + + let integer = v.trunc(); + let fractional = v.fract() * (1_u64 << 30) as f64; + + let integer = integer as i32; + let fractional = fractional as i32; + quote!((#integer, #fractional)).into() +} + fn random_ident() -> Ident { let mut rng = rand::thread_rng(); Ident::new( diff --git a/agb/src/number.rs b/agb/src/number.rs index 1b6068f5..8e9bda5b 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -50,6 +50,7 @@ pub trait FixedWidthUnsignedInteger: fn zero() -> Self; fn one() -> Self; fn ten() -> Self; + fn from_as_i32(v: i32) -> Self; } pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg { @@ -68,6 +69,9 @@ macro_rules! fixed_width_unsigned_integer_impl { fn ten() -> Self { 10 } + fn from_as_i32(v: i32) -> Self { + v as $T + } } }; } @@ -291,6 +295,56 @@ impl Num { pub fn new(integral: I) -> Self { Self(integral << N) } + + pub fn new_from_parts(num: (i32, i32)) -> Self { + Self(I::from_as_i32(((num.0) << N) + (num.1 >> (30 - N)))) + } +} + +#[macro_export] +macro_rules! num { + ($value:literal) => {{ + $crate::number::Num::new_from_parts(agb_macros::num!($value)) + }}; +} + +#[test_case] +fn test_macro_conversion(_gba: &mut super::Gba) { + fn test_positive() { + let a: Num = num!(1.5); + let one = A::one() << B; + let b = Num::from_raw(one + (one >> 1)); + + assert_eq!(a, b); + } + + fn test_negative() { + let a: Num = num!(-1.5); + let one = A::one() << B; + let b = Num::from_raw(one + (one >> 1)); + + assert_eq!(a, -b); + } + + fn test_base() { + test_positive::(); + test_positive::(); + test_positive::(); + test_positive::(); + + test_negative::(); + test_negative::(); + } + // some nice powers of two + test_base::<8>(); + test_base::<4>(); + test_base::<16>(); + // not a power of two + test_base::<10>(); + // an odd number + test_base::<9>(); + // and a prime + test_base::<11>(); } impl Num {