{-|
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 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)
import Data.Text.Prettyprint.Doc

-- | 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 :: 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 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 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 (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 -> FilePath
efName        :: FilePath
  , EdamFile -> EdamFileType
efType        :: EdamFileType
  , EdamFile -> Text
efLogicalName :: Text
  }

pprFile :: EdamFile -> Doc ann
pprFile :: EdamFile -> Doc ann
pprFile (EdamFile FilePath
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
$ FilePath -> Doc ann
forall ann. FilePath -> Doc ann
joinPath FilePath
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 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
/= :: EdamFileType -> EdamFileType -> Bool
$c/= :: EdamFileType -> EdamFileType -> Bool
== :: EdamFileType -> EdamFileType -> Bool
$c== :: EdamFileType -> EdamFileType -> Bool
Eq, Int -> EdamFileType -> ShowS
[EdamFileType] -> ShowS
EdamFileType -> FilePath
(Int -> EdamFileType -> ShowS)
-> (EdamFileType -> FilePath)
-> ([EdamFileType] -> ShowS)
-> Show EdamFileType
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [EdamFileType] -> ShowS
$cshowList :: [EdamFileType] -> ShowS
show :: EdamFileType -> FilePath
$cshow :: EdamFileType -> FilePath
showsPrec :: Int -> EdamFileType -> ShowS
$cshowsPrec :: Int -> EdamFileType -> ShowS
Show)

pprFileType :: EdamFileType -> Doc ann
pprFileType :: 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 :: 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 :: 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 :: 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 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 :: 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 :: 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 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 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 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap 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 :: 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 a ann. Pretty a => a -> Doc ann
pretty Text
part))
    ]

-- Helpers; don't export

pyPre :: Doc ann
pyPre :: 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 :: 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 :: [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 :: [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 :: Text -> Doc ann
pyComment Text
x = [Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
hsep [Doc ann
"#", Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
x]

pyField :: Text -> Doc ann -> Doc ann
pyField :: 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 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 :: 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 :: FilePath -> Doc ann
joinPath FilePath
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 (FilePath -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty FilePath
x)])
  ]

flagList :: [Doc ann] -> Doc ann
flagList :: [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 :: [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