hydra-0.15.0: src/main/haskell/Hydra/Protobuf/Serde.hs
-- Note: this is an automatically generated file. Do not edit.
-- | Serialization functions for converting Protocol Buffers v3 AST to abstract expressions
module Hydra.Protobuf.Serde where
import qualified Hydra.Ast as Ast
import qualified Hydra.Lib.Equality as Equality
import qualified Hydra.Lib.Lists as Lists
import qualified Hydra.Lib.Literals as Literals
import qualified Hydra.Lib.Logic as Logic
import qualified Hydra.Lib.Maybes as Maybes
import qualified Hydra.Lib.Strings as Strings
import qualified Hydra.Protobuf.Proto3 as Proto3
import qualified Hydra.Serialization as Serialization
import Prelude hiding (Enum, Ordering, decodeFloat, encodeFloat, fail, map, pure, sum)
import qualified Data.Scientific as Sci
-- | The name of the deprecated option
deprecatedOptionName :: String
deprecatedOptionName = "deprecated"
-- | A special Protobuf option name for descriptions (documentation)
descriptionOptionName :: String
descriptionOptionName = "_description"
-- | Filter out internal options (those whose names start with underscore)
excludeInternalOptions :: [Proto3.Option] -> [Proto3.Option]
excludeInternalOptions opts =
Lists.filter (\opt -> Logic.not (Equality.equal (Maybes.fromMaybe 0 (Strings.maybeCharAt 0 (Proto3.optionName opt))) 95)) opts
-- | Prepend an optional description comment to an expression
optDesc :: Bool -> [Proto3.Option] -> Ast.Expr -> Ast.Expr
optDesc doubleNewline opts expr =
let descs = Lists.filter (\opt -> Equality.equal (Proto3.optionName opt) "_description") opts
in (Maybes.maybe expr (\firstDesc ->
let descValue = Proto3.optionValue firstDesc
descStr =
case descValue of
Proto3.ValueBoolean v0 -> Logic.ifElse v0 "true" "false"
Proto3.ValueString v0 -> v0
commentLines = Lists.map (\line -> Strings.cat2 "// " line) (Strings.lines descStr)
comment = Serialization.cst (Strings.intercalate "\n" commentLines)
sep =
Logic.ifElse doubleNewline (Serialization.doubleNewlineSep [
comment,
expr]) (Serialization.newlineSep [
comment,
expr])
in sep) (Lists.maybeHead descs))
-- | Wrap expressions in a curly-braced block with double-newline separation
protoBlock :: [Ast.Expr] -> Ast.Expr
protoBlock exprs =
Serialization.brackets Serialization.curlyBraces Serialization.fullBlockStyle (Serialization.doubleNewlineSep exprs)
-- | Append a semicolon to an expression
semi :: Ast.Expr -> Ast.Expr
semi e =
Serialization.noSep [
e,
(Serialization.cst ";")]
-- | Convert a definition to an expression
writeDefinition :: Proto3.Definition -> Ast.Expr
writeDefinition def =
case def of
Proto3.DefinitionEnum v0 -> writeEnumDefinition v0
Proto3.DefinitionMessage v0 -> writeMessageDefinition v0
-- | Convert an enum definition to an expression
writeEnumDefinition :: Proto3.EnumDefinition -> Ast.Expr
writeEnumDefinition ed =
let name = Proto3.enumDefinitionName ed
values = Proto3.enumDefinitionValues ed
options = Proto3.enumDefinitionOptions ed
in (optDesc False options (Serialization.spaceSep [
Serialization.cst "enum",
(Serialization.cst (Proto3.unTypeName name)),
(protoBlock (Lists.map writeEnumValue values))]))
-- | Convert an enum value to an expression
writeEnumValue :: Proto3.EnumValue -> Ast.Expr
writeEnumValue ev =
let name = Proto3.enumValueName ev
number = Proto3.enumValueNumber ev
options = Proto3.enumValueOptions ev
in (optDesc False options (semi (Serialization.spaceSep [
Serialization.cst (Proto3.unEnumValueName name),
(Serialization.cst "="),
(Serialization.cst (Literals.showInt32 number))])))
-- | Convert a field to an expression
writeField :: Proto3.Field -> Ast.Expr
writeField f =
let name = Proto3.fieldName f
typ = Proto3.fieldType f
num = Proto3.fieldNumber f
options = Proto3.fieldOptions f
in (optDesc False options (case typ of
Proto3.FieldTypeOneof v0 -> Serialization.spaceSep [
Serialization.cst "oneof",
(Serialization.cst (Proto3.unFieldName name)),
(protoBlock (Lists.map writeField v0))]
Proto3.FieldTypeMap v0 ->
let kt = Proto3.mapTypeKeys v0
vt = Proto3.mapTypeValues v0
in (semi (Serialization.spaceSep (Maybes.cat [
Maybes.pure (writeFieldType typ),
(Maybes.pure (Serialization.cst (Proto3.unFieldName name))),
(Maybes.pure (Serialization.cst "=")),
(Maybes.pure (Serialization.cst (Literals.showInt32 num))),
(writeFieldOptions options)])))
Proto3.FieldTypeRepeated _ -> semi (Serialization.spaceSep (Maybes.cat [
Maybes.pure (writeFieldType typ),
(Maybes.pure (Serialization.cst (Proto3.unFieldName name))),
(Maybes.pure (Serialization.cst "=")),
(Maybes.pure (Serialization.cst (Literals.showInt32 num))),
(writeFieldOptions options)]))
Proto3.FieldTypeSimple _ -> semi (Serialization.spaceSep (Maybes.cat [
Maybes.pure (writeFieldType typ),
(Maybes.pure (Serialization.cst (Proto3.unFieldName name))),
(Maybes.pure (Serialization.cst "=")),
(Maybes.pure (Serialization.cst (Literals.showInt32 num))),
(writeFieldOptions options)]))))
-- | Convert a field option to an expression
writeFieldOption :: Proto3.Option -> Ast.Expr
writeFieldOption opt =
let name = Proto3.optionName opt
value = Proto3.optionValue opt
in (Serialization.spaceSep [
Serialization.cst name,
(Serialization.cst "="),
(writeValue value)])
-- | Convert field options to an optional bracket-enclosed expression
writeFieldOptions :: [Proto3.Option] -> Maybe Ast.Expr
writeFieldOptions opts0 =
let opts = excludeInternalOptions opts0
in (Logic.ifElse (Lists.null opts) Nothing (Maybes.pure (Serialization.bracketList Serialization.inlineStyle (Lists.map writeFieldOption opts))))
-- | Convert a field type to an expression
writeFieldType :: Proto3.FieldType -> Ast.Expr
writeFieldType ftyp =
case ftyp of
Proto3.FieldTypeMap v0 ->
let kt = Proto3.mapTypeKeys v0
vt = Proto3.mapTypeValues v0
in (Serialization.noSep [
Serialization.cst "map",
(Serialization.angleBracesList Serialization.inlineStyle [
writeSimpleType kt,
(writeSimpleType vt)])])
Proto3.FieldTypeRepeated v0 -> Serialization.spaceSep [
Serialization.cst "repeated",
(writeSimpleType v0)]
Proto3.FieldTypeSimple v0 -> writeSimpleType v0
Proto3.FieldTypeOneof _ -> Serialization.cst "oneof"
-- | Convert a file-level option to an expression
writeFileOption :: Proto3.Option -> Ast.Expr
writeFileOption opt =
let name = Proto3.optionName opt
value = Proto3.optionValue opt
in (semi (Serialization.spaceSep [
Serialization.cst "option",
(Serialization.cst name),
(Serialization.cst "="),
(writeValue value)]))
-- | Convert file-level options to an optional newline-separated expression
writeFileOptions :: [Proto3.Option] -> Maybe Ast.Expr
writeFileOptions opts0 =
let opts = excludeInternalOptions opts0
in (Logic.ifElse (Lists.null opts) Nothing (Maybes.pure (Serialization.newlineSep (Lists.map writeFileOption opts))))
-- | Convert a file reference to an import expression
writeImport :: Proto3.FileReference -> Ast.Expr
writeImport ref =
semi (Serialization.spaceSep [
Serialization.cst "import",
(Serialization.cst (Literals.showString (Proto3.unFileReference ref)))])
-- | Convert a message definition to an expression
writeMessageDefinition :: Proto3.MessageDefinition -> Ast.Expr
writeMessageDefinition md =
let name = Proto3.messageDefinitionName md
fields = Proto3.messageDefinitionFields md
options = Proto3.messageDefinitionOptions md
in (optDesc False options (Serialization.spaceSep [
Serialization.cst "message",
(Serialization.cst (Proto3.unTypeName name)),
(protoBlock (Lists.map writeField fields))]))
-- | Convert a proto file to an expression
writeProtoFile :: Proto3.ProtoFile -> Ast.Expr
writeProtoFile pf =
let pkg = Proto3.protoFilePackage pf
imports = Proto3.protoFileImports pf
defs = Proto3.protoFileTypes pf
options = Proto3.protoFileOptions pf
headerSec =
Maybes.pure (Serialization.newlineSep [
semi (Serialization.cst "syntax = \"proto3\""),
(semi (Serialization.spaceSep [
Serialization.cst "package",
(Serialization.cst (Proto3.unPackageName pkg))]))])
importsSec = Logic.ifElse (Lists.null imports) Nothing (Maybes.pure (Serialization.newlineSep (Lists.map writeImport imports)))
options1 = Lists.filter (\opt -> Logic.not (Equality.equal (Proto3.optionName opt) "_description")) options
optionsSec = writeFileOptions options1
defsSec = Logic.ifElse (Lists.null defs) Nothing (Maybes.pure (Serialization.doubleNewlineSep (Lists.map writeDefinition defs)))
in (optDesc True options (Serialization.doubleNewlineSep (Maybes.cat [
headerSec,
importsSec,
optionsSec,
defsSec])))
-- | Convert a scalar type to an expression
writeScalarType :: Proto3.ScalarType -> Ast.Expr
writeScalarType sct =
Serialization.cst (case sct of
Proto3.ScalarTypeBool -> "bool"
Proto3.ScalarTypeBytes -> "bytes"
Proto3.ScalarTypeDouble -> "double"
Proto3.ScalarTypeFixed32 -> "fixed32"
Proto3.ScalarTypeFixed64 -> "fixed64"
Proto3.ScalarTypeFloat -> "float"
Proto3.ScalarTypeInt32 -> "int32"
Proto3.ScalarTypeInt64 -> "int64"
Proto3.ScalarTypeSfixed32 -> "sfixed32"
Proto3.ScalarTypeSfixed64 -> "sfixed64"
Proto3.ScalarTypeSint32 -> "sint32"
Proto3.ScalarTypeSint64 -> "sint64"
Proto3.ScalarTypeString -> "string"
Proto3.ScalarTypeUint32 -> "uint32"
Proto3.ScalarTypeUint64 -> "uint64")
-- | Convert a simple type to an expression
writeSimpleType :: Proto3.SimpleType -> Ast.Expr
writeSimpleType st =
case st of
Proto3.SimpleTypeReference v0 -> Serialization.cst (Proto3.unTypeName v0)
Proto3.SimpleTypeScalar v0 -> writeScalarType v0
-- | Convert a value to an expression
writeValue :: Proto3.Value -> Ast.Expr
writeValue v =
Serialization.cst (case v of
Proto3.ValueBoolean v0 -> Logic.ifElse v0 "true" "false"
Proto3.ValueString v0 -> Literals.showString v0)