packages feed

hydra-lisp-0.17.2: src/main/haskell/Hydra/Lisp/Serde.hs

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

-- | Lisp serializer: converts Lisp AST to concrete syntax for Clojure, Emacs Lisp, Common Lisp, or Scheme

module Hydra.Lisp.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.Formatting as Formatting
import qualified Hydra.Graph as Graph
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.Pairs as Pairs
import qualified Hydra.Overlay.Haskell.Lib.Strings as Strings
import qualified Hydra.Lisp.Syntax as Syntax
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.Regex as Regex
import qualified Hydra.Relational as Relational
import qualified Hydra.Serialization as Serialization
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

-- | Serialize an and expression: (and expr1 expr2 ...)
andExpressionToExpr :: Syntax.Dialect -> Syntax.AndExpression -> Ast.Expr
andExpressionToExpr d andExpr =
    Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
      Serialization.cst "and"] (Lists.map (expressionToExpr d) (Syntax.andExpressionExpressions andExpr))))

-- | Serialize a function application, using funcall for computed function positions in Lisp-2 dialects
applicationToExpr :: Syntax.Dialect -> Syntax.Application -> Ast.Expr
applicationToExpr d app =

      let funExpr = Syntax.applicationFunction app
          fun = expressionToExpr d funExpr
          args = Lists.map (expressionToExpr d) (Syntax.applicationArguments app)
          funcallWhenComputed =
                  case funExpr of
                    Syntax.ExpressionVariable _ -> False
                    _ -> True
          needsFuncall =
                  case d of
                    Syntax.DialectCommonLisp -> funcallWhenComputed
                    Syntax.DialectEmacsLisp -> funcallWhenComputed
                    _ -> False
          allParts =
                  Logic.ifElse needsFuncall (Lists.concat2 [
                    Serialization.cst "funcall",
                    fun] args) (Lists.concat2 [
                    fun] args)
      in (Serialization.parens (Serialization.spaceSepAdaptive allParts))

-- | Serialize a case expression
caseExpressionToExpr :: Syntax.Dialect -> Syntax.CaseExpression -> Ast.Expr
caseExpressionToExpr d caseExpr =

      let scrutinee = expressionToExpr d (Syntax.caseExpressionScrutinee caseExpr)
          clauses = Syntax.caseExpressionClauses caseExpr
          dflt = Syntax.caseExpressionDefault caseExpr
          clauseExprs =
                  Lists.map (\c -> Serialization.parens (Serialization.spaceSepAdaptive [
                    Serialization.parens (Serialization.spaceSepAdaptive (Lists.map (expressionToExpr d) (Syntax.caseClauseKeys c))),
                    (expressionToExpr d (Syntax.caseClauseBody c))])) clauses
          defaultPart =
                  Optionals.cases dflt [] (\e -> [
                    Serialization.parens (Serialization.spaceSepAdaptive [
                      Serialization.cst "else",
                      (expressionToExpr d e)])])
      in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
        [
          Serialization.cst "case",
          scrutinee],
        clauseExprs,
        defaultPart])))

-- | Serialize a comment
commentToExpr :: Syntax.Comment -> Ast.Expr
commentToExpr c =

      let text = Syntax.commentText c
      in (Serialization.cst (Logic.ifElse (Equality.equal text "") ";" (Strings.cat2 "; " text)))

-- | Serialize a cond expression
condExpressionToExpr :: Syntax.Dialect -> Syntax.CondExpression -> Ast.Expr
condExpressionToExpr d condExpr =

      let clauses = Syntax.condExpressionClauses condExpr
          dflt = Syntax.condExpressionDefault condExpr
      in case d of
        Syntax.DialectClojure ->
          let clauseExprs =
                  Lists.concat (Lists.map (\c -> [
                    expressionToExpr d (Syntax.condClauseCondition c),
                    (expressionToExpr d (Syntax.condClauseBody c))]) clauses)
              defaultPart =
                      Optionals.cases dflt [] (\e -> [
                        Serialization.cst ":else",
                        (expressionToExpr d e)])
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "cond"],
            clauseExprs,
            defaultPart])))
        Syntax.DialectEmacsLisp ->
          let clauseExprs =
                  Lists.map (\c -> Serialization.parens (Serialization.spaceSepAdaptive [
                    expressionToExpr d (Syntax.condClauseCondition c),
                    (expressionToExpr d (Syntax.condClauseBody c))])) clauses
              defaultPart =
                      Optionals.cases dflt [] (\e -> [
                        Serialization.parens (Serialization.spaceSepAdaptive [
                          Serialization.cst "t",
                          (expressionToExpr d e)])])
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "cond"],
            clauseExprs,
            defaultPart])))
        Syntax.DialectCommonLisp ->
          let clauseExprs =
                  Lists.map (\c -> Serialization.parens (Serialization.spaceSepAdaptive [
                    expressionToExpr d (Syntax.condClauseCondition c),
                    (expressionToExpr d (Syntax.condClauseBody c))])) clauses
              defaultPart =
                      Optionals.cases dflt [] (\e -> [
                        Serialization.parens (Serialization.spaceSepAdaptive [
                          Serialization.cst "t",
                          (expressionToExpr d e)])])
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "cond"],
            clauseExprs,
            defaultPart])))
        Syntax.DialectScheme ->
          let clauseExprs =
                  Lists.map (\c -> Serialization.parens (Serialization.spaceSepAdaptive [
                    expressionToExpr d (Syntax.condClauseCondition c),
                    (expressionToExpr d (Syntax.condClauseBody c))])) clauses
              defaultPart =
                      Optionals.cases dflt [] (\e -> [
                        Serialization.parens (Serialization.spaceSepAdaptive [
                          Serialization.cst "else",
                          (expressionToExpr d e)])])
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "cond"],
            clauseExprs,
            defaultPart])))

