packages feed

hydra-haskell-0.17.0: src/main/haskell/Hydra/Haskell/Serde.hs

-- Note: this is an automatically generated file. Do not edit.

-- | Haskell operator precendence and associativity are drawn from:
-- | https://self-learning-java-tutorial.blogspot.com/2016/04/haskell-operator-precedence.html
-- | Other operators were investigated using GHCi, e.g. ":info (->)"
-- | Operator names are drawn (loosely) from:
-- | https://stackoverflow.com/questions/7746894/are-there-pronounceable-names-for-common-haskell-operators

module Hydra.Haskell.Serde where

import qualified Hydra.Ast as Ast
import qualified Hydra.Coders as Coders
import qualified Hydra.Constants as Constants
import qualified Hydra.Core as Core
import qualified Hydra.Docs as Docs
import qualified Hydra.Error.Checking as Checking
import qualified Hydra.Error.Core as ErrorCore
import qualified Hydra.Error.File as ErrorFile
import qualified Hydra.Error.Packaging as ErrorPackaging
import qualified Hydra.Error.System as ErrorSystem
import qualified Hydra.Errors as Errors
import qualified Hydra.File as File
import qualified Hydra.Graph as Graph
import qualified Hydra.Haskell.Operators as Operators
import qualified Hydra.Haskell.Syntax as Syntax
import qualified Hydra.Json.Model as Model
import qualified Hydra.Overlay.Haskell.Lib.Equality as Equality
import qualified Hydra.Overlay.Haskell.Lib.Lists as Lists
import qualified Hydra.Overlay.Haskell.Lib.Literals as Literals
import qualified Hydra.Overlay.Haskell.Lib.Logic as Logic
import qualified Hydra.Overlay.Haskell.Lib.Optionals as Optionals
import qualified Hydra.Overlay.Haskell.Lib.Strings as Strings
import qualified Hydra.Names as Names
import qualified Hydra.Packaging as Packaging
import qualified Hydra.Parsing as Parsing
import qualified Hydra.Paths as Paths
import qualified Hydra.Query as Query
import qualified Hydra.Relational as Relational
import qualified Hydra.Serialization as Serialization
import qualified Hydra.Show.Docs as ShowDocs
import qualified Hydra.System as System
import qualified Hydra.Tabular as Tabular
import qualified Hydra.Testing as Testing
import qualified Hydra.Time as Time
import qualified Hydra.Topology as Topology
import qualified Hydra.Typed as Typed
import qualified Hydra.Typing as Typing
import qualified Hydra.Util as Util
import qualified Hydra.Validation as Validation
import qualified Hydra.Variants as Variants
import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, map, pure, sum)
import qualified Data.Scientific as Sci

-- | Convert a pattern-matching alternative to an AST expression
alternativeToExpr :: Syntax.Alternative -> Ast.Expr
alternativeToExpr alt =
    Serialization.structuralSpaceSep [
      patternToExpr (Syntax.alternativePattern alt),
      (Serialization.cst "->"),
      (caseRhsToExpr (Syntax.alternativeRhs alt))]

-- | Convert a function application expression to an AST expression
applicationExpressionToExpr :: Syntax.ApplicationExpression -> Ast.Expr
applicationExpressionToExpr app =
    Serialization.ifx Operators.appOp (expressionToExpr (Syntax.applicationExpressionFunction app)) (expressionToExpr (Syntax.applicationExpressionArgument app))

-- | Convert an application pattern to an AST expression
applicationPatternToExpr :: Syntax.ApplicationPattern -> Ast.Expr
applicationPatternToExpr appPat =

      let name = Syntax.applicationPatternName appPat
          pats = Syntax.applicationPatternArgs appPat
      in (Serialization.spaceSep (Lists.cons (nameToExpr name) (Lists.map patternToExpr pats)))

