-- * Create generators from partial values with typed holes

-- | Create a parameterized generator for a type constructor,
-- given a view of generators of all types in the program to handle recursive
-- calls.
--
-- The generator chooses a partial value and recursively fills in the holes.
mkDataGen :: (MonadRandom m, Ord tc, Ord tv)
  => DataGenMap c tc tv (Sized m) -- ^ Sized generators
  -> tc -> DataGen c tv m
  -> [tv] -- ^ @T::tc, [u,v,w]::[tv]@ represents of the type "@T u v w@".
  -> Choice (Int, DataPat c tc tv)
  -- ^ Alternatives tagged with number of revursive references.
  -> DataGen c tv (Sized m)
mkDataGen g tc baseGen vs alts = mkDataGenM g k tc alts asTree localGen
  where
    k gen = DataGen vs $ \argGen -> sized $ \size ->
      if size == 0
      then genData baseGen $ Map.map (runSized 0) argGen
      else runSized size (gen argGen)
    asTree = snd
    localGen (0, _) = id
    localGen (1, _) = scale (subtract 1)
    localGen (leafCount, _) = scale (`div` leafCount)

-- | Create a base generator, same method.
mkDataGen :: (MonadRandom m, Ord tc, Ord tv)
  => DataGenMap c tc tv (Sized m) -- ^ Sized generators
  -> tc -> DataGen c tv m
  -> [tv] -- ^ @T::tc, [u,v,w]::[tv]@ represents of the type "@T u v w@".
  -> Choice (Int, DataPat c tc tv)
  -- ^ Alternatives tagged with number of revursive references.
  -> DataGen c tv (Sized m)
mkDataGen g tc baseGen vs alts = mkDataGenM g k tc alts asTree localGen
  where
    k gen = DataGen vs $ \argGen -> sized $ \size ->
      if size == 0
      then genData baseGen $ Map.map (runSized 0) argGen
      else runSized size (gen argGen)
    asTree = snd
    localGen (0, _) = id
    localGen (1, _) = scale (subtract 1)
    localGen (leafCount, _) = scale (`div` leafCount)

-- | Create a base generator, same method.
mkDataGen g tc baseGen vs alts = mkDataGenM g k tc alts asTree localGen
  where
    k gen = DataGen vs $ \argGen -> sized $ \size ->
      if size == 0
      then genData baseGen $ Map.map (runSized 0) argGen
      else runSized size (gen argGen)
    asTree = snd
    localGen (0, _) = id
    localGen (1, _) = scale (subtract 1)
    localGen (leafCount, _) = scale (`div` leafCount)

-- | Create a base generator, same method.