-- | Serialize a constant definition
constantDefinitionToExpr :: Syntax.Dialect -> Syntax.ConstantDefinition -> Ast.Expr
constantDefinitionToExpr d cdef =

      let name = symbolToExpr (Syntax.constantDefinitionName cdef)
          value = expressionToExpr d (Syntax.constantDefinitionValue cdef)
      in (Serialization.parens (Serialization.spaceSepAdaptive [
        Serialization.cst (defconstKeyword d),
        name,
        value]))

-- | The keyword for variable definitions
defKeyword :: Syntax.Dialect -> String
defKeyword d =
    case d of
      Syntax.DialectClojure -> "def"
      Syntax.DialectEmacsLisp -> "defvar"
      Syntax.DialectCommonLisp -> "cl:defvar"
      Syntax.DialectScheme -> "define"

-- | The keyword for constant definitions
defconstKeyword :: Syntax.Dialect -> String
defconstKeyword d =
    case d of
      Syntax.DialectClojure -> "def"
      Syntax.DialectEmacsLisp -> "defconst"
      Syntax.DialectCommonLisp -> "cl:defconstant"
      Syntax.DialectScheme -> "define"

-- | The keyword for named function definitions
defnKeyword :: Syntax.Dialect -> String
defnKeyword d =
    case d of
      Syntax.DialectClojure -> "defn"
      Syntax.DialectEmacsLisp -> "defun"
      Syntax.DialectCommonLisp -> "cl:defun"
      Syntax.DialectScheme -> "define"

-- | The keyword for record/struct definitions
defrecordKeyword :: Syntax.Dialect -> String
defrecordKeyword d =
    case d of
      Syntax.DialectClojure -> "defrecord"
      Syntax.DialectEmacsLisp -> "cl-defstruct"
      Syntax.DialectCommonLisp -> "cl:defstruct"
      Syntax.DialectScheme -> "define-record-type"

-- | Serialize a do/progn/begin expression
doExpressionToExpr :: Syntax.Dialect -> Syntax.DoExpression -> Ast.Expr
doExpressionToExpr d doExpr =

      let kw =
              case d of
                Syntax.DialectClojure -> "do"
                Syntax.DialectEmacsLisp -> "progn"
                Syntax.DialectCommonLisp -> "progn"
                Syntax.DialectScheme -> "begin"
      in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
        Serialization.cst kw] (Lists.map (expressionToExpr d) (Syntax.doExpressionExpressions doExpr)))))

-- | Serialize a docstring as a comment
docstringToExpr :: Syntax.Docstring -> Ast.Expr
docstringToExpr ds =

      let text = Syntax.unDocstring ds
      in (Serialization.cst (Logic.ifElse (Equality.equal text "") ";;" (Strings.cat [
        ";; ",
        text])))

-- | Serialize an export declaration
exportDeclarationToExpr :: Syntax.Dialect -> Syntax.ExportDeclaration -> Ast.Expr
exportDeclarationToExpr d edecl =

      let syms = Lists.map symbolToExpr (Syntax.exportDeclarationSymbols edecl)
      in case d of
        Syntax.DialectClojure -> Serialization.cst ""
        Syntax.DialectEmacsLisp -> Serialization.newlineSep (Lists.map (\s -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst "provide",
          (Serialization.noSep [
            Serialization.cst "'",
            s])])) syms)
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
          Serialization.cst ":export"] (Lists.map (\s -> Serialization.noSep [
          Serialization.cst ":",
          s]) syms)))
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
          Serialization.cst "export"] syms))

-- | Serialize a Lisp expression
expressionToExpr :: Syntax.Dialect -> Syntax.Expression -> Ast.Expr
expressionToExpr d expr =
    case expr of
      Syntax.ExpressionApplication v0 -> applicationToExpr d v0
      Syntax.ExpressionLambda v0 -> lambdaToExpr d v0
      Syntax.ExpressionLet v0 -> letExpressionToExpr d v0
      Syntax.ExpressionIf v0 -> ifExpressionToExpr d v0
      Syntax.ExpressionCond v0 -> condExpressionToExpr d v0
      Syntax.ExpressionCase v0 -> caseExpressionToExpr d v0
      Syntax.ExpressionAnd v0 -> andExpressionToExpr d v0
      Syntax.ExpressionOr v0 -> orExpressionToExpr d v0
      Syntax.ExpressionNot v0 -> notExpressionToExpr d v0
      Syntax.ExpressionDo v0 -> doExpressionToExpr d v0
      Syntax.ExpressionBegin v0 -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
        Serialization.cst "begin"] (Lists.map (expressionToExpr d) (Syntax.beginExpressionExpressions v0))))
      Syntax.ExpressionVariable v0 -> variableReferenceToExpr d v0
      Syntax.ExpressionLiteral v0 -> literalToExpr d v0
      Syntax.ExpressionList v0 -> listLiteralToExpr d v0
      Syntax.ExpressionVector v0 -> vectorLiteralToExpr d v0
      Syntax.ExpressionMap v0 -> mapLiteralToExpr d v0
      Syntax.ExpressionSet v0 -> setLiteralToExpr d v0
      Syntax.ExpressionCons v0 -> Serialization.parens (Serialization.spaceSepAdaptive [
        Serialization.cst "cons",
        (expressionToExpr d (Syntax.consExpressionHead v0)),
        (expressionToExpr d (Syntax.consExpressionTail v0))])
      Syntax.ExpressionDottedPair v0 -> Serialization.parens (Serialization.spaceSepAdaptive [
        expressionToExpr d (Syntax.dottedPairCar v0),
        (Serialization.cst "."),
        (expressionToExpr d (Syntax.dottedPairCdr v0))])
      Syntax.ExpressionFieldAccess v0 -> fieldAccessToExpr d v0
      Syntax.ExpressionTypeAnnotation v0 -> expressionToExpr d (Syntax.typeAnnotationExpression v0)
      Syntax.ExpressionQuote v0 -> Serialization.noSep [
        Serialization.cst "'",
        (expressionToExpr d (Syntax.quoteExpressionBody v0))]
      Syntax.ExpressionQuasiquote v0 -> Serialization.noSep [
        Serialization.cst "`",
        (expressionToExpr d (Syntax.quasiquoteExpressionBody v0))]
      Syntax.ExpressionUnquote v0 -> case d of
        Syntax.DialectClojure -> Serialization.noSep [
          Serialization.cst "~",
          (expressionToExpr d (Syntax.unquoteExpressionBody v0))]
        Syntax.DialectEmacsLisp -> Serialization.noSep [
          Serialization.cst ",",
          (expressionToExpr d (Syntax.unquoteExpressionBody v0))]
        Syntax.DialectCommonLisp -> Serialization.noSep [
          Serialization.cst ",",
          (expressionToExpr d (Syntax.unquoteExpressionBody v0))]
        Syntax.DialectScheme -> Serialization.noSep [
          Serialization.cst ",",
          (expressionToExpr d (Syntax.unquoteExpressionBody v0))]
      Syntax.ExpressionSplicingUnquote v0 -> case d of
        Syntax.DialectClojure -> Serialization.noSep [
          Serialization.cst "~@",
          (expressionToExpr d (Syntax.splicingUnquoteExpressionBody v0))]
        Syntax.DialectEmacsLisp -> Serialization.noSep [
          Serialization.cst ",@",
          (expressionToExpr d (Syntax.splicingUnquoteExpressionBody v0))]
        Syntax.DialectCommonLisp -> Serialization.noSep [
          Serialization.cst ",@",
          (expressionToExpr d (Syntax.splicingUnquoteExpressionBody v0))]
        Syntax.DialectScheme -> Serialization.noSep [
          Serialization.cst ",@",
          (expressionToExpr d (Syntax.splicingUnquoteExpressionBody v0))]
      Syntax.ExpressionSExpression v0 -> sExpressionToExpr v0

