module Data.FixedPoint.TH ( mkWord , mkInt , mkFixedPoint ) where import Language.Haskell.TH import Data.Maybe -- |@$(mkWord X)@ Makes a type alias named @WordX@ for a word of @X@ bits. -- Notice @X@ must be a multiple of 8, 'Data.Word.Word8' must be in scope, -- 'Data.FixedPoint.BigWord' must be in scope, and this splice will add -- all smaller @WordY@ type aliases needed that aren't already in scope. mkWord :: Int -> DecsQ mkWord i | i `rem` 8 /= 0 = error ("Can not build a word of bit size " ++ show i) | otherwise = do info <- lookupTypeName (mkS i) let b = isNothing info if b then do let (h,l) = getParts i if h == 0 then do let l' = l`div`2 lD <- mkWord l' a <- tySynD (mkW i) [] (appT (appT (conT $ mkName "BigWord") (conT $ mkW l')) (conT $ mkW l')) return $ a:lD else do hD <- mkWord h lD <- mkWord l a <- tySynD (mkW i) [] (appT (appT (conT $ mkName "BigWord") (conT $ mkW h)) (conT $ mkW l)) return $ a:(hD++lD) else return [] mkS :: Int -> String mkS = ("Word" ++) . show mkW,mkI :: Int -> Name mkW = mkName . mkS mkI = mkName . ("Int" ++) . show getParts i = let l = 2^(floor (logBase 2 (fromIntegral i))) h = i - l in (h,l) -- |@$(mkInt X)@ Makes a type alias named @IntX@ for an int of X bits. -- See the requirements under 'mkWord' for additional information. mkInt :: Int -> DecsQ mkInt i = do info <- lookupTypeName (mkS i) if isNothing info then do d <- mkWord i e <- tySynD (mkName . ("Int" ++) . show $ i) [] (appT (conT $ mkName "BigInt") (conT $ mkW i)) return (e:d) else return [] -- @mkFixedPoint X Y@ Builds a fixed point alias named @FixedPointX_Y@ -- where X is the integral size in bits and Y is the fractional size in -- bits. See the requirements under 'mkWord' for additional information. mkFixedPoint :: Int -> Int -> DecsQ mkFixedPoint int frac | (int + frac) `rem` 8 /= 0 = error "For fixed points, The sum of the integral and fractional bits must be a multiple of 8." | frac `rem` 8 /= 0 = error "For fixed points, the fractional representation must be a multiple of 8." | otherwise = do let flat = int + frac f <- mkInt flat i <- mkWord (flat*2) r <- mkWord frac x <- tySynD (mkName $ "FixedPoint" ++ show int ++ "_" ++ show frac) [] (appT (appT (appT (conT $ mkName "GenericFixedPoint") (conT $ mkI flat)) (conT $ mkW $ flat*2)) (conT $ mkW frac)) return (x : r ++ i ++ f)