capnp-0.17.0.0: cmd/capnpc-haskell/IR/Haskell.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
-- A last-leg intermediate form, before emitting actually Haskell source code.
--
-- This module contains a *simplified* Haskell AST; it only includes the
-- features we actually need. We roll our own for two reasons:
--
-- 1. Full Haskell ASTs are actually quite complex, and the data types exposed
-- by libraries for working with Haskell source reflect this. What we need
-- is much simpler.
-- 2. At some point we'll want to inject Haddock comments into the source (see
-- #32), and I(zenhack) don't see a good way to do that with the libraries
-- I looked at.
module IR.Haskell
( modFilePath,
DataArgs (..),
DataDecl (..),
DataVariant (..),
ClassDecl (..),
Decl (..),
Do (..),
Exp (..),
Export (..),
Import (..),
InstanceDef (..),
Module (..),
Pattern (..),
Type (..),
TypeAlias (..),
ValueDef (..),
)
where
import qualified Data.ByteString.Lazy as LBS
import Data.List (intercalate)
import qualified Data.Text as T
import qualified IR.Common as Common
import qualified IR.Name as Name
-- | A Haskell module
data Module = Module
{ -- | The parts of the module path
modName :: [Name.UnQ],
-- | The language extensions enabled in this module.
modLangPragmas :: [T.Text],
-- | The export list. If it is 'Nothing' that means there is no export
-- list (and therefore everything is exported).
modExports :: Maybe [Export],
-- | The declarations in the module.
modDecls :: [Decl],
-- | Modules to import.
modImports :: [Import]
}
deriving (Show, Read, Eq)
data Export
= ExportMod [Name.UnQ] -- module Foo.Bar
| ExportGCtors Name.GlobalQ -- Foo.Bar.Baz(..)
| ExportLCtors Name.LocalQ -- Baz(..)
| ExportGName Name.GlobalQ -- Foo.Bar.Baz
| ExportLName Name.LocalQ -- Baz
deriving (Show, Read, Eq)
data Import
= ImportAs -- import qualified Foo.Bar as Bar
{ importAs :: Name.UnQ,
parts :: [Name.UnQ]
}
| ImportQual -- import qualified Foo.Bar
{ parts :: [Name.UnQ]
}
| ImportAll -- import Foo.Bar
{ parts :: [Name.UnQ]
}
deriving (Show, Read, Eq)
-- | A declaration.
data Decl
= DcData DataDecl
| DcValue
{ typ :: Type,
def :: ValueDef
}
| DcInstance
{ ctx :: [Type],
typ :: Type,
defs :: [InstanceDef]
}
| DcTypeInstance Type Type
| DcDeriveInstance
{ ctx :: [Type],
typ :: Type
}
| DcClass
{ ctx :: [Type],
name :: Name.LocalQ,
params :: [Name.UnQ],
funDeps :: [(T.Text, T.Text)],
decls :: [ClassDecl]
}
deriving (Show, Read, Eq)
data DataDecl = Data
{ -- | The name of the declared type.
dataName :: Name.UnQ,
typeArgs :: [Type],
-- | The variants/data constructors for the type.
dataVariants :: [DataVariant],
-- | A list of type classes to include in the deriving clause.
derives :: [Name.UnQ],
-- | Whether the declarationis a "newtype" or "data" declaration.
dataNewtype :: !Bool,
-- | If true, this is actually an instance of a data family, rather
-- than a stand-alone type.
dataInstance :: !Bool
}
deriving (Show, Read, Eq)
data ClassDecl
= CdValueDecl Name.UnQ Type
| CdValueDef ValueDef
| -- | A MINIMAL pragma.
CdMinimal [Name.UnQ]
deriving (Show, Read, Eq)
data InstanceDef
= IdValue ValueDef
| IdData DataDecl
| IdType TypeAlias
deriving (Show, Read, Eq)
data TypeAlias = TypeAlias Name.UnQ [Type] Type
deriving (Show, Read, Eq)
data ValueDef = DfValue
{ name :: Name.UnQ,
value :: Exp,
params :: [Pattern]
}
deriving (Show, Read, Eq)
-- | A data constructor
data DataVariant = DataVariant
{ -- | The name of the constructor.
dvCtorName :: Name.UnQ,
dvArgs :: DataArgs
}
deriving (Show, Read, Eq)
-- | Arguments to a data constructor
data DataArgs
= APos [Type]
| ARec [(Name.UnQ, Type)]
deriving (Show, Read, Eq)
data Type
= TGName Name.GlobalQ
| TLName Name.LocalQ
| TVar T.Text
| TApp Type [Type]
| TFn [Type]
| TCtx [Type] Type
| TPrim Common.PrimWord
| TUnit
| TKindAnnotated Type Type
| TString T.Text -- type-level string literal
deriving (Show, Read, Eq)
data Exp
= EVar T.Text
| EApp Exp [Exp]
| -- | "Functorial" application, i.e. f <$> x <*> y <*> z.
EFApp Exp [Exp]
| EGName Name.GlobalQ
| ELName Name.LocalQ
| EInt Integer
| EDo [Do] Exp
| -- | A call to (>>=)
EBind Exp Exp
| ETup [Exp]
| EBytes LBS.ByteString
| ECase Exp [(Pattern, Exp)]
| ETypeAnno Exp Type
| ELambda [Pattern] Exp
| ERecord Exp [(Name.UnQ, Exp)]
| ELabel Name.UnQ
| EList [Exp]
| ETypeApp Exp [Type] -- TypeApplications; f @x @y @z
deriving (Show, Read, Eq)
data Do
= DoBind Name.UnQ Exp
| DoE Exp
deriving (Show, Read, Eq)
data Pattern
= PVar T.Text
| PLCtor Name.LocalQ [Pattern]
| PGCtor Name.GlobalQ [Pattern]
| PInt Integer
| -- | Name{..}
PLRecordWildCard Name.LocalQ
deriving (Show, Read, Eq)
-- | Get the file path for a module. For example, the module @Foo.Bar.Baz@ will
-- have a file path of @Foo/Bar/Baz.hs@.
modFilePath :: Module -> FilePath
modFilePath Module {modName} =
intercalate "/" (map (T.unpack . Name.renderUnQ) modName) ++ ".hs"