-- | The boolean false expression
falseExpr :: Syntax.Dialect -> Ast.Expr
falseExpr d =
    case d of
      Syntax.DialectClojure -> Serialization.cst "false"
      Syntax.DialectEmacsLisp -> Serialization.cst "nil"
      Syntax.DialectCommonLisp -> Serialization.cst "cl:nil"
      Syntax.DialectScheme -> Serialization.cst "#f"

-- | Serialize a field access expression
fieldAccessToExpr :: Syntax.Dialect -> Syntax.FieldAccess -> Ast.Expr
fieldAccessToExpr d fa =

      let rtype = symbolToExpr (Syntax.fieldAccessRecordType fa)
          field = symbolToExpr (Syntax.fieldAccessField fa)
          target = expressionToExpr d (Syntax.fieldAccessTarget fa)
      in case d of
        Syntax.DialectClojure -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.noSep [
            Serialization.cst ":",
            field],
          target])
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.noSep [
            rtype,
            (Serialization.cst "-"),
            field],
          target])
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.noSep [
            rtype,
            (Serialization.cst "-"),
            field],
          target])
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.noSep [
            rtype,
            (Serialization.cst "-"),
            field],
          target])

-- | Format a float64 value as a dialect-specific literal string, including special values like NaN and infinities
formatLispFloat :: Syntax.Dialect -> Double -> String
formatLispFloat d v =

      let s = Literals.showFloat64 v
      in (Logic.ifElse (Equality.equal s "NaN") (case d of
        Syntax.DialectClojure -> "Double/NaN"
        Syntax.DialectScheme -> "+nan.0"
        Syntax.DialectCommonLisp -> "+hydra-nan+"
        Syntax.DialectEmacsLisp -> "0.0e+NaN") (Logic.ifElse (Equality.equal s "Infinity") (case d of
        Syntax.DialectClojure -> "Double/POSITIVE_INFINITY"
        Syntax.DialectScheme -> "+inf.0"
        Syntax.DialectCommonLisp -> "+hydra-pos-inf+"
        Syntax.DialectEmacsLisp -> "1.0e+INF") (Logic.ifElse (Equality.equal s "-Infinity") (case d of
        Syntax.DialectClojure -> "Double/NEGATIVE_INFINITY"
        Syntax.DialectScheme -> "-inf.0"
        Syntax.DialectCommonLisp -> "+hydra-neg-inf+"
        Syntax.DialectEmacsLisp -> "-1.0e+INF") s)))

-- | Serialize a function definition
functionDefinitionToExpr :: Syntax.Dialect -> Syntax.FunctionDefinition -> Ast.Expr
functionDefinitionToExpr d fdef =

      let name = symbolToExpr (Syntax.functionDefinitionName fdef)
          params = Lists.map symbolToExpr (Syntax.functionDefinitionParams fdef)
          body = Lists.map (expressionToExpr d) (Syntax.functionDefinitionBody fdef)
      in case d of
        Syntax.DialectClojure -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "defn",
            name],
          [
            Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep params)],
          body]))
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "defun",
            name],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "defun",
            name],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "define"],
          [
            Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
              name] params))],
          body]))

-- | Serialize an if expression: (if test then else)
ifExpressionToExpr :: Syntax.Dialect -> Syntax.IfExpression -> Ast.Expr
ifExpressionToExpr d ifExpr =

      let cond = expressionToExpr d (Syntax.ifExpressionCondition ifExpr)
          then_ = expressionToExpr d (Syntax.ifExpressionThen ifExpr)
          else_ = Syntax.ifExpressionElse ifExpr
          elsePart = Optionals.cases else_ [] (\e -> [
                expressionToExpr d e])
      in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
        [
          Serialization.cst "if",
          cond,
          then_],
        elsePart])))