-- | Convert a case expression to an AST expression
caseExpressionToExpr :: Syntax.CaseExpression -> Ast.Expr
caseExpressionToExpr caseExpr =

      let cs = Syntax.caseExpressionCase caseExpr
          alts = Syntax.caseExpressionAlternatives caseExpr
          ofOp =
                  Ast.Op {
                    Ast.opSymbol = (Ast.Symbol "of"),
                    Ast.opPadding = Ast.Padding {
                      Ast.paddingLeft = Ast.WsSpace,
                      Ast.paddingRight = (Ast.WsBreakAndIndent "  ")},
                    Ast.opPrecedence = (Ast.Precedence 0),
                    Ast.opAssociativity = Ast.AssociativityNone}
          lhs =
                  Serialization.spaceSep [
                    Serialization.cst "case",
                    (expressionToExpr cs)]
          rhs = Serialization.newlineSep (Lists.map alternativeToExpr alts)
      in (Serialization.ifx ofOp lhs rhs)

-- | Convert a case right-hand side to an AST expression
caseRhsToExpr :: Syntax.CaseRhs -> Ast.Expr
caseRhsToExpr rhs = expressionToExpr (Syntax.unCaseRhs rhs)

-- | Convert a class constraint to an AST expression
classConstraintToExpr :: Syntax.ClassConstraint -> Ast.Expr
classConstraintToExpr clsAsrt =

      let name = Syntax.classConstraintName clsAsrt
          types = Syntax.classConstraintTypes clsAsrt
      in (Serialization.spaceSep (Lists.cons (nameToExpr name) [
        Serialization.commaSep Serialization.halfBlockStyle (Lists.map typeToExpr types)]))

-- | Convert a type class constraint to an AST expression
constraintToExpr :: Syntax.Constraint -> Ast.Expr
constraintToExpr sert =
    case sert of
      Syntax.ConstraintClass v0 -> classConstraintToExpr v0
      Syntax.ConstraintTuple v0 -> Serialization.parenList False (Lists.map constraintToExpr v0)

-- | Convert a data constructor to an AST expression
constructorToExpr :: Syntax.Constructor -> Ast.Expr
constructorToExpr cons =

      let mc =
              case cons of
                Syntax.ConstructorOrdinary v0 -> Syntax.positionalConstructorComments v0
                Syntax.ConstructorRecord v0 -> Syntax.recordConstructorComments v0
          body =
                  case cons of
                    Syntax.ConstructorOrdinary v0 ->
                      let name = Syntax.positionalConstructorName v0
                          types = Syntax.positionalConstructorFields v0
                      in (Serialization.spaceSep (Lists.cons (nameToExpr name) [
                        Serialization.spaceSep (Lists.map typeToExpr types)]))
                    Syntax.ConstructorRecord v0 ->
                      let name = Syntax.recordConstructorName v0
                          fields = Syntax.recordConstructorFields v0
                      in (Serialization.spaceSep (Lists.cons (nameToExpr name) [
                        Serialization.curlyBracesList Nothing Serialization.halfBlockStyle (Lists.map fieldToExpr fields)]))
      in (Optionals.cases mc body (\c -> Serialization.newlineSep (Lists.cons (Serialization.cst (toHaskellComments c)) [
        body])))

-- | Convert a data/newtype keyword to an AST expression
dataKeywordToExpr :: Syntax.DataKeyword -> Ast.Expr
dataKeywordToExpr kw =
    case kw of
      Syntax.DataKeywordData -> Serialization.cst "data"
      Syntax.DataKeywordNewtype -> Serialization.cst "newtype"

-- | Convert a declaration head to an AST expression
declarationHeadToExpr :: Syntax.DeclarationHead -> Ast.Expr
declarationHeadToExpr hd =
    case hd of
      Syntax.DeclarationHeadApplication v0 ->
        let fun = Syntax.applicationDeclarationHeadFunction v0
            op = Syntax.applicationDeclarationHeadOperand v0
        in (Serialization.spaceSep (Lists.cons (declarationHeadToExpr fun) [
          variableToExpr op]))
      Syntax.DeclarationHeadSimple v0 -> nameToExpr v0

