-- |
--
-- B9 produces not only VM-Images but also text documents such as configuration
-- files required by virtual machines. This module is about creating and merging
-- files containing parsable syntactic structures, such as most configuration files
-- do.
--
-- B9 can be used to create configuration files by assembling structured documents,
-- for example Yaml, JSON, Erlang Terms.
--
-- One example is creating a single cloud-init 'user-data' file from a set of
-- 'user-data' snippets - all of which using yaml syntax to declare the same
-- object (e.g @"user-data"@).
--
-- The goal is, that b9 is able to merge these snippets into one, intelligently
-- merging fields as one would expect, e.g. when merging multiple snippets with
-- @writefiles@ fields, the output object's @writefiles@ field contains all the
-- @write_file@ objects.
--
-- Another example is the OTP/Erlang sys.config for configuring OTP/Erlang releases.
module B9.Artifact.Content.AST
  ( FromAST (..),
    AST (..),
    parseFromTextWithErrorMessage,
  )
where

import B9.Artifact.Content
import B9.Artifact.Content.StringTemplate
import B9.B9Monad
import B9.QCUtil
import B9.Text
import Control.Eff
import Control.Parallel.Strategies
import Data.Binary (Binary)
import Data.Data
import Data.Hashable
import GHC.Generics (Generic)
import Test.QuickCheck