-- | Serialize an import declaration
importDeclarationToExpr :: Syntax.Dialect -> Syntax.ImportDeclaration -> Ast.Expr
importDeclarationToExpr d idecl =

      let modName = Syntax.unNamespaceName (Syntax.importDeclarationModule idecl)
      in case d of
        Syntax.DialectClojure -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst ":require",
          (Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep [
            Serialization.cst modName]))])
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst "require",
          (Serialization.noSep [
            Serialization.cst "'",
            (Serialization.cst modName)])])
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst ":use",
          (Serialization.cst (Strings.cat2 ":" modName))])
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst "import",
          (Serialization.parens (Serialization.cst modName))])

-- | Serialize a keyword
keywordToExpr :: Syntax.Dialect -> Syntax.Keyword -> Ast.Expr
keywordToExpr d k =

      let name = Syntax.keywordName k
          ns = Syntax.keywordNamespace k
      in case d of
        Syntax.DialectScheme -> Serialization.noSep [
          Serialization.cst "'",
          (Serialization.cst name)]
        _ -> Serialization.cst (Optionals.cases ns (Strings.cat2 ":" name) (\n -> Strings.cat [
          n,
          "/:",
          name]))

-- | The keyword for anonymous functions
lambdaKeyword :: Syntax.Dialect -> String
lambdaKeyword d =
    case d of
      Syntax.DialectClojure -> "fn"
      Syntax.DialectEmacsLisp -> "lambda"
      Syntax.DialectCommonLisp -> "cl:lambda"
      Syntax.DialectScheme -> "lambda"

-- | Serialize a lambda expression
lambdaToExpr :: Syntax.Dialect -> Syntax.Lambda -> Ast.Expr
lambdaToExpr d lam =

      let params = Lists.map symbolToExpr (Syntax.lambdaParams lam)
          body = Lists.map (expressionToExpr d) (Syntax.lambdaBody lam)
          mname = Syntax.lambdaName lam
          kw = lambdaKeyword d
      in case d of
        Syntax.DialectClojure -> Optionals.cases mname (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst kw],
          [
            Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep params)],
          body]))) (\sym -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst kw,
            (symbolToExpr sym)],
          [
            Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep params)],
          body])))
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst kw],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst kw],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst kw],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))

-- | Serialize a let expression
letExpressionToExpr :: Syntax.Dialect -> Syntax.LetExpression -> Ast.Expr
letExpressionToExpr d letExpr =

      let kind = Syntax.letExpressionKind letExpr
          bindings = Syntax.letExpressionBindings letExpr
          body = Lists.map (expressionToExpr d) (Syntax.letExpressionBody letExpr)
          bindingPairs =
                  Lists.map (\b -> case b of
                    Syntax.LetBindingSimple v0 -> (symbolToExpr (Syntax.simpleBindingName v0), (expressionToExpr d (Syntax.simpleBindingValue v0)))
                    Syntax.LetBindingDestructuring _ -> (Serialization.cst "<destructuring>", (Serialization.cst "<destructuring>"))) bindings
      in case d of
        Syntax.DialectClojure -> case kind of
          Syntax.LetKindRecursive ->
            let fnSpecs =
                    Lists.map (\b -> case b of
                      Syntax.LetBindingSimple v2 ->
                        let name = symbolToExpr (Syntax.simpleBindingName v2)
                            val = Syntax.simpleBindingValue v2
                        in case val of
                          Syntax.ExpressionLambda v3 ->
                            let params = Lists.map symbolToExpr (Syntax.lambdaParams v3)
                                lbody = Lists.map (expressionToExpr d) (Syntax.lambdaBody v3)
                            in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
                              [
                                name],
                              [
                                Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep params)],
                              lbody])))
                          _ -> Serialization.parens (Serialization.spaceSepAdaptive [
                            name,
                            (expressionToExpr d val)])
                      Syntax.LetBindingDestructuring _ -> Serialization.cst "<destructuring>") bindings
            in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
              [
                Serialization.cst "letfn"],
              [
                Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep fnSpecs)],
              body])))
          Syntax.LetKindParallel -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "let"],
            [
              Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep (Lists.concat (Lists.map (\p -> [
                Pairs.first p,
                (Pairs.second p)]) bindingPairs)))],
            body]))
          Syntax.LetKindSequential -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "let"],
            [
              Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep (Lists.concat (Lists.map (\p -> [
                Pairs.first p,
                (Pairs.second p)]) bindingPairs)))],
            body]))
        Syntax.DialectEmacsLisp ->
          let kw =
                  case kind of
                    Syntax.LetKindParallel -> "let"
                    Syntax.LetKindSequential -> "let*"
                    Syntax.LetKindRecursive -> "letrec"
              bindingExprs =
                      Lists.map (\p -> Serialization.parens (Serialization.spaceSepAdaptive [
                        Pairs.first p,
                        (Pairs.second p)])) bindingPairs
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst kw],
            [
              Serialization.parens (Serialization.spaceSepAdaptive bindingExprs)],
            body])))
        Syntax.DialectCommonLisp ->
          let kw =
                  case kind of
                    Syntax.LetKindParallel -> "let"
                    Syntax.LetKindSequential -> "let*"
                    Syntax.LetKindRecursive -> "letrec"
              bindingExprs =
                      Lists.map (\p -> Serialization.parens (Serialization.spaceSepAdaptive [
                        Pairs.first p,
                        (Pairs.second p)])) bindingPairs
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst kw],
            [
              Serialization.parens (Serialization.spaceSepAdaptive bindingExprs)],
            body])))
        Syntax.DialectScheme ->
          let kw =
                  case kind of
                    Syntax.LetKindParallel -> "let"
                    Syntax.LetKindSequential -> "let*"
                    Syntax.LetKindRecursive -> "letrec"
              bindingExprs =
                      Lists.map (\p -> Serialization.parens (Serialization.spaceSepAdaptive [
                        Pairs.first p,
                        (Pairs.second p)])) bindingPairs
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst kw],
            [
              Serialization.parens (Serialization.spaceSepAdaptive bindingExprs)],
            body])))