-- | Convert a declaration to an AST expression
declarationToExpr :: Syntax.Declaration -> Ast.Expr
declarationToExpr decl =

      let mc =
              case decl of
                Syntax.DeclarationData v0 -> Syntax.dataDeclarationComments v0
                Syntax.DeclarationType v0 -> Syntax.typeSynonymDeclarationComments v0
                Syntax.DeclarationValueBinding v0 -> case v0 of
                  Syntax.ValueBindingSimple v1 -> Syntax.simpleValueBindingComments v1
                Syntax.DeclarationTypedBinding v0 -> Syntax.typedBindingComments v0
          body =
                  case decl of
                    Syntax.DeclarationData v0 ->
                      let kw = Syntax.dataDeclarationKeyword v0
                          hd = Syntax.dataDeclarationHead v0
                          cons = Syntax.dataDeclarationConstructors v0
                          deriv = Syntax.dataDeclarationDeriving v0
                          derivCat = Lists.concat (Lists.map Syntax.unDerivingClause deriv)
                          constructors = Serialization.orSep Serialization.halfBlockStyle (Lists.map constructorToExpr cons)
                          derivingClause =
                                  Logic.ifElse (Lists.null derivCat) [] [
                                    Serialization.spaceSep (Lists.cons (Serialization.cst "deriving") [
                                      Serialization.parenList False (Lists.map nameToExpr derivCat)])]
                          mainParts =
                                  [
                                    Serialization.spaceSep (Lists.cons (dataKeywordToExpr kw) (Lists.cons (declarationHeadToExpr hd) [
                                      Serialization.cst "="])),
                                    constructors]
                      in (Serialization.indentBlock (Lists.concat2 mainParts derivingClause))
                    Syntax.DeclarationType v0 ->
                      let hd = Syntax.typeSynonymDeclarationName v0
                          typ = Syntax.typeSynonymDeclarationType v0
                      in (Serialization.spaceSep (Lists.cons (Serialization.cst "type") (Lists.cons (declarationHeadToExpr hd) (Lists.cons (Serialization.cst "=") [
                        typeToExpr typ]))))
                    Syntax.DeclarationValueBinding v0 -> valueBindingToExpr v0
                    Syntax.DeclarationTypedBinding v0 ->
                      let typeSig = Syntax.typedBindingTypeSignature v0
                          vb = Syntax.typedBindingValueBinding v0
                          name = Syntax.typeSignatureName typeSig
                          htype = Syntax.typeSignatureType typeSig
                      in (Serialization.newlineSep (Lists.cons (Serialization.structuralSpaceSep [
                        nameToExpr name,
                        (Serialization.cst "::"),
                        (typeToExpr htype)]) [
                        valueBindingToExpr vb]))
      in (Optionals.cases mc body (\c -> Serialization.newlineSep (Lists.cons (Serialization.cst (toHaskellComments c)) [
        body])))

-- | Convert a Haskell expression to an AST expression
expressionToExpr :: Syntax.Expression -> Ast.Expr
expressionToExpr expr =
    case expr of
      Syntax.ExpressionApplication v0 -> applicationExpressionToExpr v0
      Syntax.ExpressionCase v0 -> caseExpressionToExpr v0
      Syntax.ExpressionConstructRecord v0 -> recordExpressionToExpr v0
      Syntax.ExpressionDo v0 -> Serialization.indentBlock (Lists.cons (Serialization.cst "do") (Lists.map statementToExpr v0))
      Syntax.ExpressionIf v0 -> ifExpressionToExpr v0
      Syntax.ExpressionLiteral v0 -> literalToExpr v0
      Syntax.ExpressionLambda v0 -> Serialization.parenthesize (lambdaExpressionToExpr v0)
      Syntax.ExpressionLet v0 ->
        let bindings = Syntax.letExpressionBindings v0
            inner = Syntax.letExpressionInner v0
            encodeBinding = \binding -> Serialization.indentSubsequentLines "    " (localBindingToExpr binding)
        in (Serialization.indentBlock (Lists.cons (Serialization.cst "") (Lists.cons (Serialization.spaceSep (Lists.cons (Serialization.cst "let") [
          Serialization.customIndentBlock "    " (Lists.map encodeBinding bindings)])) [
          Serialization.spaceSep (Lists.cons (Serialization.cst "in") [
            expressionToExpr inner])])))
      Syntax.ExpressionList v0 -> Serialization.bracketList Serialization.halfBlockStyle (Lists.map expressionToExpr v0)
      Syntax.ExpressionTuple v0 -> Serialization.parenListAdaptive (Lists.map expressionToExpr v0)
      Syntax.ExpressionVariable v0 -> nameToExpr v0

