packages feed

clash-lib-hedgehog-1.8.0: src/Clash/Hedgehog/Internal/Bias.hs

{-|
Copyright   : (C) 2021, QBayLogic B.V.
License     : BSD2 (see the file LICENSE)
Maintainer  : QBayLogic B.V. <devops@qbaylogic.com>

Bias for influencing generator choice.
-}

{-# LANGUAGE CPP #-}

module Clash.Hedgehog.Internal.Bias
  ( Bias(..)
  ) where

import Clash.Core.Subst (aeqType)
import Clash.Core.TyCon
import Clash.Core.Type
import Clash.Core.TysPrim

-- | Determine the bias of an item. This is used to set the weight of that item
-- so we can sample using the 'Hedgehog.Gen.frequency' generator instead of
-- 'Hedgehog.Gen.element' or 'Hedgehog.Gen.choice'.
--
-- Where might you want to introduce such a bias? If there is a collection of
-- elements where there is a likeliness that real code would use certain values
-- more or less, we want to be able to capture this. An obvious example of this
-- is the @TyConMap@, where without it every constructor would have an even
-- weighting, when in reality some (like @Void#@ or @Addr#@ are much less
-- likely to appear in code written by a Clash user).
--
class Bias a where
  biasOf :: a -> Int

-- Remember, the bias we pick here does not necessarily matter. Only
-- constructors with the correct shape will ever be considered.
--
-- TODO These biases are only very loosely based in reality, and could be
-- completely useless at generating the kinds / types we want to see.
instance Bias TyCon where
  biasOf tc@PrimTyCon{}
    | aeqType ty liftedTypeKind   = biasBy 3  -- Type
    | aeqType ty typeNatKind      = biasBy 2  -- Nat
    | aeqType ty typeSymbolKind   = biasBy 1  -- Symbol

    | aeqType ty integerPrimTy    = biasBy 5  -- Integer, Natural, Int#, Word#
    | aeqType ty naturalPrimTy    = biasBy 5
    | aeqType ty intPrimTy        = biasBy 5
    | aeqType ty wordPrimTy       = biasBy 5
    | aeqType ty int64PrimTy      = biasBy 4  -- Int64#, Word64#
    | aeqType ty word64PrimTy     = biasBy 4
    | aeqType ty floatPrimTy      = biasBy 3  -- Float#, Double#
    | aeqType ty doublePrimTy     = biasBy 3
    | aeqType ty charPrimTy       = biasBy 2  -- Char#, ByteArray#, Addr#
    | aeqType ty byteArrayPrimTy  = biasBy 2
    | aeqType ty stringPrimTy     = biasBy 2
#if !MIN_VERSION_base(4,16,0)
    | aeqType ty voidPrimTy       = biasBy 1  -- Void#
#endif

    | otherwise                   = baseBias  -- Anything else is base
   where
    baseBias = 10
    ty       = mkTyConTy (tyConName tc)

    biasBy :: Int -> Int
    biasBy n = baseBias ^ n

  biasOf AlgTyCon{}         = 20 ^ (4 :: Int)
  biasOf PromotedDataCon{}  = 20 ^ (3 :: Int)
  biasOf FunTyCon{}         = 20 ^ (3 :: Int)