-- | Describe how to create structured content that has a tree-like syntactic
-- structure, e.g. yaml, JSON and erlang-proplists. The first parameter defines
-- a /context/ into which the 'AST' is embedded,
-- e.g. B9.Artifact.Content'. The second parameter defines a specifix
-- syntax, e.g 'B9.Artifact.Content.ErlangPropList' that the 'AST' value generates.
data AST c a
  = -- | Create an object similar to a
    -- Json object.
    ASTObj [(String, AST c a)]
  | -- | An array.
    ASTArr [AST c a]
  | -- | Merge the nested elements, this is a very
    -- powerful tool that allows to combine
    ASTMerge [AST c a]
  | -- several inputs in a smart and safe way,
    -- e.g. by merging the values of the same
    -- fields in yaml objects.
    ASTEmbed c -- Embed more impure content.
  | ASTString String -- A string literal.
  | ASTInt Int -- An Int literal.
  | ASTParse SourceFile -- An 'AST' obtained from parsing a source
      -- file that contains a string corresponding
      -- to the type parameter @a@, e.g. 'YamlObject's
  | AST a -- Embed a literal @a@.
  deriving (ReadPrec [AST c a]
ReadPrec (AST c a)
Int -> ReadS (AST c a)
ReadS [AST c a]
(Int -> ReadS (AST c a))
-> ReadS [AST c a]
-> ReadPrec (AST c a)
-> ReadPrec [AST c a]
-> Read (AST c a)
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
forall c a. (Read c, Read a) => ReadPrec [AST c a]
forall c a. (Read c, Read a) => ReadPrec (AST c a)
forall c a. (Read c, Read a) => Int -> ReadS (AST c a)
forall c a. (Read c, Read a) => ReadS [AST c a]
readListPrec :: ReadPrec [AST c a]
$creadListPrec :: forall c a. (Read c, Read a) => ReadPrec [AST c a]
readPrec :: ReadPrec (AST c a)
$creadPrec :: forall c a. (Read c, Read a) => ReadPrec (AST c a)
readList :: ReadS [AST c a]
$creadList :: forall c a. (Read c, Read a) => ReadS [AST c a]
readsPrec :: Int -> ReadS (AST c a)
$creadsPrec :: forall c a. (Read c, Read a) => Int -> ReadS (AST c a)
Read, Int -> AST c a -> ShowS
[AST c a] -> ShowS
AST c a -> String
(Int -> AST c a -> ShowS)
-> (AST c a -> String) -> ([AST c a] -> ShowS) -> Show (AST c a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall c a. (Show c, Show a) => Int -> AST c a -> ShowS
forall c a. (Show c, Show a) => [AST c a] -> ShowS
forall c a. (Show c, Show a) => AST c a -> String
showList :: [AST c a] -> ShowS
$cshowList :: forall c a. (Show c, Show a) => [AST c a] -> ShowS
show :: AST c a -> String
$cshow :: forall c a. (Show c, Show a) => AST c a -> String
showsPrec :: Int -> AST c a -> ShowS
$cshowsPrec :: forall c a. (Show c, Show a) => Int -> AST c a -> ShowS
Show, Typeable, Typeable (AST c a)
DataType
Constr
Typeable (AST c a)
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> AST c a -> c (AST c a))
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c (AST c a))
-> (AST c a -> Constr)
-> (AST c a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c (AST c a)))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (AST c a)))
-> ((forall b. Data b => b -> b) -> AST c a -> AST c a)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> AST c a -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> AST c a -> r)
-> (forall u. (forall d. Data d => d -> u) -> AST c a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> AST c a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> AST c a -> m (AST c a))
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> AST c a -> m (AST c a))
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> AST c a -> m (AST c a))
-> Data (AST c a)
AST c a -> DataType
AST c a -> Constr
(forall b. Data b => b -> b) -> AST c a -> AST c a
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AST c a -> c (AST c a)
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AST c a)
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (AST c a))
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> AST c a -> u
forall u. (forall d. Data d => d -> u) -> AST c a -> [u]
forall c a. (Data c, Data a) => Typeable (AST c a)
forall c a. (Data c, Data a) => AST c a -> DataType
forall c a. (Data c, Data a) => AST c a -> Constr
forall c a.
(Data c, Data a) =>
(forall b. Data b => b -> b) -> AST c a -> AST c a
forall c a u.
(Data c, Data a) =>
Int -> (forall d. Data d => d -> u) -> AST c a -> u
forall c a u.
(Data c, Data a) =>
(forall d. Data d => d -> u) -> AST c a -> [u]
forall c a r r'.
(Data c, Data a) =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
forall c a r r'.
(Data c, Data a) =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
forall c a (m :: * -> *).
(Data c, Data a, Monad m) =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
forall c a (m :: * -> *).
(Data c, Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
forall c a (c :: * -> *).
(Data c, Data a) =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AST c a)
forall c a (c :: * -> *).
(Data c, Data a) =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AST c a -> c (AST c a)
forall c a (t :: * -> *) (c :: * -> *).
(Data c, Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (AST c a))
forall c a (t :: * -> * -> *) (c :: * -> *).
(Data c, Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (AST c a))
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AST c a)
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AST c a -> c (AST c a)
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c (AST c a))
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (AST c a))
$cAST :: Constr
$cASTParse :: Constr
$cASTInt :: Constr
$cASTString :: Constr
$cASTEmbed :: Constr
$cASTMerge :: Constr
$cASTArr :: Constr
$cASTObj :: Constr
$tAST :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
$cgmapMo :: forall c a (m :: * -> *).
(Data c, Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
gmapMp :: (forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
$cgmapMp :: forall c a (m :: * -> *).
(Data c, Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
gmapM :: (forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
$cgmapM :: forall c a (m :: * -> *).
(Data c, Data a, Monad m) =>
(forall d. Data d => d -> m d) -> AST c a -> m (AST c a)
gmapQi :: Int -> (forall d. Data d => d -> u) -> AST c a -> u
$cgmapQi :: forall c a u.
(Data c, Data a) =>
Int -> (forall d. Data d => d -> u) -> AST c a -> u
gmapQ :: (forall d. Data d => d -> u) -> AST c a -> [u]
$cgmapQ :: forall c a u.
(Data c, Data a) =>
(forall d. Data d => d -> u) -> AST c a -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
$cgmapQr :: forall c a r r'.
(Data c, Data a) =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
$cgmapQl :: forall c a r r'.
(Data c, Data a) =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AST c a -> r
gmapT :: (forall b. Data b => b -> b) -> AST c a -> AST c a
$cgmapT :: forall c a.
(Data c, Data a) =>
(forall b. Data b => b -> b) -> AST c a -> AST c a
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (AST c a))
$cdataCast2 :: forall c a (t :: * -> * -> *) (c :: * -> *).
(Data c, Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (AST c a))
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c (AST c a))
$cdataCast1 :: forall c a (t :: * -> *) (c :: * -> *).
(Data c, Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (AST c a))
dataTypeOf :: AST c a -> DataType
$cdataTypeOf :: forall c a. (Data c, Data a) => AST c a -> DataType
toConstr :: AST c a -> Constr
$ctoConstr :: forall c a. (Data c, Data a) => AST c a -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AST c a)
$cgunfold :: forall c a (c :: * -> *).
(Data c, Data a) =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AST c a)
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AST c a -> c (AST c a)
$cgfoldl :: forall c a (c :: * -> *).
(Data c, Data a) =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AST c a -> c (AST c a)
$cp1Data :: forall c a. (Data c, Data a) => Typeable (AST c a)
Data, AST c a -> AST c a -> Bool
(AST c a -> AST c a -> Bool)
-> (AST c a -> AST c a -> Bool) -> Eq (AST c a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall c a. (Eq c, Eq a) => AST c a -> AST c a -> Bool
/= :: AST c a -> AST c a -> Bool
$c/= :: forall c a. (Eq c, Eq a) => AST c a -> AST c a -> Bool
== :: AST c a -> AST c a -> Bool
$c== :: forall c a. (Eq c, Eq a) => AST c a -> AST c a -> Bool
Eq, (forall x. AST c a -> Rep (AST c a) x)
-> (forall x. Rep (AST c a) x -> AST c a) -> Generic (AST c a)
forall x. Rep (AST c a) x -> AST c a
forall x. AST c a -> Rep (AST c a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall c a x. Rep (AST c a) x -> AST c a
forall c a x. AST c a -> Rep (AST c a) x
$cto :: forall c a x. Rep (AST c a) x -> AST c a
$cfrom :: forall c a x. AST c a -> Rep (AST c a) x
Generic)

instance Functor (AST c) where
  fmap :: (a -> b) -> AST c a -> AST c b
fmap a -> b
f (AST a
a) = b -> AST c b
forall c a. a -> AST c a
AST (a -> b
f a
a)
  fmap a -> b
f (ASTObj [(String, AST c a)]
x) = [(String, AST c b)] -> AST c b
forall c a. [(String, AST c a)] -> AST c a
ASTObj ((((String, AST c a) -> (String, AST c b))
-> [(String, AST c a)] -> [(String, AST c b)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((String, AST c a) -> (String, AST c b))
 -> [(String, AST c a)] -> [(String, AST c b)])
-> ((a -> b) -> (String, AST c a) -> (String, AST c b))
-> (a -> b)
-> [(String, AST c a)]
-> [(String, AST c b)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AST c a -> AST c b) -> (String, AST c a) -> (String, AST c b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((AST c a -> AST c b) -> (String, AST c a) -> (String, AST c b))
-> ((a -> b) -> AST c a -> AST c b)
-> (a -> b)
-> (String, AST c a)
-> (String, AST c b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> AST c a -> AST c b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) a -> b
f [(String, AST c a)]
x)
  fmap a -> b
f (ASTArr [AST c a]
x) = [AST c b] -> AST c b
forall c a. [AST c a] -> AST c a
ASTArr (((AST c a -> AST c b) -> [AST c a] -> [AST c b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((AST c a -> AST c b) -> [AST c a] -> [AST c b])
-> ((a -> b) -> AST c a -> AST c b)
-> (a -> b)
-> [AST c a]
-> [AST c b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> AST c a -> AST c b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) a -> b
f [AST c a]
x)
  fmap a -> b
f (ASTMerge [AST c a]
x) = [AST c b] -> AST c b
forall c a. [AST c a] -> AST c a
ASTMerge (((AST c a -> AST c b) -> [AST c a] -> [AST c b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((AST c a -> AST c b) -> [AST c a] -> [AST c b])
-> ((a -> b) -> AST c a -> AST c b)
-> (a -> b)
-> [AST c a]
-> [AST c b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> AST c a -> AST c b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) a -> b
f [AST c a]
x)
  fmap a -> b
_ (ASTEmbed c
x) = c -> AST c b
forall c a. c -> AST c a
ASTEmbed c
x
  fmap a -> b
_ (ASTString String
x) = String -> AST c b
forall c a. String -> AST c a
ASTString String
x
  fmap a -> b
_ (ASTInt Int
x) = Int -> AST c b
forall c a. Int -> AST c a
ASTInt Int
x
  fmap a -> b
_ (ASTParse SourceFile
x) = SourceFile -> AST c b
forall c a. SourceFile -> AST c a
ASTParse SourceFile
x

instance (Hashable c, Hashable a) => Hashable (AST c a)

instance (Binary c, Binary a) => Binary (AST c a)

instance (NFData c, NFData a) => NFData (AST c a)

-- | Types of values that describe content, that can be created from an 'AST'.
class FromAST a where
  fromAST ::
    (IsB9 e, ToContentGenerator c) =>
    AST c a ->
    Eff e a

instance (Arbitrary c, Arbitrary a) => Arbitrary (AST c a) where
  arbitrary :: Gen (AST c a)
arbitrary =
    [Gen (AST c a)] -> Gen (AST c a)
forall a. [Gen a] -> Gen a
oneof
      [ [(String, AST c a)] -> AST c a
forall c a. [(String, AST c a)] -> AST c a
ASTObj ([(String, AST c a)] -> AST c a)
-> Gen [(String, AST c a)] -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [(String, AST c a)] -> Gen [(String, AST c a)]
forall a. Gen a -> Gen a
smaller (Gen (String, AST c a) -> Gen [(String, AST c a)]
forall a. Gen a -> Gen [a]
listOf ((,) (String -> AST c a -> (String, AST c a))
-> Gen String -> Gen (AST c a -> (String, AST c a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen String
forall a. Arbitrary a => Gen a
arbitrary Gen (AST c a -> (String, AST c a))
-> Gen (AST c a) -> Gen (String, AST c a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen (AST c a)
forall a. Arbitrary a => Gen a
arbitrary)),
        [AST c a] -> AST c a
forall c a. [AST c a] -> AST c a
ASTArr ([AST c a] -> AST c a) -> Gen [AST c a] -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [AST c a] -> Gen [AST c a]
forall a. Gen a -> Gen a
smaller (Gen (AST c a) -> Gen [AST c a]
forall a. Gen a -> Gen [a]
listOf Gen (AST c a)
forall a. Arbitrary a => Gen a
arbitrary),
        [AST c a] -> AST c a
forall c a. [AST c a] -> AST c a
ASTMerge ([AST c a] -> AST c a) -> Gen [AST c a] -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int -> Gen [AST c a]) -> Gen [AST c a]
forall a. (Int -> Gen a) -> Gen a
sized (\Int
s -> Int -> Gen [AST c a] -> Gen [AST c a]
forall a. Int -> Gen a -> Gen a
resize (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
2 Int
s) (Gen (AST c a) -> Gen [AST c a]
forall a. Gen a -> Gen [a]
listOf (Gen (AST c a) -> Gen (AST c a)
forall a. Gen a -> Gen a
halfSize Gen (AST c a)
forall a. Arbitrary a => Gen a
arbitrary))),
        c -> AST c a
forall c a. c -> AST c a
ASTEmbed (c -> AST c a) -> Gen c -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen c -> Gen c
forall a. Gen a -> Gen a
smaller Gen c
forall a. Arbitrary a => Gen a
arbitrary,
        String -> AST c a
forall c a. String -> AST c a
ASTString (String -> AST c a) -> Gen String -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen String
forall a. Arbitrary a => Gen a
arbitrary,
        SourceFile -> AST c a
forall c a. SourceFile -> AST c a
ASTParse (SourceFile -> AST c a) -> Gen SourceFile -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen SourceFile -> Gen SourceFile
forall a. Gen a -> Gen a
smaller Gen SourceFile
forall a. Arbitrary a => Gen a
arbitrary,
        a -> AST c a
forall c a. a -> AST c a
AST (a -> AST c a) -> Gen a -> Gen (AST c a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen a -> Gen a
forall a. Gen a -> Gen a
smaller Gen a
forall a. Arbitrary a => Gen a
arbitrary
      ]