-- | Convert a field declaration to an AST expression
fieldToExpr :: Syntax.Field -> Ast.Expr
fieldToExpr field =

      let name = Syntax.fieldName field
          typ = Syntax.fieldType field
          mc = Syntax.fieldComments field
          body = Serialization.spaceSep (Lists.cons (nameToExpr name) (Lists.cons (Serialization.cst "::") [
                typeToExpr typ]))
      in (Optionals.cases mc body (\c -> Serialization.newlineSep (Lists.cons (Serialization.cst (toHaskellComments c)) [
        body])))

-- | Render a 'EntityReference' as Haddock link syntax
haddockEntityRef :: Packaging.EntityReference -> String
haddockEntityRef x =
    case x of
      Packaging.EntityReferenceDefinition v0 -> Strings.cat2 "'" (Strings.cat2 (case v0 of
        Packaging.DefinitionReferencePrimitive v1 -> Names.localNameOf v1
        Packaging.DefinitionReferenceTerm v1 -> Names.localNameOf v1
        Packaging.DefinitionReferenceType v1 -> Names.localNameOf v1) "'")
      Packaging.EntityReferenceModule v0 -> Packaging.unModuleName v0
      Packaging.EntityReferencePackage v0 -> Packaging.unPackageName v0
      Packaging.EntityReferenceTermExpr v0 -> Strings.cat2 "@" (Strings.cat2 v0 "@")
      Packaging.EntityReferenceTypeExpr v0 -> Strings.cat2 "@" (Strings.cat2 v0 "@")

-- | Convert an if-then-else expression to an AST expression
ifExpressionToExpr :: Syntax.IfExpression -> Ast.Expr
ifExpressionToExpr ifExpr =

      let eif = Syntax.ifExpressionCondition ifExpr
          ethen = Syntax.ifExpressionThen ifExpr
          eelse = Syntax.ifExpressionElse ifExpr
          ifOp =
                  Ast.Op {
                    Ast.opSymbol = (Ast.Symbol ""),
                    Ast.opPadding = Ast.Padding {
                      Ast.paddingLeft = Ast.WsNone,
                      Ast.paddingRight = (Ast.WsBreakAndIndent "  ")},
                    Ast.opPrecedence = (Ast.Precedence 0),
                    Ast.opAssociativity = Ast.AssociativityNone}
          body =
                  Serialization.newlineSep (Lists.cons (Serialization.spaceSep (Lists.cons (Serialization.cst "then") [
                    expressionToExpr ethen])) [
                    Serialization.spaceSep (Lists.cons (Serialization.cst "else") [
                      expressionToExpr eelse])])
      in (Serialization.ifx ifOp (Serialization.spaceSep (Lists.cons (Serialization.cst "if") [
        expressionToExpr eif])) body)