-- | The keyword for list construction
listKeyword :: Syntax.Dialect -> String
listKeyword d =
    case d of
      Syntax.DialectClojure -> "list"
      Syntax.DialectEmacsLisp -> "list"
      Syntax.DialectCommonLisp -> "cl:list"
      Syntax.DialectScheme -> "list"

-- | Serialize a list literal
listLiteralToExpr :: Syntax.Dialect -> Syntax.ListLiteral -> Ast.Expr
listLiteralToExpr d ll =

      let elems = Lists.map (expressionToExpr d) (Syntax.listLiteralElements ll)
          quoted = Syntax.listLiteralQuoted ll
      in (Logic.ifElse quoted (Serialization.noSep [
        Serialization.cst "'",
        (Serialization.parens (Serialization.spaceSepAdaptive elems))]) (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
        Serialization.cst (listKeyword d)] elems))))

-- | Serialize a literal value
literalToExpr :: Syntax.Dialect -> Syntax.Literal -> Ast.Expr
literalToExpr d lit =
    case lit of
      Syntax.LiteralInteger v0 -> Serialization.cst (Literals.showBigint (Syntax.integerLiteralValue v0))
      Syntax.LiteralFloat v0 -> Serialization.cst (formatLispFloat d (Syntax.floatLiteralValue v0))
      Syntax.LiteralString v0 ->
        let e1 = Strings.intercalate "\\\\" (Strings.splitOn "\\" v0)
        in case d of
          Syntax.DialectCommonLisp ->
            let escaped = Strings.intercalate "\\\"" (Strings.splitOn "\"" e1)
            in (Serialization.cst (Strings.cat [
              "\"",
              escaped,
              "\""]))
          Syntax.DialectClojure ->
            let e2 = Strings.intercalate "\\n" (Strings.splitOn (Strings.fromList [
                  10]) e1)
                e3 = Strings.intercalate "\\r" (Strings.splitOn (Strings.fromList [
                      13]) e2)
                e4 = Strings.intercalate "\\t" (Strings.splitOn (Strings.fromList [
                      9]) e3)
                escaped = Strings.intercalate "\\\"" (Strings.splitOn "\"" e4)
            in (Serialization.cst (Strings.cat [
              "\"",
              escaped,
              "\""]))
          Syntax.DialectEmacsLisp ->
            let e2 = Strings.intercalate "\\n" (Strings.splitOn (Strings.fromList [
                  10]) e1)
                e3 = Strings.intercalate "\\r" (Strings.splitOn (Strings.fromList [
                      13]) e2)
                e4 = Strings.intercalate "\\t" (Strings.splitOn (Strings.fromList [
                      9]) e3)
                escaped = Strings.intercalate "\\\"" (Strings.splitOn "\"" e4)
            in (Serialization.cst (Strings.cat [
              "\"",
              escaped,
              "\""]))
          Syntax.DialectScheme ->
            let e2 = Strings.intercalate "\\n" (Strings.splitOn (Strings.fromList [
                  10]) e1)
                e3 = Strings.intercalate "\\r" (Strings.splitOn (Strings.fromList [
                      13]) e2)
                e4 = Strings.intercalate "\\t" (Strings.splitOn (Strings.fromList [
                      9]) e3)
                escaped = Strings.intercalate "\\\"" (Strings.splitOn "\"" e4)
            in (Serialization.cst (Strings.cat [
              "\"",
              escaped,
              "\""]))
      Syntax.LiteralCharacter v0 ->
        let ch = Syntax.characterLiteralValue v0
        in case d of
          Syntax.DialectClojure -> Serialization.cst (Strings.cat2 "\\" ch)
          Syntax.DialectEmacsLisp -> Serialization.cst (Strings.cat2 "?" ch)
          Syntax.DialectCommonLisp -> Serialization.cst (Strings.cat2 "#\\" ch)
          Syntax.DialectScheme -> Serialization.cst (Strings.cat2 "#\\" ch)
      Syntax.LiteralBoolean v0 -> Logic.ifElse v0 (trueExpr d) (falseExpr d)
      Syntax.LiteralNil -> nilExpr d
      Syntax.LiteralKeyword v0 -> keywordToExpr d v0
      Syntax.LiteralSymbol v0 -> Serialization.noSep [
        Serialization.cst "'",
        (symbolToExpr v0)]

-- | Serialize a macro definition
macroDefinitionToExpr :: Syntax.Dialect -> Syntax.MacroDefinition -> Ast.Expr
macroDefinitionToExpr d mdef =

      let name = symbolToExpr (Syntax.macroDefinitionName mdef)
          params = Lists.map symbolToExpr (Syntax.macroDefinitionParams mdef)
          body = Lists.map (expressionToExpr d) (Syntax.macroDefinitionBody mdef)
      in case d of
        Syntax.DialectClojure -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "defmacro",
            name],
          [
            Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep params)],
          body]))
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "defmacro",
            name],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "defmacro",
            name],
          [
            Serialization.parens (Serialization.spaceSepAdaptive params)],
          body]))
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "define-syntax",
            name],
          body]))

