create a number macro that can use floating point numbes

This commit is contained in:
Corwin Kuiper 2021-12-04 02:44:57 +00:00
parent b88cf39a67
commit 6e0cbbe9eb
2 changed files with 70 additions and 2 deletions

View file

@ -45,6 +45,19 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
.into() .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 { fn random_ident() -> Ident {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
Ident::new( Ident::new(

View file

@ -2,8 +2,8 @@ use core::{
cmp::{Eq, Ord, PartialEq, PartialOrd}, cmp::{Eq, Ord, PartialEq, PartialOrd},
fmt::{Debug, Display}, fmt::{Debug, Display},
ops::{ ops::{
Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, Shr, Add, AddAssign, BitAnd, BitOr, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign,
Sub, SubAssign, Shl, Shr, Sub, SubAssign,
}, },
}; };
@ -40,6 +40,7 @@ pub trait FixedWidthUnsignedInteger:
+ Sub<Output = Self> + Sub<Output = Self>
+ Not<Output = Self> + Not<Output = Self>
+ BitAnd<Output = Self> + BitAnd<Output = Self>
+ BitOr<Output = Self>
+ Rem<Output = Self> + Rem<Output = Self>
+ Div<Output = Self> + Div<Output = Self>
+ Mul<Output = Self> + Mul<Output = Self>
@ -50,6 +51,7 @@ pub trait FixedWidthUnsignedInteger:
fn zero() -> Self; fn zero() -> Self;
fn one() -> Self; fn one() -> Self;
fn ten() -> Self; fn ten() -> Self;
fn from_as_i32(v: i32) -> Self;
} }
pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg<Output = Self> { pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg<Output = Self> {
@ -68,6 +70,9 @@ macro_rules! fixed_width_unsigned_integer_impl {
fn ten() -> Self { fn ten() -> Self {
10 10
} }
fn from_as_i32(v: i32) -> Self {
v as $T
}
} }
}; };
} }
@ -291,6 +296,56 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
pub fn new(integral: I) -> Self { pub fn new(integral: I) -> Self {
Self(integral << N) 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<A: FixedWidthUnsignedInteger, const B: usize>() {
let a: Num<A, B> = num!(1.5);
let one = A::one() << B;
let b = Num::from_raw(one + (one >> 1));
assert_eq!(a, b);
}
fn test_negative<A: FixedWidthSignedInteger, const B: usize>() {
let a: Num<A, B> = num!(-1.5);
let one = A::one() << B;
let b = Num::from_raw(one + (one >> 1));
assert_eq!(a, -b);
}
fn test_base<const B: usize>() {
test_positive::<i32, 8>();
test_positive::<i16, 8>();
test_positive::<u32, 8>();
test_positive::<u16, 8>();
test_negative::<i32, 8>();
test_negative::<i16, 8>();
}
// 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<I: FixedWidthSignedInteger, const N: usize> Num<I, N> { impl<I: FixedWidthSignedInteger, const N: usize> Num<I, N> {