-- | Convert an import statement to an AST expression
importToExpr :: Syntax.Import -> Ast.Expr
importToExpr import_ =

      let qual = Syntax.importQualified import_
          modName = Syntax.importModule import_
          mod = Syntax.importAs import_
          mspec = Syntax.importSpec import_
          name = Syntax.unModuleName modName
          hidingSec =
                  \spec -> case spec of
                    Syntax.ImportSpecHiding v0 -> Serialization.spaceSep (Lists.cons (Serialization.cst "hiding ") [
                      Serialization.parens (Serialization.commaSep Serialization.inlineStyle (Lists.map namedImportExportToExpr v0))])
          parts =
                  Optionals.cat [
                    Just (Serialization.cst "import"),
                    (Logic.ifElse qual (Just (Serialization.cst "qualified")) Nothing),
                    (Just (Serialization.cst name)),
                    (Optionals.map (\m -> Serialization.cst (Strings.cat2 "as " (Syntax.unModuleName m))) mod),
                    (Optionals.map hidingSec mspec)]
      in (Serialization.spaceSep parts)

-- | Convert a lambda expression to an AST expression
lambdaExpressionToExpr :: Syntax.LambdaExpression -> Ast.Expr
lambdaExpressionToExpr lambdaExpr =

      let bindings = Syntax.lambdaExpressionBindings lambdaExpr
          inner = Syntax.lambdaExpressionInner lambdaExpr
          head = Serialization.spaceSep (Lists.map patternToExpr bindings)
          body = expressionToExpr inner
      in (Serialization.ifx Operators.lambdaOp (Serialization.prefix "\\" head) body)

-- | Convert a literal value to an AST expression
literalToExpr :: Syntax.Literal -> Ast.Expr
literalToExpr lit =

      let parensIfNeg =
              \b -> \e -> Logic.ifElse b (Strings.cat [
                "(",
                e,
                ")"]) e
          showFloat =
                  \showFn -> \v ->
                    let raw = showFn v
                    in (Logic.ifElse (Equality.equal raw "NaN") "(0/0)" (Logic.ifElse (Equality.equal raw "Infinity") "(1/0)" (Logic.ifElse (Equality.equal raw "-Infinity") "(-(1/0))" (parensIfNeg (Equality.equal (Optionals.fromOptional 0 (Strings.maybeCharAt 0 raw)) 45) raw))))
      in (Serialization.cst (case lit of
        Syntax.LiteralChar v0 -> Literals.showString (Literals.showUint16 v0)
        Syntax.LiteralDouble v0 -> showFloat (\v -> Literals.showFloat64 v) v0
        Syntax.LiteralFloat v0 -> showFloat (\v -> Literals.showFloat32 v) v0
        Syntax.LiteralInt v0 -> parensIfNeg (Equality.lt v0 0) (Literals.showInt32 v0)
        Syntax.LiteralInteger v0 -> parensIfNeg (Equality.lt v0 0) (Literals.showBigint v0)
        Syntax.LiteralString v0 -> Literals.showString v0))

-- | Convert a local binding to an AST expression
localBindingToExpr :: Syntax.LocalBinding -> Ast.Expr
localBindingToExpr binding =
    case binding of
      Syntax.LocalBindingSignature v0 -> typeSignatureToExpr v0
      Syntax.LocalBindingValue v0 -> valueBindingToExpr v0

-- | Convert a module head to an AST expression
moduleHeadToExpr :: Syntax.ModuleHead -> Ast.Expr
moduleHeadToExpr moduleHead =

      let mc = Syntax.moduleHeadComments moduleHead
          modName = Syntax.moduleHeadName moduleHead
          mname = Syntax.unModuleName modName
          head =
                  Serialization.spaceSep (Lists.cons (Serialization.cst "module") (Lists.cons (Serialization.cst mname) [
                    Serialization.cst "where"]))
      in (Optionals.cases mc head (\c -> Serialization.newlineSep (Lists.cons (Serialization.cst (toHaskellComments c)) (Lists.cons (Serialization.cst "") [
        head]))))