-- | Serialize a map literal
mapLiteralToExpr :: Syntax.Dialect -> Syntax.MapLiteral -> Ast.Expr
mapLiteralToExpr d ml =

      let entries = Syntax.mapLiteralEntries ml
      in case d of
        Syntax.DialectClojure -> Serialization.brackets Serialization.curlyBraces Serialization.inlineStyle (Serialization.spaceSep (Lists.concat (Lists.map (\e -> [
          expressionToExpr d (Syntax.mapEntryKey e),
          (expressionToExpr d (Syntax.mapEntryValue e))]) entries)))
        Syntax.DialectEmacsLisp -> Serialization.noSep [
          Serialization.cst "'",
          (Serialization.parens (Serialization.spaceSepAdaptive (Lists.map (\e -> Serialization.parens (Serialization.spaceSepAdaptive [
            expressionToExpr d (Syntax.mapEntryKey e),
            (Serialization.cst "."),
            (expressionToExpr d (Syntax.mapEntryValue e))])) entries)))]
        Syntax.DialectCommonLisp -> Serialization.noSep [
          Serialization.cst "'",
          (Serialization.parens (Serialization.spaceSepAdaptive (Lists.map (\e -> Serialization.parens (Serialization.spaceSepAdaptive [
            expressionToExpr d (Syntax.mapEntryKey e),
            (Serialization.cst "."),
            (expressionToExpr d (Syntax.mapEntryValue e))])) entries)))]
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
          Serialization.cst "list"] (Lists.map (\e -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst "cons",
          (expressionToExpr d (Syntax.mapEntryKey e)),
          (expressionToExpr d (Syntax.mapEntryValue e))])) entries)))

-- | Serialize a module declaration
moduleDeclarationToExpr :: Syntax.Dialect -> Syntax.ModuleDeclaration -> Ast.Expr
moduleDeclarationToExpr d mdecl =

      let name = Syntax.unNamespaceName (Syntax.moduleDeclarationName mdecl)
      in case d of
        Syntax.DialectClojure -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst "ns",
          (Serialization.cst name)])
        Syntax.DialectEmacsLisp -> Serialization.newlineSep [
          Serialization.parens (Serialization.spaceSepAdaptive [
            Serialization.cst "require",
            (Serialization.noSep [
              Serialization.cst "'",
              (Serialization.cst "cl-lib")])]),
          (Serialization.parens (Serialization.spaceSepAdaptive [
            Serialization.cst "provide",
            (Serialization.noSep [
              Serialization.cst "'",
              (Serialization.cst name)])]))]
        Syntax.DialectCommonLisp -> Serialization.newlineSep [
          Serialization.parens (Serialization.spaceSepAdaptive [
            Serialization.cst "defpackage",
            (Serialization.cst (Strings.cat2 ":" name))]),
          (Serialization.parens (Serialization.spaceSepAdaptive [
            Serialization.cst "in-package",
            (Serialization.cst (Strings.cat2 ":" name))]))]
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive [
          Serialization.cst "define-library",
          (Serialization.parens (Serialization.cst name))])

-- | The nil expression
nilExpr :: Syntax.Dialect -> Ast.Expr
nilExpr d =
    case d of
      Syntax.DialectClojure -> Serialization.cst "nil"
      Syntax.DialectEmacsLisp -> Serialization.cst "nil"
      Syntax.DialectCommonLisp -> Serialization.cst "cl:nil"
      Syntax.DialectScheme -> Serialization.cst "'()"

-- | Serialize a not expression: (not expr)
notExpressionToExpr :: Syntax.Dialect -> Syntax.NotExpression -> Ast.Expr
notExpressionToExpr d notExpr =
    Serialization.parens (Serialization.spaceSepAdaptive [
      Serialization.cst "not",
      (expressionToExpr d (Syntax.notExpressionExpression notExpr))])

-- | Serialize an or expression: (or expr1 expr2 ...)
orExpressionToExpr :: Syntax.Dialect -> Syntax.OrExpression -> Ast.Expr
orExpressionToExpr d orExpr =
    Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
      Serialization.cst "or"] (Lists.map (expressionToExpr d) (Syntax.orExpressionExpressions orExpr))))

