{-# 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 Data.List (intercalate) import qualified Data.ByteString.Lazy as LBS import qualified Data.Text as T import qualified IR.Common as Common import qualified IR.Name as Name -- | A Haskell module data Module = Module { modName :: [Name.UnQ] -- ^ The parts of the module path , modLangPragmas :: [T.Text] -- ^ The language extensions enabled in this module. , modExports :: Maybe [Export] -- ^ The export list. If it is 'Nothing' that means there is no export -- list (and therefore everything is exported). , modDecls :: [Decl] -- ^ The declarations in the module. , modImports :: [Import] -- ^ Modules to 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] } | DcClass { ctx :: [Type] , name :: Name.LocalQ , params :: [Name.UnQ] , decls :: [ClassDecl] } deriving(Show, Read, Eq) data DataDecl = Data { dataName :: Name.UnQ -- ^ The name of the declared type. , typeArgs :: [Type] , dataVariants :: [DataVariant] -- ^ The variants/data constructors for the type. , derives :: [Name.UnQ] -- ^ A list of type classes to include in the deriving clause. , dataNewtype :: !Bool -- ^ Whether the declarationis a "newtype" or "data" declaration. } deriving(Show, Read, Eq) data ClassDecl = CdValueDecl Name.UnQ Type | CdValueDef ValueDef | CdMinimal [Name.UnQ] -- ^ A MINIMAL pragma. 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 { dvCtorName :: Name.UnQ -- ^ The name of the constructor. , 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 deriving(Show, Read, Eq) data Exp = EApp Exp [Exp] | EFApp Exp [Exp] -- ^ "Functorial" application, i.e. f <$> x <*> y <*> z. | EGName Name.GlobalQ | ELName Name.LocalQ | EInt Integer | EDo [Do] Exp | EBind Exp Exp -- ^ A call to (>>=) | ETup [Exp] | EBytes LBS.ByteString | ECase Exp [(Pattern, Exp)] | ETypeAnno Exp Type | ELambda [Pattern] Exp | ERecord Exp [(Name.UnQ, Exp)] 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"