-- | Convert a Haskell module to an AST expression
moduleToExpr :: Syntax.Module -> Ast.Expr
moduleToExpr module_ =

      let mh = Syntax.moduleHead module_
          imports = Syntax.moduleImports module_
          decls = Syntax.moduleDeclarations module_
          warning = [
                Serialization.cst (toSimpleComments Constants.warningAutoGeneratedFile)]
          headerLine = Optionals.cases mh [] (\h -> [
                moduleHeadToExpr h])
          declLines = Lists.map declarationToExpr decls
          importLines = Logic.ifElse (Lists.null imports) [] [
                Serialization.newlineSep (Lists.map importToExpr imports)]
      in (Serialization.doubleNewlineSep (Lists.concat [
        warning,
        headerLine,
        importLines,
        declLines]))

-- | Convert a Haskell name to an AST expression
nameToExpr :: Syntax.Name -> Ast.Expr
nameToExpr name =
    Serialization.cst (case name of
      Syntax.NameImplicit v0 -> Strings.cat2 "?" (writeQualifiedName v0)
      Syntax.NameNormal v0 -> writeQualifiedName v0)

-- | Convert an import/export specification to an AST expression
namedImportExportToExpr :: Syntax.NamedImportExport -> Ast.Expr
namedImportExportToExpr spec = nameToExpr (Syntax.namedImportExportName spec)

-- | Convert a pattern to an AST expression
patternToExpr :: Syntax.Pattern -> Ast.Expr
patternToExpr pat =
    case pat of
      Syntax.PatternApplication v0 -> applicationPatternToExpr v0
      Syntax.PatternList v0 -> Serialization.bracketList Serialization.halfBlockStyle (Lists.map patternToExpr v0)
      Syntax.PatternLiteral v0 -> literalToExpr v0
      Syntax.PatternName v0 -> nameToExpr v0
      Syntax.PatternTuple v0 -> Serialization.parenListAdaptive (Lists.map patternToExpr v0)
      Syntax.PatternWildcard -> Serialization.cst "_"

-- | Convert a record construction expression to an AST expression
recordExpressionToExpr :: Syntax.RecordExpression -> Ast.Expr
recordExpressionToExpr constructRecord =

      let name = Syntax.recordExpressionName constructRecord
          updates = Syntax.recordExpressionFields constructRecord
          fromUpdate =
                  \update ->
                    let fn = Syntax.fieldUpdateName update
                        val = Syntax.fieldUpdateValue update
                    in (Serialization.ifx Operators.defineOp (nameToExpr fn) (expressionToExpr val))
          body = Serialization.commaSep Serialization.halfBlockStyle (Lists.map fromUpdate updates)
      in (Serialization.spaceSep (Lists.cons (nameToExpr name) [
        Serialization.brackets Serialization.curlyBraces Serialization.halfBlockStyle body]))

-- | Convert a right-hand side to an AST expression
rightHandSideToExpr :: Syntax.RightHandSide -> Ast.Expr
rightHandSideToExpr rhs = expressionToExpr (Syntax.unRightHandSide rhs)

-- | Convert a statement to an AST expression
statementToExpr :: Syntax.Statement -> Ast.Expr
statementToExpr stmt = expressionToExpr (Syntax.unStatement stmt)

-- | Convert a string to Haddock documentation comments. Empty source lines emit `-- |` (no trailing space) so blank doc lines don't carry trailing whitespace into the generated file. Doc-escape tags are rendered as Haddock links via haddockEntityRef.
toHaskellComments :: String -> String
toHaskellComments c =
    Strings.intercalate "\n" (Lists.map (\s -> Logic.ifElse (Equality.equal s "") "-- |" (Strings.cat2 "-- | " s)) (Strings.lines (ShowDocs.renderDocStringWith haddockEntityRef c)))

-- | Convert a string to simple line comments. Empty source lines emit `--` (no trailing space) for the same reason as toHaskellComments.
toSimpleComments :: String -> String
toSimpleComments c =
    Strings.intercalate "\n" (Lists.map (\s -> Logic.ifElse (Equality.equal s "") "--" (Strings.cat2 "-- " s)) (Strings.lines c))

