capnp-0.13.0.0: cmd/capnpc-haskell/Trans/NewToHaskell.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
module Trans.NewToHaskell
( fileToModules
) where
import qualified Capnp.Repr as R
import Control.Monad (guard)
import Data.String (IsString(fromString))
import Data.Word
import qualified IR.Common as C
import qualified IR.Haskell as Hs
import qualified IR.Name as Name
import qualified IR.New as New
import Trans.ToHaskellCommon
-- | Modules imported by all generated modules.
imports :: [Hs.Import]
imports =
[ Hs.ImportAs { importAs = "R", parts = ["Capnp", "Repr"] }
, Hs.ImportAs { importAs = "RP", parts = ["Capnp", "Repr", "Parsed"] }
, Hs.ImportAs { importAs = "Basics", parts = ["Capnp", "New", "Basics"] }
, Hs.ImportAs { importAs = "OL", parts = ["GHC", "OverloadedLabels"] }
, Hs.ImportAs { importAs = "GH", parts = ["Capnp", "GenHelpers", "New"] }
, Hs.ImportAs { importAs = "C", parts = ["Capnp", "New", "Classes"] }
, Hs.ImportAs { importAs = "Generics", parts = ["GHC", "Generics"] }
]
-- | Modules imported by generated modules that use rpc. We separate these out to
-- avoid a circular import when generating code for rpc.capnp -- which does not
-- contain interfaces, so does not need to import the rpc system -- but which
-- must be imported *by* the rpc system.
rpcImports :: [Hs.Import]
rpcImports =
[ Hs.ImportAs { importAs = "GH", parts = ["Capnp", "GenHelpers", "New", "Rpc"] }
]
fileToModules :: New.File -> [Hs.Module]
fileToModules file =
[ fileToMainModule file
, fileToModuleAlias file
]
fileToMainModule :: New.File -> Hs.Module
fileToMainModule file@New.File{fileName, usesRpc} =
fixImports $ Hs.Module
{ modName = ["Capnp", "Gen"] ++ makeModName fileName ++ ["New"]
, modLangPragmas =
[ "TypeFamilies"
, "DataKinds"
, "DeriveGeneric"
, "DuplicateRecordFields"
, "EmptyDataDeriving"
, "FlexibleInstances"
, "MultiParamTypeClasses"
, "UndecidableInstances"
, "UndecidableSuperClasses"
, "OverloadedLabels"
, "OverloadedStrings"
, "StandaloneDeriving"
, "RecordWildCards"
, "TypeApplications"
, "ScopedTypeVariables"
]
, modExports = Nothing
, modImports = imports ++ (guard usesRpc >> rpcImports)
, modDecls = fileToDecls file
}
fileToModuleAlias :: New.File -> Hs.Module
fileToModuleAlias New.File{fileId,fileName} =
let reExport = ["Capnp", "Gen"] ++ makeModName fileName ++ ["New"]
in Hs.Module
{ modName = idToModule fileId ++ ["New"]
, modLangPragmas = []
, modExports = Just [Hs.ExportMod reExport]
, modImports = [ Hs.ImportAll { parts = reExport } ]
, modDecls = []
}
fileToDecls :: New.File -> [Hs.Decl]
fileToDecls New.File{fileId, decls} =
concatMap (declToDecls fileId) decls
declToDecls :: Word64 -> New.Decl -> [Hs.Decl]
declToDecls thisMod decl =
case decl of
New.TypeDecl {name, nodeId, params, repr, extraTypeInfo} ->
let dataName = Name.localToUnQ name
typeArgs = toTVars params
typ = case typeArgs of
[] -> tuName dataName
_ -> Hs.TApp (tuName dataName) typeArgs
in
[ Hs.DcData Hs.Data
{ dataName
, typeArgs
, dataVariants =
case extraTypeInfo of
Just (New.EnumTypeInfo variants) ->
[ Hs.DataVariant
{ dvCtorName = Name.localToUnQ $ Name.mkSub name variantName
, dvArgs = Hs.APos []
}
| variantName <- variants
]
++
[ declareUnknownVariant name ]
_ -> []
, derives =
case extraTypeInfo of
Just New.EnumTypeInfo {} -> [ "Std_.Eq", "Std_.Show", "Generics.Generic" ]
_ -> []
, dataNewtype = False
, dataInstance = False
}
, Hs.DcTypeInstance
(Hs.TApp (tgName ["R"] "ReprFor") [typ])
(toType repr)
, Hs.DcInstance
{ ctx = []
, typ = Hs.TApp (tgName ["C"] "HasTypeId") [typ]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "typeId"
, params = []
, value = Hs.EInt (fromIntegral nodeId)
}
]
}
] ++
let ctx = paramsContext typeArgs in
case extraTypeInfo of
Just New.StructTypeInfo{nWords, nPtrs} ->
[ Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "TypedStruct") [typ]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "numStructWords"
, params = []
, value = Hs.EInt $ fromIntegral nWords
}
, Hs.IdValue Hs.DfValue
{ name = "numStructPtrs"
, params = []
, value = Hs.EInt $ fromIntegral nPtrs
}
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "Allocate") [typ]
, defs =
[ Hs.IdType $
Hs.TypeAlias "AllocHint" [typ] Hs.TUnit
, Hs.IdValue Hs.DfValue
{ name = "new"
, params = [Hs.PVar "_"]
, value = egName ["C"] "newTypedStruct"
}
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp
(tgName ["C"] "EstimateAlloc")
[ typ, Hs.TApp (tgName ["C"] "Parsed") [typ] ]
, defs = []
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "AllocateList") [typ]
, defs =
[ Hs.IdType $ Hs.TypeAlias "ListAllocHint" [typ] (tStd_ "Int")
, Hs.IdValue Hs.DfValue
{ name = "newList"
, params = []
, value = egName ["C"] "newTypedStructList"
}
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp
(tgName ["C"] "EstimateListAlloc")
[typ, Hs.TApp (tgName ["C"] "Parsed") [typ]]
, defs = []
}
]
Just (New.EnumTypeInfo variants) ->
[ Hs.DcInstance
{ ctx
, typ = Hs.TApp (tStd_ "Enum") [typ]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "toEnum"
, params = [Hs.PVar "n_"]
, value =
Hs.ECase (euName "n_") $
[ ( Hs.PInt i
, Hs.ELName (Name.mkSub name variantName)
)
| (i, variantName) <- zip [0..] variants
] ++
[ ( Hs.PVar "tag_"
, Hs.EApp
(Hs.ELName (unknownVariant name))
[Hs.EApp (eStd_ "fromIntegral") [euName "tag_"]]
)
]
}
, Hs.IdValue Hs.DfValue
{ name = "fromEnum"
, params = [Hs.PVar "value_"]
, value =
Hs.ECase (euName "value_") $
[ ( Hs.PLCtor (Name.mkSub name variantName) []
, Hs.EInt i
)
| (i, variantName) <- zip [0..] variants
] ++
[ ( Hs.PLCtor (unknownVariant name) [Hs.PVar "tag_"]
, Hs.EApp (eStd_ "fromIntegral") [euName "tag_"]
)
]
}
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "IsWord") [typ]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "fromWord"
, params = [Hs.PVar "w_"]
, value = Hs.EApp (eStd_ "toEnum") [Hs.EApp (eStd_ "fromIntegral") [Hs.EVar "w_"]]
}
, Hs.IdValue Hs.DfValue
{ name = "toWord"
, params = [Hs.PVar "v_"]
, value = Hs.EApp (eStd_ "fromIntegral") [Hs.EApp (eStd_ "fromEnum") [Hs.EVar "v_"]]
}
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "Parse") [typ, typ]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "parse"
, params = []
, value = egName ["GH"] "parseEnum"
}
, Hs.IdValue Hs.DfValue
{ name = "encode"
, params = []
, value = egName ["GH"] "encodeEnum"
}
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "AllocateList") [typ]
, defs =
[ Hs.IdType $ Hs.TypeAlias "ListAllocHint" [typ] (tStd_ "Int")
]
}
, Hs.DcInstance
{ ctx
, typ = Hs.TApp (tgName ["C"] "EstimateListAlloc") [typ, typ]
, defs = []
}
]
Just New.InterfaceTypeInfo {methods, supers} ->
defineInterfaceParse name params
++ defineInterfaceServer thisMod name params methods supers
Nothing -> []
New.FieldDecl{containerType, typeParams, fieldName, fieldLocType} ->
let tVars = toTVars typeParams
ctx = paramsContext tVars
labelType = Hs.TString (Name.renderUnQ fieldName)
parentType = Hs.TApp (Hs.TLName containerType) tVars
childType = fieldLocTypeToType thisMod fieldLocType
fieldKind = Hs.TGName $ fieldLocTypeToFieldKind fieldLocType
in
[ Hs.DcInstance
{ ctx
, typ = Hs.TApp
(tgName ["GH"] "HasField")
[labelType, fieldKind, parentType, childType]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "fieldByLabel"
, value = fieldLocTypeToField fieldLocType
, params = []
}
]
}
]
New.UnionDecl{name, typeParams, tagLoc, variants} ->
let tVars = toTVars typeParams
typ = Hs.TApp (Hs.TLName name) tVars
in
Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp (tgName ["GH"] "HasUnion") [typ]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "unionField"
, params = []
, value = fieldLocTypeToField $ C.DataField
tagLoc
(C.PrimWord (C.PrimInt (C.IntType C.Unsigned C.Sz16)))
}
, defineRawData thisMod name tVars variants
, defineInternalWhich name variants
, Hs.IdData Hs.Data
{ dataName = "Which"
, typeArgs = [typ]
, dataVariants = []
, derives = []
, dataNewtype = False
, dataInstance = False
}
]
}
: concatMap (variantToDecls thisMod name typeParams) variants
New.SuperDecl { subName, typeParams, superType } ->
let tVars = toTVars typeParams in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp (tgName ["C"] "Super")
[ typeToType thisMod $ C.PtrType $ C.PtrInterface superType
, Hs.TApp (Hs.TLName subName) tVars
]
, defs = []
}
]
New.MethodDecl
{ interfaceName
, interfaceId
, methodId
, methodInfo = New.MethodInfo
{ typeParams
, methodName
, paramType
, resultType
}
} ->
let tVars = toTVars typeParams in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp
(tgName ["GH"] "HasMethod")
[ Hs.TString (Name.renderUnQ methodName)
, Hs.TApp (Hs.TLName interfaceName) tVars
, compositeTypeToType thisMod paramType
, compositeTypeToType thisMod resultType
]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "methodByLabel"
, params = []
, value = Hs.EApp
(egName ["GH"] "Method")
[ Hs.EInt $ fromIntegral interfaceId
, Hs.EInt $ fromIntegral methodId
]
}
]
}
]
New.ParsedInstanceDecl{ typeName, typeParams, parsedInstances } ->
defineParsedInstances thisMod typeName typeParams parsedInstances
New.ConstDecl { name, value } ->
defineConstant thisMod name value
defineConstant thisMod localName value =
let name = Name.localToUnQ localName in
case value of
C.VoidValue ->
[ Hs.DcValue
{ typ = Hs.TUnit
, def = Hs.DfValue
{ name
, params = []
, value = Hs.ETup []
}
}
]
C.WordValue t v ->
[ Hs.DcValue
{ typ = typeToType thisMod (C.WordType t)
, def = Hs.DfValue
{ name
, params = []
, value = Hs.EApp (egName ["C"] "fromWord") [Hs.EInt (fromIntegral v)]
}
}
]
C.PtrValue t v ->
[ Hs.DcValue
{ typ = Hs.TApp (tgName ["R"] "Raw") [tgName ["GH"] "Const", typeToType thisMod (C.PtrType t)]
, def = Hs.DfValue
{ name
, params = []
, value = Hs.EApp
(egName ["GH"] "getPtrConst")
[Hs.ETypeAnno (Hs.EBytes (makePtrBytes v)) (tgName ["GH"] "ByteString")]
}
}
]
defineRawData thisMod name tVars variants =
Hs.IdData Hs.Data
{ dataName = "RawWhich"
, typeArgs =
[ Hs.TVar "mut_"
, Hs.TApp (Hs.TVar $ Name.renderUnQ $ Name.localToUnQ name) tVars
]
, dataNewtype = False
, dataInstance = False
, dataVariants =
[ Hs.DataVariant
{ dvCtorName =
"RW_" <> Name.localToUnQ (Name.mkSub name variantName)
, dvArgs = Hs.APos
[ Hs.TApp
(tReprName "Raw")
[ Hs.TVar "mut_"
, fieldLocTypeToType thisMod fieldLocType
]
]
}
| New.UnionVariant{variantName, fieldLocType} <- variants
]
++
[ Hs.DataVariant
{ dvCtorName = "RW_" <> Name.localToUnQ (unknownVariant name)
, dvArgs = Hs.APos [tStd_ "Word16"]
}
]
-- TODO: derive Show, Read, Eq, Generic, to be feature complete with the code generated by RawToHaskell.
-- This will require a stand-alone deriving declaration
, derives = []
}
unknownVariant :: Name.LocalQ -> Name.LocalQ
unknownVariant name = Name.mkSub name "unknown'"
rawCtorName :: Name.LocalQ -> Name.UnQ
rawCtorName local = "RW_" <> Name.localToUnQ local
defineInternalWhich structName variants =
Hs.IdValue Hs.DfValue
{ name = "internalWhich"
, params = [Hs.PVar "tag_", Hs.PVar "struct_"]
, value =
Hs.ECase (Hs.ELName "tag_") $
[ ( Hs.PInt $ fromIntegral tagValue
, Hs.EFApp
(euName $ rawCtorName (Name.mkSub structName variantName))
[ Hs.EApp
(egName ["GH"] "readVariant")
[ Hs.ELabel variantName
, euName "struct_"
]
]
)
| New.UnionVariant{tagValue, variantName} <- variants
]
++
[ ( Hs.PVar "_"
, Hs.EApp (eStd_ "pure")
[ Hs.EApp
(euName $ rawCtorName (unknownVariant structName))
[euName "tag_"]
]
)
]
}
variantToDecls thisMod containerType typeParams New.UnionVariant{tagValue, variantName, fieldLocType} =
let tVars = toTVars typeParams
ctx = paramsContext tVars
labelType = Hs.TString (Name.renderUnQ variantName)
parentType = Hs.TApp (Hs.TLName containerType) tVars
childType = fieldLocTypeToType thisMod fieldLocType
fieldKind = Hs.TGName $ fieldLocTypeToFieldKind fieldLocType
in
[ Hs.DcInstance
{ ctx
, typ = Hs.TApp
(tgName ["GH"] "HasVariant")
[labelType, fieldKind, parentType, childType]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "variantByLabel"
, params = []
, value = Hs.EApp
(egName ["GH"] "Variant")
[ fieldLocTypeToField fieldLocType
, Hs.EInt (fromIntegral tagValue)
]
}
]
}
]
paramsContext :: [Hs.Type] -> [Hs.Type]
paramsContext = map paramConstraints
-- | Constraints required for a capnproto type parameter. The returned
-- expression has kind 'Constraint'.
paramConstraints :: Hs.Type -> Hs.Type
paramConstraints t =
Hs.TApp (tgName ["GH"] "TypeParam") [t]
tCapnp :: Word64 -> Name.CapnpQ -> Hs.Type
tCapnp thisMod Name.CapnpQ{local, fileId}
| thisMod == fileId = Hs.TLName local
| otherwise = tgName (map Name.renderUnQ $ idToModule fileId ++ ["New"]) local
fieldLocTypeToType :: Word64 -> C.FieldLocType New.Brand Name.CapnpQ -> Hs.Type
fieldLocTypeToType thisMod = \case
C.VoidField -> Hs.TUnit
C.DataField _ t -> wordTypeToType thisMod t
C.PtrField _ t -> ptrTypeToType thisMod t
C.HereField t -> compositeTypeToType thisMod t
fieldLocTypeToFieldKind :: C.FieldLocType b n -> Name.GlobalQ
fieldLocTypeToFieldKind = \case
C.HereField _ -> gName ["GH"] "Group"
_ -> gName ["GH"] "Slot"
wordTypeToType thisMod = \case
C.EnumType t -> tCapnp thisMod t
C.PrimWord t -> primWordToType t
primWordToType = \case
C.PrimInt t -> intTypeToType t
C.PrimFloat32 -> tStd_ "Float"
C.PrimFloat64 -> tStd_ "Double"
C.PrimBool -> tStd_ "Bool"
intTypeToType (C.IntType sign size) =
let prefix = case sign of
C.Signed -> "Int"
C.Unsigned -> "Word"
in
tStd_ $ fromString $ prefix ++ show (C.sizeBits size)
wordTypeBits = \case
C.EnumType _ -> 16
C.PrimWord (C.PrimInt (C.IntType _ size)) -> C.sizeBits size
C.PrimWord C.PrimFloat32 -> 32
C.PrimWord C.PrimFloat64 -> 64
C.PrimWord C.PrimBool -> 1
ptrTypeToType thisMod = \case
C.ListOf t -> Hs.TApp (tgName ["R"] "List") [typeToType thisMod t]
C.PrimPtr t -> primPtrToType t
C.PtrComposite t -> compositeTypeToType thisMod t
C.PtrInterface t -> interfaceTypeToType thisMod t
C.PtrParam t -> typeParamToType t
typeToType thisMod = \case
C.CompositeType t -> compositeTypeToType thisMod t
C.VoidType -> Hs.TUnit
C.WordType t -> wordTypeToType thisMod t
C.PtrType t -> ptrTypeToType thisMod t
primPtrToType = \case
C.PrimText -> tgName ["Basics"] "Text"
C.PrimData -> tgName ["Basics"] "Data"
C.PrimAnyPtr t -> anyPtrToType t
anyPtrToType :: C.AnyPtr -> Hs.Type
anyPtrToType t = case t of
C.Struct -> basics "AnyStruct"
C.List -> basics "AnyList"
C.Cap -> basics "Capability"
C.Ptr -> Hs.TApp (tStd_ "Maybe") [basics "AnyPointer"]
where
basics = tgName ["Basics"]
compositeTypeToType thisMod (C.StructType name brand) = namedType thisMod name brand
interfaceTypeToType thisMod (C.InterfaceType name brand) = namedType thisMod name brand
typeParamToType = Hs.TVar . Name.typeVarName . C.paramName
namedType :: Word64 -> Name.CapnpQ -> C.ListBrand Name.CapnpQ -> Hs.Type
namedType thisMod name (C.ListBrand []) = tCapnp thisMod name
namedType thisMod name (C.ListBrand args) =
Hs.TApp
(tCapnp thisMod name)
[ typeToType thisMod (C.PtrType t) | t <- args ]
fieldLocTypeToField = \case
C.DataField loc wt ->
let shift = C.dataOff loc
index = C.dataIdx loc
nbits = wordTypeBits wt
defaultValue = C.dataDef loc
in
Hs.EApp
(egName ["GH"] "dataField")
[ Hs.EInt $ fromIntegral shift
, Hs.EInt $ fromIntegral index
, Hs.EInt $ fromIntegral nbits
, Hs.EInt $ fromIntegral defaultValue
]
C.PtrField idx _ ->
Hs.EApp (egName ["GH"] "ptrField") [Hs.EInt $ fromIntegral idx]
C.VoidField ->
egName ["GH"] "voidField"
C.HereField _ ->
egName ["GH"] "groupField"
class ToType a where
toType :: a -> Hs.Type
instance ToType R.Repr where
toType (R.Ptr p) = rApp "Ptr" [toType p]
toType (R.Data d) = rApp "Data" [toType d]
instance ToType a => ToType (Maybe a) where
toType Nothing = tStd_ "Nothing"
toType (Just a) = Hs.TApp (tStd_ "Just") [toType a]
instance ToType R.PtrRepr where
toType R.Cap = tReprName "Cap"
toType (R.List r) = rApp "List" [toType r]
toType R.Struct = tReprName "Struct"
instance ToType R.ListRepr where
toType (R.ListNormal nl) = rApp "ListNormal" [toType nl]
toType R.ListComposite = tReprName "ListComposite"
instance ToType R.NormalListRepr where
toType (R.ListData r) = rApp "ListData" [toType r]
toType R.ListPtr = tReprName "ListPtr"
instance ToType R.DataSz where
toType = tReprName . fromString . show
rApp :: Name.LocalQ -> [Hs.Type] -> Hs.Type
rApp n = Hs.TApp (tReprName n)
tReprName :: Name.LocalQ -> Hs.Type
tReprName = tgName ["R"]
declareUnknownVariant :: Name.LocalQ -> Hs.DataVariant
declareUnknownVariant name = Hs.DataVariant
{ dvCtorName = Name.localToUnQ $ Name.mkSub name "unknown'"
, dvArgs = Hs.APos [tStd_ "Word16"]
}
defineParsedInstances :: Word64 -> Name.LocalQ -> [Name.UnQ] -> New.ParsedInstances -> [Hs.Decl]
defineParsedInstances thisMod typeName typeParams instanceInfo =
concatMap (\f -> f typeName typeParams instanceInfo)
[ defineParsed thisMod
, defineParse
, defineMarshal
]
defineParsed :: Word64 -> Name.LocalQ -> [Name.UnQ] -> New.ParsedInstances -> [Hs.Decl]
defineParsed thisMod typeName typeParams instanceInfo =
let tVars = map (Hs.TVar . Name.typeVarName) typeParams
typ = Hs.TApp (Hs.TLName typeName) tVars
parsedTy = case instanceInfo of
New.ParsedStruct{} -> typ
New.ParsedUnion{} -> Hs.TApp (tgName ["GH"] "Which") [typ]
in
Hs.DcData Hs.Data
{ dataName = "C.Parsed"
, typeArgs = [parsedTy]
, derives = [ "Generics.Generic" ]
, dataNewtype = False
, dataInstance = True
, dataVariants =
case instanceInfo of
New.ParsedStruct { fields, hasUnion, dataCtorName } ->
[ Hs.DataVariant
{ dvCtorName = Name.localToUnQ dataCtorName
, dvArgs = Hs.ARec $
[ ( name
, Hs.TApp
(tgName ["RP"] "Parsed")
[fieldLocTypeToType thisMod typ]
)
| (name, typ) <- fields
] ++
[ ( "union'"
, Hs.TApp (tgName ["C"] "Parsed")
[Hs.TApp (tgName ["GH"] "Which") [typ]]
)
| hasUnion
]
}
]
New.ParsedUnion { variants } ->
[ Hs.DataVariant
{ dvCtorName = Name.localToUnQ $ Name.mkSub typeName name
, dvArgs = case ftype of
C.VoidField -> Hs.APos []
_ -> Hs.APos
[ Hs.TApp
(tgName ["RP"] "Parsed")
[fieldLocTypeToType thisMod ftype]
]
}
| (name, ftype) <- variants
]
++
[ declareUnknownVariant typeName ]
}
:
[ Hs.DcDeriveInstance
[ Hs.TApp (tStd_ cls) [Hs.TApp (tgName ["RP"] "Parsed") [v]]
| v <- tVars
]
(Hs.TApp (tStd_ cls) [Hs.TApp (tgName ["C"] "Parsed") [parsedTy]])
| cls <- ["Show", "Eq"]
]
defineParse :: Name.LocalQ -> [Name.UnQ] -> New.ParsedInstances -> [Hs.Decl]
defineParse typeName typeParams New.ParsedStruct { fields, hasUnion, dataCtorName } =
let tVars = toTVars typeParams
typ = Hs.TApp (Hs.TLName typeName) tVars
in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp (tgName ["C"] "Parse") [typ, Hs.TApp (tgName ["C"] "Parsed") [typ]]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "parse"
, params = [Hs.PVar "raw_"]
, value = Hs.EFApp (Hs.ELName dataCtorName) $
[ Hs.EApp
(egName ["GH"] "parseField")
[Hs.ELabel field, euName "raw_"]
| field <- map fst fields
]
++
if hasUnion then
[ Hs.EApp
(egName ["C"] "parse")
[Hs.EApp (egName ["GH"] "structUnion") [euName "raw_"]]
]
else
[]
}
]
}
]
defineParse typeName typeParams New.ParsedUnion{ variants } =
let tVars = toTVars typeParams
typ = Hs.TApp (tgName ["GH"] "Which") [Hs.TApp (Hs.TLName typeName) tVars]
in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp (tgName ["C"] "Parse") [typ, Hs.TApp (tgName ["C"] "Parsed") [typ]]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "parse"
, params = [Hs.PVar "raw_"]
, value = Hs.EDo
[ Hs.DoBind "rawWhich_" $ Hs.EApp (egName ["GH"] "unionWhich") [euName "raw_"]
]
(Hs.ECase (euName "rawWhich_") $
[ let ctorName = Name.mkSub typeName variantName in
case fieldLocType of
C.VoidField ->
( puName (rawCtorName ctorName) [Hs.PVar "_"]
, Hs.EApp (eStd_ "pure") [Hs.ELName ctorName]
)
_ ->
( puName (rawCtorName ctorName) [Hs.PVar "rawArg_"]
, Hs.EFApp
(Hs.ELName ctorName)
[Hs.EApp (egName ["C"] "parse") [euName "rawArg_"]]
)
| (variantName, fieldLocType) <- variants
]
++
[ let ctorName = unknownVariant typeName in
( puName (rawCtorName ctorName) [Hs.PVar "tag_"]
, Hs.EApp
(eStd_ "pure")
[Hs.EApp (Hs.ELName ctorName) [euName "tag_"]]
)
]
)
}
]
}
]
defineInterfaceParse typeName typeParams =
let tVars = toTVars typeParams
typ = Hs.TApp (Hs.TLName typeName) tVars
in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp (tgName ["C"] "Parse") [typ, Hs.TApp (tgName ["GH"] "Client") [typ]]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "parse"
, params = []
, value = egName ["GH"] "parseCap"
}
, Hs.IdValue Hs.DfValue
{ name = "encode"
, params = []
, value = egName ["GH"] "encodeCap"
}
]
}
]
defineMarshal :: Name.LocalQ -> [Name.UnQ] -> New.ParsedInstances -> [Hs.Decl]
defineMarshal typeName typeParams New.ParsedStruct { fields, hasUnion, dataCtorName } =
let tVars = toTVars typeParams
typ = Hs.TApp (Hs.TLName typeName) tVars
in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp
(tgName ["C"] "Marshal")
[typ, Hs.TApp (tgName ["C"] "Parsed") [typ]]
, defs =
[ if null fields && not hasUnion then
-- We need to special case this, since otherwise GHC will complain about
-- the record wildcard pattern on a ctor with no arguments.
Hs.IdValue Hs.DfValue
{ name = "marshalInto"
, params = [ Hs.PVar "_raw", Hs.PLCtor dataCtorName [] ]
, value = Hs.EApp (eStd_ "pure") [Hs.ETup []]
}
else
Hs.IdValue Hs.DfValue
{ name = "marshalInto"
, params =
[ Hs.PVar "raw_", Hs.PLRecordWildCard dataCtorName]
, value = Hs.EDo
(map (Hs.DoE . uncurry emitMarshalField) fields)
(if hasUnion then
Hs.EApp (egName ["C"] "marshalInto")
[ Hs.EApp (egName ["GH"] "structUnion") [euName "raw_"]
, euName "union'"
]
else
Hs.EApp (eStd_ "pure") [Hs.ETup []]
)
}
]
}
]
defineMarshal typeName typeParams New.ParsedUnion { variants } =
let tVars = toTVars typeParams
typ = Hs.TApp (tgName ["GH"] "Which") [Hs.TApp (Hs.TLName typeName) tVars]
in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp
(tgName ["C"] "Marshal")
[typ, Hs.TApp (tgName ["C"] "Parsed") [typ]]
, defs =
[ Hs.IdValue Hs.DfValue
{ name = "marshalInto"
, params = [ Hs.PVar "raw_", Hs.PVar "parsed_" ]
, value = Hs.ECase (Hs.EVar "parsed_") $
[ ( Hs.PLCtor (Name.mkSub typeName name) $
case fieldLocType of
C.VoidField -> []
_ -> [Hs.PVar "arg_"]
, emitMarshalVariant name fieldLocType
)
| (name, fieldLocType) <- variants
] ++
[ ( Hs.PLCtor (unknownVariant typeName) [Hs.PVar "tag_"]
, Hs.EApp
(egName ["GH"] "encodeField")
[ egName ["GH"] "unionField"
, Hs.EVar "tag_"
, unionStruct (euName "raw_")
]
)
]
}
]
}
]
defineInterfaceServer thisMod typeName typeParams methods supers =
let tVars = toTVars typeParams
typ = Hs.TApp (Hs.TLName typeName) tVars
clsName = Name.mkSub typeName "server_"
in
[ Hs.DcInstance
{ ctx = paramsContext tVars
, typ = Hs.TApp (tgName ["GH"] "Export") [typ]
, defs =
[ Hs.IdType $ Hs.TypeAlias "Server" [typ] $ Hs.TApp (Hs.TLName clsName) tVars
, Hs.IdValue Hs.DfValue
{ name = "methodHandlerTree"
, params = [Hs.PVar "_", Hs.PVar "s_"]
, value =
Hs.EApp (egName ["GH"] "MethodHandlerTree")
[ Hs.ETypeApp (egName ["C"] "typeId") [typ]
, Hs.EList
[ Hs.EApp
(egName ["GH"] "toUntypedMethodHandler")
[ Hs.EApp
(Hs.ETypeApp
(Hs.EVar (Name.renderUnQ (Name.valueName (Name.mkSub typeName methodName))))
tVars
)
[Hs.EVar "s_"]
]
| New.MethodInfo{methodName} <- methods
]
, Hs.EList
[ Hs.EApp (egName ["GH"] "methodHandlerTree")
[ Hs.ETypeApp
(egName ["GH"] "Proxy")
[typeToType thisMod $ C.PtrType $ C.PtrInterface super]
, Hs.EVar "s_"
]
| super <- supers
]
]
}
]
}
, Hs.DcClass
{ ctx =
[ Hs.TApp (tgName ["GH"] "Server")
[ typeToType thisMod $ C.PtrType $ C.PtrInterface super
, Hs.TVar "s_"
]
| super <- supers
]
, name = clsName
, params = map (Name.UnQ . Name.typeVarName) typeParams ++ ["s_"]
, funDeps = []
, decls =
Hs.CdMinimal
[ mkMethodName typeName methodName
| New.MethodInfo{methodName} <- methods
]
: concatMap (defineIfaceClassMethod thisMod typeName) methods
}
]
defineIfaceClassMethod thisMod typeName New.MethodInfo{methodName, paramType, resultType} =
let mkType t = typeToType thisMod (C.CompositeType t)
name = mkMethodName typeName methodName
in
[ Hs.CdValueDecl
name
(Hs.TFn
[ Hs.TVar "s_"
, Hs.TApp
(tgName ["GH"] "MethodHandler")
[ mkType paramType
, mkType resultType
]
]
)
, Hs.CdValueDef Hs.DfValue
{ name
, params = [Hs.PVar "_"]
, value = egName ["GH"] "methodUnimplemented"
}
]
mkMethodName typeName methodName =
Name.valueName (Name.mkSub typeName methodName)
emitMarshalField :: Name.UnQ -> C.FieldLocType New.Brand Name.CapnpQ -> Hs.Exp
emitMarshalField name (C.HereField _) =
Hs.EDo
[ Hs.DoBind "group_" $ Hs.EApp
(egName ["GH"] "readField")
[Hs.ELabel name, Hs.EVar "raw_"]
]
(Hs.EApp (egName ["C"] "marshalInto") [Hs.EVar "group_", euName name])
emitMarshalField name _ =
Hs.EApp (egName ["GH"] "encodeField")
[ Hs.ELabel name
, euName name
, euName "raw_"
]
emitMarshalVariant :: Name.UnQ -> C.FieldLocType New.Brand Name.CapnpQ -> Hs.Exp
emitMarshalVariant name (C.HereField _) = Hs.EDo
[ Hs.DoBind "rawGroup_" $
Hs.EApp (egName ["GH"] "initVariant")
[ Hs.ELabel name
, unionStruct (euName "raw_")
]
]
(Hs.EApp (egName ["C"] "marshalInto") [euName "rawGroup_", euName "arg_"])
emitMarshalVariant name C.VoidField =
Hs.EApp (egName ["GH"] "encodeVariant")
[ Hs.ELabel name
, Hs.ETup []
, unionStruct (euName "raw_")
]
emitMarshalVariant name _ =
Hs.EApp (egName ["GH"] "encodeVariant")
[ Hs.ELabel name
, euName "arg_"
, unionStruct (euName "raw_")
]
unionStruct :: Hs.Exp -> Hs.Exp
unionStruct e = Hs.EApp (egName ["GH"] "unionStruct") [e]