-- | Serialize a full Lisp program
programToExpr :: Syntax.Program -> Ast.Expr
programToExpr prog =

      let d = Syntax.programDialect prog
          modDecl = Syntax.programModule prog
          imports = Syntax.programImports prog
          exports = Syntax.programExports prog
          forms = Syntax.programForms prog
          formPart = Lists.map (topLevelFormWithCommentsToExpr d) forms
          warning =
                  case d of
                    Syntax.DialectEmacsLisp -> [
                      Serialization.cst ";; -*- lexical-binding: t -*-",
                      (Serialization.cst (Strings.cat2 "; " Constants.warningAutoGeneratedFile))]
                    _ -> [
                      Serialization.cst (Strings.cat2 "; " Constants.warningAutoGeneratedFile)]
          importNames = Lists.map (\idecl -> Syntax.unNamespaceName (Syntax.importDeclarationModule idecl)) imports
          exportSyms = Lists.concat (Lists.map (\edecl -> Lists.map symbolToExpr (Syntax.exportDeclarationSymbols edecl)) exports)
      in case d of
        Syntax.DialectClojure -> Optionals.cases modDecl (Serialization.doubleNewlineSep (Lists.concat2 warning formPart)) (\m ->
          let nameStr = Syntax.unNamespaceName (Syntax.moduleDeclarationName m)
              requireClauses =
                      Lists.map (\imp -> Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep [
                        Serialization.cst imp,
                        (Serialization.cst ":refer"),
                        (Serialization.cst ":all")])) importNames
              nsForm =
                      Logic.ifElse (Lists.null requireClauses) (Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "ns",
                        (Serialization.cst nameStr)])) (Serialization.parens (Serialization.newlineSep [
                        Serialization.spaceSep [
                          Serialization.cst "ns",
                          (Serialization.cst nameStr)],
                        (Serialization.spaceSep (Lists.concat2 [
                          Serialization.cst "  (:require"] requireClauses)),
                        (Serialization.cst ")")]))
              varNames =
                      Lists.concat (Lists.map (\fwc ->
                        let form = Syntax.topLevelFormWithCommentsForm fwc
                        in case form of
                          Syntax.TopLevelFormVariable v1 -> [
                            symbolToExpr (Syntax.variableDefinitionName v1)]
                          Syntax.TopLevelFormFunction v1 -> [
                            symbolToExpr (Syntax.functionDefinitionName v1)]
                          _ -> []) forms)
              declareForm =
                      Logic.ifElse (Lists.null varNames) [] [
                        Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
                          Serialization.cst "declare"] varNames))]
          in (Serialization.doubleNewlineSep (Lists.concat [
            warning,
            [
              nsForm],
            declareForm,
            formPart])))
        Syntax.DialectEmacsLisp -> Optionals.cases modDecl (Serialization.doubleNewlineSep (Lists.concat2 warning formPart)) (\m ->
          let nameStr = Syntax.unNamespaceName (Syntax.moduleDeclarationName m)
              requireClLib =
                      Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "require",
                        (Serialization.noSep [
                          Serialization.cst "'",
                          (Serialization.cst "cl-lib")])])
              requireImports =
                      Lists.map (\imp -> Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "require",
                        (Serialization.noSep [
                          Serialization.cst "'",
                          (Serialization.cst imp)])])) importNames
              provideForm =
                      Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "provide",
                        (Serialization.noSep [
                          Serialization.cst "'",
                          (Serialization.cst nameStr)])])
          in (Serialization.doubleNewlineSep (Lists.concat [
            warning,
            [
              requireClLib],
            requireImports,
            formPart,
            [
              provideForm]])))
        Syntax.DialectCommonLisp -> Optionals.cases modDecl (Serialization.doubleNewlineSep (Lists.concat2 warning formPart)) (\m ->
          let nameStr = Syntax.unNamespaceName (Syntax.moduleDeclarationName m)
              colonName = Strings.cat2 ":" nameStr
              useClause =
                      Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
                        Serialization.cst ":use",
                        (Serialization.cst ":cl")] (Lists.map (\imp -> Serialization.cst (Strings.cat2 ":" imp)) importNames)))
              exportClause =
                      Logic.ifElse (Lists.null exportSyms) [] [
                        Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
                          Serialization.cst ":export"] (Lists.map (\s -> Serialization.noSep [
                          Serialization.cst ":",
                          s]) exportSyms)))]
              defpkgForm =
                      Serialization.parens (Serialization.newlineSep (Lists.concat [
                        [
                          Serialization.spaceSep [
                            Serialization.cst "defpackage",
                            (Serialization.cst colonName)]],
                        [
                          useClause],
                        exportClause]))
              inpkgForm =
                      Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "in-package",
                        (Serialization.cst colonName)])
          in (Serialization.doubleNewlineSep (Lists.concat [
            warning,
            [
              defpkgForm,
              inpkgForm],
            formPart])))
        Syntax.DialectScheme -> Optionals.cases modDecl (Serialization.doubleNewlineSep (Lists.concat2 warning formPart)) (\m ->
          let nameStr = Syntax.unNamespaceName (Syntax.moduleDeclarationName m)
              nameParts = Lists.map (\p -> Formatting.convertCaseCamelToLowerSnake p) (Strings.splitOn "." nameStr)
              nameExpr = Serialization.parens (Serialization.spaceSepAdaptive (Lists.map (\p -> Serialization.cst p) nameParts))
              domainImportExprs =
                      Lists.map (\idecl ->
                        let nsName = Syntax.unNamespaceName (Syntax.importDeclarationModule idecl)
                            nsParts = Lists.map (\p -> Formatting.convertCaseCamelToLowerSnake p) (Strings.splitOn "." nsName)
                        in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.map (\p -> Serialization.cst p) nsParts)))) imports
              schemeBaseExpr =
                      Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "scheme",
                        (Serialization.cst "base")])
              allImportExprs = Lists.concat2 [
                    schemeBaseExpr] domainImportExprs
              importClause =
                      Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
                        Serialization.cst "import"] allImportExprs))
              exportClauses = Lists.map (\edecl -> exportDeclarationToExpr d edecl) exports
              beginClause = Serialization.parens (Serialization.newlineSep (Lists.concat2 [
                    Serialization.cst "begin"] formPart))
              libraryExpr =
                      Serialization.parens (Serialization.newlineSep (Lists.concat [
                        [
                          Serialization.spaceSep [
                            Serialization.cst "define-library",
                            nameExpr]],
                        exportClauses,
                        [
                          importClause],
                        [
                          beginClause]]))
          in (Serialization.doubleNewlineSep (Lists.concat2 warning [
            libraryExpr])))

-- | Serialize a record type definition
recordTypeDefinitionToExpr :: Syntax.Dialect -> Syntax.RecordTypeDefinition -> Ast.Expr
recordTypeDefinitionToExpr d rdef =

      let name = symbolToExpr (Syntax.recordTypeDefinitionName rdef)
          fields = Lists.map (\f -> symbolToExpr (Syntax.fieldDefinitionName f)) (Syntax.recordTypeDefinitionFields rdef)
      in case d of
        Syntax.DialectClojure ->
          let nameStr = Syntax.unSymbol (Syntax.recordTypeDefinitionName rdef)
              fieldNames = Lists.map (\f -> Syntax.unSymbol (Syntax.fieldDefinitionName f)) (Syntax.recordTypeDefinitionFields rdef)
              defrecordForm =
                      Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst "defrecord",
                        name,
                        (Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep fields))])
              makeAlias =
                      Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
                        [
                          Serialization.cst "defn",
                          (Serialization.cst (Strings.cat2 "make-" nameStr))],
                        [
                          Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep fields)],
                        [
                          Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
                            Serialization.cst (Strings.cat2 "->" nameStr)] (Lists.map (\fn -> Serialization.cst fn) fieldNames)))]]))
          in (Serialization.newlineSep [
            defrecordForm,
            makeAlias])
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "cl-defstruct",
            name],
          fields]))
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
          [
            Serialization.cst "cl:defstruct",
            name],
          fields]))
        Syntax.DialectScheme ->
          let nameStr = Syntax.unSymbol (Syntax.recordTypeDefinitionName rdef)
              fieldNames = Lists.map (\f -> Syntax.unSymbol (Syntax.fieldDefinitionName f)) (Syntax.recordTypeDefinitionFields rdef)
              constructor =
                      Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
                        Serialization.cst (Strings.cat2 "make-" nameStr)] (Lists.map (\fn -> Serialization.cst fn) fieldNames)))
              predicate = Serialization.cst (Strings.cat2 nameStr "?")
              accessors =
                      Lists.map (\fn -> Serialization.parens (Serialization.spaceSepAdaptive [
                        Serialization.cst fn,
                        (Serialization.cst (Strings.cat [
                          nameStr,
                          "-",
                          fn]))])) fieldNames
          in (Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat [
            [
              Serialization.cst "define-record-type",
              name,
              constructor,
              predicate],
            accessors])))