-- | Convert a type signature to an AST expression
typeSignatureToExpr :: Syntax.TypeSignature -> Ast.Expr
typeSignatureToExpr typeSig =

      let name = Syntax.typeSignatureName typeSig
          typ = Syntax.typeSignatureType typeSig
          nameExpr = nameToExpr name
          typeExpr = typeToExpr typ
          inlineSig =
                  Serialization.structuralSpaceSep [
                    nameExpr,
                    (Serialization.cst "::"),
                    typeExpr]
      in (Serialization.chooseLayout Serialization.maxLineWidth inlineSig (Serialization.newlineSep [
        Serialization.spaceSep [
          nameExpr,
          (Serialization.cst "::")],
        (Serialization.tabIndent typeExpr)]))

-- | Convert a Haskell type to an AST expression
typeToExpr :: Syntax.Type -> Ast.Expr
typeToExpr htype =
    case htype of
      Syntax.TypeApplication v0 ->
        let lhs = Syntax.applicationTypeContext v0
            rhs = Syntax.applicationTypeArgument v0
        in (Serialization.ifx Operators.appOp (typeToExpr lhs) (typeToExpr rhs))
      Syntax.TypeCtx v0 ->
        let ctx = Syntax.constrainedTypeCtx v0
            typ = Syntax.constrainedTypeType v0
        in (Serialization.ifx Operators.assertOp (constraintToExpr ctx) (typeToExpr typ))
      Syntax.TypeFunction v0 ->
        let dom = Syntax.functionTypeDomain v0
            cod = Syntax.functionTypeCodomain v0
        in (Serialization.ifx Operators.arrowOp (typeToExpr dom) (typeToExpr cod))
      Syntax.TypeList v0 -> Serialization.bracketList Serialization.inlineStyle [
        typeToExpr v0]
      Syntax.TypeTuple v0 -> Serialization.parenListAdaptive (Lists.map typeToExpr v0)
      Syntax.TypeVariable v0 -> nameToExpr v0

-- | Convert a value binding to an AST expression
valueBindingToExpr :: Syntax.ValueBinding -> Ast.Expr
valueBindingToExpr vb =
    case vb of
      Syntax.ValueBindingSimple v0 ->
        let pat = Syntax.simpleValueBindingPattern v0
            rhs = Syntax.simpleValueBindingRhs v0
            local = Syntax.simpleValueBindingLocalBindings v0
            lhsExpr = patternToExpr pat
            rhsExpr = rightHandSideToExpr rhs
            inlineBody =
                    Serialization.structuralSpaceSep [
                      lhsExpr,
                      (Serialization.cst "="),
                      rhsExpr]
            body =
                    Serialization.chooseLayout Serialization.maxLineWidth inlineBody (Serialization.newlineSep [
                      Serialization.spaceSep [
                        lhsExpr,
                        (Serialization.cst "=")],
                      (Serialization.tabIndent rhsExpr)])
        in (Optionals.cases local body (\localBindings ->
          let bindings = Syntax.unLocalBindings localBindings
          in (Serialization.indentBlock (Lists.cons body [
            Serialization.indentBlock (Lists.cons (Serialization.cst "where") (Lists.map localBindingToExpr bindings))]))))

-- | Convert a type variable to an AST expression
variableToExpr :: Syntax.Variable -> Ast.Expr
variableToExpr variable = nameToExpr (Syntax.unVariable variable)

-- | Write a qualified name as a string
writeQualifiedName :: Syntax.QualifiedName -> String
writeQualifiedName qname =

      let qualifiers = Syntax.qualifiedNameQualifiers qname
          unqual = Syntax.qualifiedNameUnqualified qname
          h = \namePart -> Syntax.unNamePart namePart
          allParts = Lists.concat2 (Lists.map h qualifiers) [
                h unqual]
      in (Strings.intercalate "." allParts)