capnp-0.17.0.0: cmd/capnpc-haskell/Trans/FlatToAbstractOp.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
module Trans.FlatToAbstractOp (cgrToFiles) where
import qualified Capnp.Repr as R
import Data.Bifunctor (Bifunctor (..))
import Data.Maybe (isJust)
import qualified IR.AbstractOp as AO
import qualified IR.Common as C
import qualified IR.Flat as Flat
import qualified IR.Name as Name
cgrToFiles :: Flat.CodeGenReq -> [AO.File]
cgrToFiles = map fileToFile . Flat.reqFiles
fileToFile :: Flat.File -> AO.File
fileToFile Flat.File {fileId, fileName, nodes} =
AO.File
{ fileId,
fileName,
decls = concatMap nodeToDecls nodes,
usesRpc = not $ null [() | Flat.Node {union_ = Flat.Interface {}} <- nodes]
}
mapTypes :: (Bifunctor p, Functor f) => p (f Flat.Node) Flat.Node -> p (f Name.CapnpQ) Name.CapnpQ
mapTypes = C.bothMap (\Flat.Node {name} -> name)
nodeToDecls :: Flat.Node -> [AO.Decl]
nodeToDecls Flat.Node {nodeId, name = Name.CapnpQ {local}, typeParams, union_} =
let mkType repr extraTypeInfo =
AO.TypeDecl
{ name = local,
nodeId,
params = map C.paramName typeParams,
repr,
extraTypeInfo
}
mkField field =
fieldToDecl local typeParams field
mkMethodInfo Flat.Method {name, paramType, resultType} =
AO.MethodInfo
{ typeParams = map C.paramName typeParams,
methodName = name,
paramType = mapTypes paramType,
resultType = mapTypes resultType
}
parsedStructNode fields hasUnion isGroup =
AO.ParsedInstanceDecl
{ typeName = local,
typeParams = map C.paramName typeParams,
parsedInstances =
AO.ParsedStruct
{ fields =
[ ( Name.getUnQ fieldName,
mapTypes fieldLocType
)
| Flat.Field {fieldName, fieldLocType} <- fields
],
hasUnion,
dataCtorName = dataCtorName isGroup
}
}
parsedUnionNode Flat.Union {variants} =
AO.ParsedInstanceDecl
{ typeName = local,
typeParams = map C.paramName typeParams,
parsedInstances =
AO.ParsedUnion
{ variants =
[ ( Name.getUnQ fieldName,
mapTypes fieldLocType
)
| Flat.Variant {field = Flat.Field {fieldName, fieldLocType}} <- variants
]
}
}
dataCtorName isGroup
| isGroup = Name.mkSub local ""
| otherwise = local
structUnionNodes Nothing = []
structUnionNodes (Just union@Flat.Union {tagOffset, variants}) =
[ AO.UnionDecl
{ name = local,
typeParams = map C.paramName typeParams,
tagLoc =
C.DataLoc
{ dataIdx = fromIntegral $ tagOffset `div` 4,
dataOff = fromIntegral $ (tagOffset `mod` 4) * 16,
dataDef = 0
},
variants = map variantToVariant variants
},
parsedUnionNode union
]
in case union_ of
Flat.Other -> []
Flat.Constant {value} ->
[AO.ConstDecl {name = local, value = mapTypes value}]
Flat.Enum enumerants ->
[mkType (R.Data R.Sz16) $ Just $ AO.EnumTypeInfo enumerants]
Flat.Interface {methods, supers} ->
let methodInfos = map mkMethodInfo methods
superTypes = map mapTypes supers
in mkType
(R.Ptr (Just R.Cap))
( Just
AO.InterfaceTypeInfo
{ methods = methodInfos,
supers = superTypes
}
)
: [ AO.SuperDecl
{ subName = local,
typeParams = map C.paramName typeParams,
superType = superType
}
| superType <- superTypes
]
++ [ AO.MethodDecl
{ interfaceName = local,
interfaceId = nodeId,
methodId,
methodInfo
}
| (methodId, methodInfo) <- zip [0 ..] methodInfos
]
Flat.Struct {isGroup, fields, union, dataWordCount = nWords, pointerCount = nPtrs} ->
mkType (R.Ptr (Just R.Struct)) (Just AO.StructTypeInfo {nWords, nPtrs})
: parsedStructNode fields (isJust union) isGroup
: (structUnionNodes union ++ map mkField fields)
fieldToDecl :: Name.LocalQ -> [C.TypeParamRef Flat.Node] -> Flat.Field -> AO.Decl
fieldToDecl containerType typeParams Flat.Field {fieldName, fieldLocType} =
AO.FieldDecl
{ containerType,
typeParams = map C.paramName typeParams,
fieldName = Name.getUnQ fieldName,
fieldLocType = mapTypes fieldLocType
}
variantToVariant :: Flat.Variant -> AO.UnionVariant
variantToVariant Flat.Variant {tagValue, field = Flat.Field {fieldName, fieldLocType}} =
AO.UnionVariant
{ variantName = Name.getUnQ fieldName,
tagValue,
fieldLocType = mapTypes fieldLocType
}