-- | Serialize an S-expression escape hatch
sExpressionToExpr :: Syntax.SExpression -> Ast.Expr
sExpressionToExpr sexpr =
    case sexpr of
      Syntax.SExpressionAtom v0 -> Serialization.cst v0
      Syntax.SExpressionList v0 -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.map sExpressionToExpr v0))

-- | Serialize a set literal
setLiteralToExpr :: Syntax.Dialect -> Syntax.SetLiteral -> Ast.Expr
setLiteralToExpr d sl =

      let elems = Lists.map (expressionToExpr d) (Syntax.setLiteralElements sl)
      in case d of
        Syntax.DialectClojure -> Serialization.noSep [
          Serialization.cst "#",
          (Serialization.brackets Serialization.curlyBraces Serialization.inlineStyle (Serialization.spaceSep elems))]
        Syntax.DialectEmacsLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
          Serialization.cst "list"] elems))
        Syntax.DialectCommonLisp -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
          Serialization.cst "cl:list"] elems))
        Syntax.DialectScheme -> Serialization.parens (Serialization.spaceSepAdaptive (Lists.concat2 [
          Serialization.cst "list"] elems))

-- | Serialize a symbol
symbolToExpr :: Syntax.Symbol -> Ast.Expr
symbolToExpr s = Serialization.cst (Syntax.unSymbol s)

-- | Serialize a top-level form
topLevelFormToExpr :: Syntax.Dialect -> Syntax.TopLevelForm -> Ast.Expr
topLevelFormToExpr d form =
    case form of
      Syntax.TopLevelFormFunction v0 -> functionDefinitionToExpr d v0
      Syntax.TopLevelFormVariable v0 -> variableDefinitionToExpr d v0
      Syntax.TopLevelFormConstant v0 -> constantDefinitionToExpr d v0
      Syntax.TopLevelFormRecordType v0 -> recordTypeDefinitionToExpr d v0
      Syntax.TopLevelFormMacro v0 -> macroDefinitionToExpr d v0
      Syntax.TopLevelFormExpression v0 -> expressionToExpr d v0

-- | Serialize a top-level form together with its comments
topLevelFormWithCommentsToExpr :: Syntax.Dialect -> Syntax.TopLevelFormWithComments -> Ast.Expr
topLevelFormWithCommentsToExpr d fwc =

      let mdoc = Syntax.topLevelFormWithCommentsDoc fwc
          mcomment = Syntax.topLevelFormWithCommentsComment fwc
          form = Syntax.topLevelFormWithCommentsForm fwc
          docPart = Optionals.cases mdoc [] (\ds -> [
                docstringToExpr ds])
          commentPart = Optionals.cases mcomment [] (\c -> [
                commentToExpr c])
          formExpr = topLevelFormToExpr d form
      in (Serialization.newlineSep (Lists.concat [
        commentPart,
        docPart,
        [
          formExpr]]))

-- | The boolean true expression
trueExpr :: Syntax.Dialect -> Ast.Expr
trueExpr d =
    case d of
      Syntax.DialectClojure -> Serialization.cst "true"
      Syntax.DialectEmacsLisp -> Serialization.cst "t"
      Syntax.DialectCommonLisp -> Serialization.cst "cl:t"
      Syntax.DialectScheme -> Serialization.cst "#t"

-- | Serialize a variable definition
variableDefinitionToExpr :: Syntax.Dialect -> Syntax.VariableDefinition -> Ast.Expr
variableDefinitionToExpr d vdef =

      let name = symbolToExpr (Syntax.variableDefinitionName vdef)
          value = expressionToExpr d (Syntax.variableDefinitionValue vdef)
      in (Serialization.parens (Serialization.spaceSepAdaptive [
        Serialization.cst (defKeyword d),
        name,
        value]))

-- | Serialize a variable reference
variableReferenceToExpr :: Syntax.Dialect -> Syntax.VariableReference -> Ast.Expr
variableReferenceToExpr d vref =

      let name = symbolToExpr (Syntax.variableReferenceName vref)
          isFnNs = Syntax.variableReferenceFunctionNamespace vref
      in (Logic.ifElse isFnNs (case d of
        Syntax.DialectCommonLisp -> Serialization.noSep [
          Serialization.cst "#'",
          name]
        Syntax.DialectClojure -> name
        Syntax.DialectEmacsLisp -> name
        Syntax.DialectScheme -> name) name)

-- | Serialize a vector literal
vectorLiteralToExpr :: Syntax.Dialect -> Syntax.VectorLiteral -> Ast.Expr
vectorLiteralToExpr d vl =

      let elems = Lists.map (expressionToExpr d) (Syntax.vectorLiteralElements vl)
      in case d of
        Syntax.DialectClojure -> Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep elems)
        Syntax.DialectEmacsLisp -> Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (Serialization.spaceSep elems)
        Syntax.DialectCommonLisp -> Serialization.noSep [
          Serialization.cst "#",
          (Serialization.parens (Serialization.spaceSepAdaptive elems))]
        Syntax.DialectScheme -> Serialization.noSep [
          Serialization.cst "#",
          (Serialization.parens (Serialization.spaceSepAdaptive elems))]