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

    Data types and rendering for Edalize Metadata files (EDAM).
    -}

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE OverloadedStrings #-}

    module Clash.Edalize.Edam
      ( Edam(..)
      , EdamFile(..)
      , EdamFileType(..)
      , EdamTools(..)
      , GhdlOptions(..)
      , IcarusOptions(..)
      , ModelsimOptions(..)
      , QuartusOptions(..)
      , VivadoOptions(..)

      , pprEdam
      ) where

    import Data.Default
    import Data.Maybe
    import Data.Text (Text)

    #if MIN_VERSION_prettyprinter(1,7,0)
    import Prettyprinter
    #else
    import Data.Text.Prettyprint.Doc
    #endif

    -- | EDAM data structure to be given to an Edalize backend. This contains all
    -- information needed to generate a project scaffolding. Note that hooks and
    -- VPI modules are currently not specified by clash.
    --
    data Edam = Edam
      { Edam -> Text
    edamProjectName :: Text
      , Edam -> Text
    edamTopEntity   :: Text
      , Edam -> [EdamFile]
    edamFiles       :: [EdamFile]
      , Edam -> EdamTools
    edamToolOptions :: EdamTools
      }

    pprEdam :: Edam -> Doc ann
    pprEdam :: forall ann. Edam -> Doc ann
    pprEdam (Edam Text
    n Text
    te [EdamFile]
    fs EdamTools
    ts) = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep
      [ Doc ann
    forall ann. Doc ann
    pyPre
      , [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    hsep [Doc ann
    "edam", Doc ann
    forall ann. Doc ann
    equals, Doc ann
    forall ann. Doc ann
    manifest]
      , Doc ann
    forall ann. Doc ann
    pyPost
      ]
     where
      manifest :: Doc ann
    manifest = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "name" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    n)
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "toplevel" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    te)
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "files" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyList ((EdamFile -> Doc ann) -> [EdamFile] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap EdamFile -> Doc ann
    forall ann. EdamFile -> Doc ann
    pprFile [EdamFile]
    fs)
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "tool_options" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ EdamTools -> Doc ann
    forall ann. EdamTools -> Doc ann
    pprEdamTools EdamTools
    ts
        ]

    -- | Information about each file in the project. This does not include
    -- is_include_file or include_path, as these are not currently used by Clash.
    --
    data EdamFile = EdamFile
      { EdamFile -> String
    efName        :: FilePath
      , EdamFile -> EdamFileType
    efType        :: EdamFileType
      , EdamFile -> Text
    efLogicalName :: Text
      }

    pprFile :: EdamFile -> Doc ann
    pprFile :: forall ann. EdamFile -> Doc ann
    pprFile (EdamFile String
    n EdamFileType
    ty Text
    ln) =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "name" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ String -> Doc ann
    forall ann. String -> Doc ann
    joinPath String
    n
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "file_type" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (EdamFileType -> Doc ann
    forall ann. EdamFileType -> Doc ann
    pprFileType EdamFileType
    ty)
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "logical_name" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    ln)
        ]

    -- | A subset of the file types recognized by Edalize. The supported formats
    -- are largely from IP-XACT 2014 (IEEE 1685-2014), although Edalize extends
    -- this with other types, e.g. QSYS.
    --
    -- Only file types which are generated by Clash are listed.
    --
    data EdamFileType
      = Unknown
        -- ^ Unknown file type.
      | VhdlSource
        -- ^ VHDL source.
      | VerilogSource
        -- ^ Verilog source.
      | SystemVerilogSource
        -- ^ SystemVerilog source.
      | TclSource
        -- ^ Tool Command Language source.
      | QSYS
        -- ^ QSys system source.
      | SDC
        -- ^ Synopsys Design Constraints source.
      deriving (EdamFileType -> EdamFileType -> Bool
    (EdamFileType -> EdamFileType -> Bool)
    -> (EdamFileType -> EdamFileType -> Bool) -> Eq EdamFileType
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: EdamFileType -> EdamFileType -> Bool
    == :: EdamFileType -> EdamFileType -> Bool
    $c/= :: EdamFileType -> EdamFileType -> Bool
    /= :: EdamFileType -> EdamFileType -> Bool
    Eq, Int -> EdamFileType -> ShowS
    [EdamFileType] -> ShowS
    EdamFileType -> String
    (Int -> EdamFileType -> ShowS)
    -> (EdamFileType -> String)
    -> ([EdamFileType] -> ShowS)
    -> Show EdamFileType
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> EdamFileType -> ShowS
    showsPrec :: Int -> EdamFileType -> ShowS
    $cshow :: EdamFileType -> String
    show :: EdamFileType -> String
    $cshowList :: [EdamFileType] -> ShowS
    showList :: [EdamFileType] -> ShowS
    Show)

    pprFileType :: EdamFileType -> Doc ann
    pprFileType :: forall ann. EdamFileType -> Doc ann
    pprFileType = \case
      EdamFileType
    Unknown -> Doc ann
    "unknown"
      EdamFileType
    VhdlSource -> Doc ann
    "vhdlSource"
      EdamFileType
    VerilogSource -> Doc ann
    "verilogSource"
      EdamFileType
    SystemVerilogSource -> Doc ann
    "systemVerilogSource"
      EdamFileType
    TclSource -> Doc ann
    "tclSource"
      EdamFileType
    QSYS -> Doc ann
    "QSYS"
      EdamFileType
    SDC -> Doc ann
    "SDC"

    -- | Tool-specific configuration used by Edalize.
    -- Currently only tools which are supported by Clash are provided.
    --
    data EdamTools = EdamTools
      { EdamTools -> Maybe GhdlOptions
    etGhdl      :: Maybe GhdlOptions
      , EdamTools -> Maybe IcarusOptions
    etIcarus    :: Maybe IcarusOptions
      , EdamTools -> Maybe ModelsimOptions
    etModelsim  :: Maybe ModelsimOptions
      , EdamTools -> Maybe QuartusOptions
    etQuartus   :: Maybe QuartusOptions
      , EdamTools -> Maybe VivadoOptions
    etVivado    :: Maybe VivadoOptions
      }

    instance Default EdamTools where
      def :: EdamTools
    def = Maybe GhdlOptions
    -> Maybe IcarusOptions
    -> Maybe ModelsimOptions
    -> Maybe QuartusOptions
    -> Maybe VivadoOptions
    -> EdamTools
    EdamTools Maybe GhdlOptions
    forall a. Default a => a
    def Maybe IcarusOptions
    forall a. Default a => a
    def Maybe ModelsimOptions
    forall a. Default a => a
    def Maybe QuartusOptions
    forall a. Default a => a
    def Maybe VivadoOptions
    forall a. Default a => a
    def

    pprEdamTools :: EdamTools -> Doc ann
    pprEdamTools :: forall ann. EdamTools -> Doc ann
    pprEdamTools EdamTools
    tools =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "ghdl" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ GhdlOptions -> Doc ann
    forall ann. GhdlOptions -> Doc ann
    pprGhdlOptions GhdlOptions
    ghdl
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "icarus" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ IcarusOptions -> Doc ann
    forall ann. IcarusOptions -> Doc ann
    pprIcarusOptions IcarusOptions
    icarus
        , Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    "modelsim" (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ ModelsimOptions -> Doc ann
    forall ann. ModelsimOptions -> Doc ann
    pprModelsimOptions ModelsimOptions
    modelsim
        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "quartus"
            Text
    "TODO Specify options if using Quartus"
            (QuartusOptions -> Doc ann
    forall ann. QuartusOptions -> Doc ann
    pprQuartusOptions QuartusOptions
    quartus)

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "vivado"
            Text
    "TODO Specify options if using Vivado"
            (VivadoOptions -> Doc ann
    forall ann. VivadoOptions -> Doc ann
    pprVivadoOptions VivadoOptions
    vivado)
        ]
     where
      ghdl :: GhdlOptions
    ghdl     = GhdlOptions -> Maybe GhdlOptions -> GhdlOptions
    forall a. a -> Maybe a -> a
    fromMaybe GhdlOptions
    forall a. Default a => a
    def (EdamTools -> Maybe GhdlOptions
    etGhdl EdamTools
    tools)
      icarus :: IcarusOptions
    icarus   = IcarusOptions -> Maybe IcarusOptions -> IcarusOptions
    forall a. a -> Maybe a -> a
    fromMaybe IcarusOptions
    forall a. Default a => a
    def (EdamTools -> Maybe IcarusOptions
    etIcarus EdamTools
    tools)
      modelsim :: ModelsimOptions
    modelsim = ModelsimOptions -> Maybe ModelsimOptions -> ModelsimOptions
    forall a. a -> Maybe a -> a
    fromMaybe ModelsimOptions
    forall a. Default a => a
    def (EdamTools -> Maybe ModelsimOptions
    etModelsim EdamTools
    tools)
      quartus :: QuartusOptions
    quartus  = QuartusOptions -> Maybe QuartusOptions -> QuartusOptions
    forall a. a -> Maybe a -> a
    fromMaybe QuartusOptions
    forall a. Default a => a
    def (EdamTools -> Maybe QuartusOptions
    etQuartus EdamTools
    tools)
      vivado :: VivadoOptions
    vivado   = VivadoOptions -> Maybe VivadoOptions -> VivadoOptions
    forall a. a -> Maybe a -> a
    fromMaybe VivadoOptions
    forall a. Default a => a
    def (EdamTools -> Maybe VivadoOptions
    etVivado EdamTools
    tools)

    data GhdlOptions = GhdlOptions
      { GhdlOptions -> [Text]
    ghdlAnalyseOpts :: [Text]
      , GhdlOptions -> [Text]
    ghdlRunOpts     :: [Text]
      }

    instance Default GhdlOptions where
      def :: GhdlOptions
    def = [Text] -> [Text] -> GhdlOptions
    GhdlOptions [] []

    pprGhdlOptions :: GhdlOptions -> Doc ann
    pprGhdlOptions :: forall ann. GhdlOptions -> Doc ann
    pprGhdlOptions (GhdlOptions [Text]
    aOpts [Text]
    rOpts) =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "analyze_options"
            Text
    "Command line arguments for analysis"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    aOpts))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "run_options"
            Text
    "Command line arguments for simulation"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    rOpts))
        ]

    data IcarusOptions = IcarusOptions
      { IcarusOptions -> [Text]
    icarusOpts      :: [Text]
      , IcarusOptions -> Text
    icarusTimeScale :: Text
      }

    instance Default IcarusOptions where
      def :: IcarusOptions
    def = [Text] -> Text -> IcarusOptions
    IcarusOptions [] Text
    "100fs/100fs"

    pprIcarusOptions :: IcarusOptions -> Doc ann
    pprIcarusOptions :: forall ann. IcarusOptions -> Doc ann
    pprIcarusOptions (IcarusOptions [Text]
    opts Text
    ts) =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "iverilog_options"
            Text
    "Command line options for iverilog"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    opts))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "timescale"
            Text
    "Default timescale for simulation"
            (Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    ts))
        ]

    data ModelsimOptions = ModelsimOptions
      { ModelsimOptions -> [Text]
    msVlogOpts :: [Text]
      , ModelsimOptions -> [Text]
    msVsimOpts :: [Text]
      }

    instance Default ModelsimOptions where
      def :: ModelsimOptions
    def = [Text] -> [Text] -> ModelsimOptions
    ModelsimOptions [] []

    pprModelsimOptions :: ModelsimOptions -> Doc ann
    pprModelsimOptions :: forall ann. ModelsimOptions -> Doc ann
    pprModelsimOptions (ModelsimOptions [Text]
    vlog [Text]
    vsim) =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "vlog_options"
            Text
    "Command line arguments for vlog"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    vlog))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "vsim_options"
            Text
    "Command line arguments for vsim"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    vsim))
        ]

    data QuartusOptions = QuartusOptions
      { QuartusOptions -> Int
    quartusBoardDevIndex :: Int
      , QuartusOptions -> Text
    quartusFamily        :: Text
      , QuartusOptions -> Text
    quartusDevice        :: Text
      , QuartusOptions -> [Text]
    quartusOpts          :: [Text]
      , QuartusOptions -> [Text]
    quartusDseOpts       :: [Text]
      }

    instance Default QuartusOptions where
      def :: QuartusOptions
    def = Int -> Text -> Text -> [Text] -> [Text] -> QuartusOptions
    QuartusOptions Int
    1 Text
    "" Text
    "" [] []

    pprQuartusOptions :: QuartusOptions -> Doc ann
    pprQuartusOptions :: forall ann. QuartusOptions -> Doc ann
    pprQuartusOptions (QuartusOptions Int
    bdi Text
    fam Text
    dev [Text]
    opts [Text]
    dse) =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "board_device_index"
            Text
    "Specify the FPGA's device number in the JTAG chain"
            (Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Int -> Doc ann
    forall ann. Int -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Int
    bdi))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "family"
            Text
    "FPGA family, e.g. Cyclone IV E"
            (Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    fam))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "device"
            Text
    "Device identifier, e.g. EP4CE55F23C8"
            (Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    dev))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "quartus_options"
            Text
    "Command line arguments for Quartus"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    opts))

        , Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "dse_options"
            Text
    "Command line arguments for Design Space Explorer"
            ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    flagList ((Text -> Doc ann) -> [Text] -> [Doc ann]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty [Text]
    dse))
        ]

    data VivadoOptions = VivadoOptions
      { VivadoOptions -> Text
    vivadoPart :: Text
      }

    instance Default VivadoOptions where
      def :: VivadoOptions
    def = Text -> VivadoOptions
    VivadoOptions Text
    ""

    pprVivadoOptions :: VivadoOptions -> Doc ann
    pprVivadoOptions :: forall ann. VivadoOptions -> Doc ann
    pprVivadoOptions (VivadoOptions Text
    part) =
      [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    pyRecord
        [ Text -> Text -> Doc ann -> Doc ann
    forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField
            Text
    "part"
            Text
    "Specify target part by ID, e.g. xc7z020-1clg400c"
            (Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    part))
        ]

    -- Helpers; don't export

    pyPre :: Doc ann
    pyPre :: forall ann. Doc ann
    pyPre = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep
      [ Doc ann
    "import os"
      , Doc ann
    ""
      , Doc ann
    "edam_root = os.path.dirname(os.path.realpath(__file__))"
      , Doc ann
    "work_root = 'build'"
      , Doc ann
    ""
      , Doc ann
    "# TODO Specify the EDA tool to use"
      , Doc ann
    "tool = ''"
      , Doc ann
    ""
      ]

    pyPost :: Doc ann
    pyPost :: forall ann. Doc ann
    pyPost = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep
      [ Doc ann
    ""
      , Doc ann
    "if __name__ == '__main__':"
      , Int -> Doc ann -> Doc ann
    forall ann. Int -> Doc ann -> Doc ann
    indent Int
    4 (Doc ann -> Doc ann) -> Doc ann -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep
          [ Doc ann
    "from edalize import *"
          , Doc ann
    ""
          , Doc ann
    "tool = get_edatool(tool)(edam=edam, work_root=work_root)"
          , Doc ann
    "os.makedirs(work_root)"
          , Doc ann
    "tool.configure()"
          , Doc ann
    "tool.build()"
          ]
      ]

    pyList :: [Doc ann] -> Doc ann
    pyList :: forall ann. [Doc ann] -> Doc ann
    pyList [Doc ann]
    xs = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep [Doc ann
    forall ann. Doc ann
    lbracket, Int -> Doc ann -> Doc ann
    forall ann. Int -> Doc ann -> Doc ann
    indent Int
    4 ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    commaList [Doc ann]
    xs), Doc ann
    forall ann. Doc ann
    rbracket]

    pyRecord :: [Doc ann] -> Doc ann
    pyRecord :: forall ann. [Doc ann] -> Doc ann
    pyRecord [Doc ann]
    xs = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep [Doc ann
    forall ann. Doc ann
    lbrace, Int -> Doc ann -> Doc ann
    forall ann. Int -> Doc ann -> Doc ann
    indent Int
    4 ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    commaList [Doc ann]
    xs), Doc ann
    forall ann. Doc ann
    rbrace]

    pyComment :: Text -> Doc ann
    pyComment :: forall ann. Text -> Doc ann
    pyComment Text
    x = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    hsep [Doc ann
    "#", Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    x]

    pyField :: Text -> Doc ann -> Doc ann
    pyField :: forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    n Doc ann
    x = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    hcat [Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Text -> Doc ann
    forall ann. Text -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty Text
    n), Doc ann
    forall ann. Doc ann
    colon, Doc ann
    forall ann. Doc ann
    space, Doc ann
    x]

    pyDocField :: Text -> Text -> Doc ann -> Doc ann
    pyDocField :: forall ann. Text -> Text -> Doc ann -> Doc ann
    pyDocField Text
    n Text
    d Doc ann
    x = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep [Text -> Doc ann
    forall ann. Text -> Doc ann
    pyComment Text
    d, Text -> Doc ann -> Doc ann
    forall ann. Text -> Doc ann -> Doc ann
    pyField Text
    n Doc ann
    x]

    joinPath :: FilePath -> Doc ann
    joinPath :: forall ann. String -> Doc ann
    joinPath String
    x = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    hcat
      [ Doc ann
    "os.path.join"
      , Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    parens ([Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    hsep ([Doc ann] -> Doc ann) -> [Doc ann] -> Doc ann
    forall a b. (a -> b) -> a -> b
    $ Doc ann -> [Doc ann] -> [Doc ann]
    forall ann. Doc ann -> [Doc ann] -> [Doc ann]
    punctuate Doc ann
    forall ann. Doc ann
    comma [Doc ann
    "edam_root", Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (String -> Doc ann
    forall ann. String -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty String
    x)])
      ]

    flagList :: [Doc ann] -> Doc ann
    flagList :: forall ann. [Doc ann] -> Doc ann
    flagList = Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann
    squotes (Doc ann -> Doc ann)
    -> ([Doc ann] -> Doc ann) -> [Doc ann] -> Doc ann
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    hsep

    commaList :: [Doc ann] -> Doc ann
    commaList :: forall ann. [Doc ann] -> Doc ann
    commaList = [Doc ann] -> Doc ann
    forall ann. [Doc ann] -> Doc ann
    vsep ([Doc ann] -> Doc ann)
    -> ([Doc ann] -> [Doc ann]) -> [Doc ann] -> Doc ann
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Doc ann -> [Doc ann] -> [Doc ann]
    forall ann. Doc ann -> [Doc ann] -> [Doc ann]
    punctuate Doc ann
    forall ann. Doc ann
    comma