mirror of
https://github.com/zap-proto/haskell.git
synced 2026-10-30 15:05:00 +00:00
..rather than BS.pack [0,1,2,...] This makes a *dramatic* difference on both the (haskell source) size and (ghc) build time of the modules generated from the sandstorm schema. One particularly pathological example: sandstorm's mime.capnp is dominated by one giant table in the form of a constant declaration, with both keys and values being Text. The source file is about 56KiB. The size of the output, with the old version of the code generator, was almost 4MiB! The new output size is 196KiB, which is much more reasonable. Build time for that file is now quite fast, whereas before it was one of the slowest ones. Part of the problem is the way we were pretty-printing things, which could have been solved in other ways, but this will also improve the size of constants that are mostly text, even without that. I also suspect this will improve build times more than just fixing the pretty-printing would.
198 lines
5.1 KiB
Haskell
198 lines
5.1 KiB
Haskell
{-# 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"
|