packages feed

hydra-0.15.0: src/main/haskell/Hydra/Lisp/Coder.hs

-- Note: this is an automatically generated file. Do not edit.
-- | Lisp code generator: converts Hydra type and term modules to Lisp AST

module Hydra.Lisp.Coder where
import qualified Hydra.Analysis as Analysis
import qualified Hydra.Core as Core
import qualified Hydra.Environment as Environment
import qualified Hydra.Formatting as Formatting
import qualified Hydra.Lib.Eithers as Eithers
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.Maps as Maps
import qualified Hydra.Lib.Maybes as Maybes
import qualified Hydra.Lib.Pairs as Pairs
import qualified Hydra.Lib.Sets as Sets
import qualified Hydra.Lib.Strings as Strings
import qualified Hydra.Lisp.Language as Language
import qualified Hydra.Lisp.Syntax as Syntax
import qualified Hydra.Names as Names
import qualified Hydra.Packaging as Packaging
import qualified Hydra.Predicates as Predicates
import qualified Hydra.Show.Core as ShowCore
import qualified Hydra.Sorting as Sorting
import qualified Hydra.Strip as Strip
import qualified Hydra.Variables as Variables
import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, map, pure, sum)
import qualified Data.Scientific as Sci
dialectCadr :: Syntax.Dialect -> String
dialectCadr d =
    case d of
      Syntax.DialectClojure -> "second"
      _ -> "cadr"
dialectCar :: Syntax.Dialect -> String
dialectCar d =
    case d of
      Syntax.DialectClojure -> "first"
      _ -> "car"
dialectConstructorPrefix :: Syntax.Dialect -> String
dialectConstructorPrefix d =
    case d of
      Syntax.DialectClojure -> "->"
      _ -> "make-"
dialectEqual :: Syntax.Dialect -> String
dialectEqual d =
    case d of
      Syntax.DialectClojure -> "="
      Syntax.DialectCommonLisp -> "equal"
      Syntax.DialectEmacsLisp -> "equal"
      _ -> "equal?"
dialectSupportsLetrec :: Syntax.Dialect -> Bool
dialectSupportsLetrec d =
    case d of
      Syntax.DialectClojure -> False
      _ -> True
encodeApplication :: Syntax.Dialect -> t0 -> t1 -> Core.Term -> Core.Term -> Either t2 Syntax.Expression
encodeApplication dialect cx g rawFun rawArg =

      let dFun = Strip.deannotateTerm rawFun
          normal =
                  Eithers.bind (encodeTerm dialect cx g rawFun) (\fun -> Eithers.bind (encodeTerm dialect cx g rawArg) (\arg -> Right (lispApp fun [
                    arg])))
          enc = \t -> encodeTerm dialect cx g t
      in case dFun of
        Core.TermApplication v0 ->
          let midFun = Core.applicationFunction v0
              midArg = Core.applicationArgument v0
              dMidFun = Strip.deannotateTerm midFun
              isLazy2 =
                      Logic.or (isPrimitiveRef "hydra.lib.eithers.fromLeft" dMidFun) (Logic.or (isPrimitiveRef "hydra.lib.eithers.fromRight" dMidFun) (isPrimitiveRef "hydra.lib.maybes.fromMaybe" dMidFun))
          in (Logic.ifElse isLazy2 (Eithers.bind (enc midFun) (\ePrim -> Eithers.bind (enc midArg) (\eDef -> Eithers.bind (enc rawArg) (\eArg -> Right (lispApp (lispApp ePrim [
            wrapInThunk eDef]) [
            eArg]))))) (case dMidFun of
            Core.TermApplication v1 ->
              let innerFun = Core.applicationFunction v1
                  innerArg = Core.applicationArgument v1
                  dInnerFun = Strip.deannotateTerm innerFun
              in (Logic.ifElse (isPrimitiveRef "hydra.lib.logic.ifElse" dInnerFun) (Eithers.bind (enc innerArg) (\eC -> Eithers.bind (enc midArg) (\eT -> Eithers.bind (enc rawArg) (\eE -> Right (Syntax.ExpressionIf (Syntax.IfExpression {
                Syntax.ifExpressionCondition = eC,
                Syntax.ifExpressionThen = eT,
                Syntax.ifExpressionElse = (Just eE)})))))) (Logic.ifElse (isPrimitiveRef "hydra.lib.maybes.maybe" dInnerFun) (Eithers.bind (enc innerFun) (\eP -> Eithers.bind (enc innerArg) (\eDef -> Eithers.bind (enc midArg) (\eF -> Eithers.bind (enc rawArg) (\eM -> Right (lispApp (lispApp (lispApp eP [
                wrapInThunk eDef]) [
                eF]) [
                eM])))))) (Logic.ifElse (isPrimitiveRef "hydra.lib.maybes.cases" dInnerFun) (Eithers.bind (enc innerFun) (\eP -> Eithers.bind (enc innerArg) (\eM -> Eithers.bind (enc midArg) (\eN -> Eithers.bind (enc rawArg) (\eJ -> Right (lispApp (lispApp (lispApp eP [
                eM]) [
                wrapInThunk eN]) [
                eJ])))))) normal)))
            _ -> normal))
        _ -> normal
encodeFieldDef :: Core.FieldType -> Syntax.FieldDefinition
encodeFieldDef ft =

      let fname = Core.unName (Core.fieldTypeName ft)
      in Syntax.FieldDefinition {
        Syntax.fieldDefinitionName = (Syntax.Symbol (Formatting.convertCaseCamelToLowerSnake fname)),
        Syntax.fieldDefinitionDefaultValue = Nothing}
encodeLambdaTerm :: Syntax.Dialect -> t0 -> t1 -> Core.Lambda -> Either t2 Syntax.Expression
encodeLambdaTerm dialect cx g lam =

      let param =
              Formatting.convertCaseCamelOrUnderscoreToLowerSnake (Formatting.sanitizeWithUnderscores Language.lispReservedWords (Core.unName (Core.lambdaParameter lam)))
      in (Eithers.bind (encodeTerm dialect cx g (Core.lambdaBody lam)) (\body -> Right (lispLambdaExpr [
        param] body)))
encodeLetAsLambdaApp :: Syntax.Dialect -> t0 -> t1 -> [Core.Binding] -> Core.Term -> Either t2 Syntax.Expression
encodeLetAsLambdaApp dialect cx g bindings body =
    Eithers.bind (encodeTerm dialect cx g body) (\bodyExpr -> Eithers.foldl (\acc -> \b ->
      let bname =
              Formatting.convertCaseCamelOrUnderscoreToLowerSnake (Formatting.sanitizeWithUnderscores Language.lispReservedWords (Core.unName (Core.bindingName b)))
      in (Eithers.bind (encodeTerm dialect cx g (Core.bindingTerm b)) (\bval -> Right (lispApp (lispLambdaExpr [
        bname] acc) [
        bval])))) bodyExpr (Lists.reverse bindings))
encodeLetAsNative :: Syntax.Dialect -> t0 -> t1 -> [Core.Binding] -> Core.Term -> Either t2 Syntax.Expression
encodeLetAsNative dialect cx g bindings body =
    Eithers.bind (encodeTerm dialect cx g body) (\bodyExpr ->
      let supportsLetrec = dialectSupportsLetrec dialect
          allNames = Sets.fromList (Lists.map (\b -> Core.bindingName b) bindings)
          adjList =
                  Lists.map (\b -> (Core.bindingName b, (Sets.toList (Sets.intersection allNames (Variables.freeVariablesInTerm (Core.bindingTerm b)))))) bindings
          sccs = Sorting.topologicalSortComponents adjList
          nameToBinding = Maps.fromList (Lists.map (\b -> (Core.bindingName b, b)) bindings)
          sortedBindings = Maybes.cat (Lists.map (\name -> Maps.lookup name nameToBinding) (Lists.concat sccs))
          hasCycle = Lists.foldl (\acc -> \scc -> Logic.or acc (Equality.gt (Lists.length scc) 1)) False sccs
      in (Eithers.bind (Eithers.mapList (\b ->
        let bname =
                Formatting.convertCaseCamelOrUnderscoreToLowerSnake (Formatting.sanitizeWithUnderscores Language.lispReservedWords (Core.unName (Core.bindingName b)))
            isSelfRef = Sets.member (Core.bindingName b) (Variables.freeVariablesInTerm (Core.bindingTerm b))
            isLambda =
                    case (Strip.deannotateTerm (Core.bindingTerm b)) of
                      Core.TermLambda _ -> True
                      _ -> False
        in (Eithers.bind (encodeTerm dialect cx g (Core.bindingTerm b)) (\bval ->
          let isClojure = Logic.not supportsLetrec
              wrappedVal =
                      Logic.ifElse isClojure (Logic.ifElse isSelfRef (Logic.ifElse isLambda (case bval of
                        Syntax.ExpressionLambda v0 -> Syntax.ExpressionLambda (Syntax.Lambda {
                          Syntax.lambdaName = (Just (Syntax.Symbol bname)),
                          Syntax.lambdaParams = (Syntax.lambdaParams v0),
                          Syntax.lambdaRestParam = (Syntax.lambdaRestParam v0),
                          Syntax.lambdaBody = (Syntax.lambdaBody v0)})
                        _ -> bval) (lispNamedLambdaExpr bname [
                        "_arg"] (lispApp bval [
                        lispVar "_arg"]))) bval) (Logic.ifElse (Logic.and isSelfRef (Logic.not isLambda)) (lispLambdaExpr [
                        "_arg"] (lispApp bval [
                        lispVar "_arg"])) bval)
          in (Right (bname, wrappedVal))))) sortedBindings) (\encodedBindings ->
        let hasSelfRef =
                Lists.foldl (\acc -> \b -> Logic.or acc (Sets.member (Core.bindingName b) (Variables.freeVariablesInTerm (Core.bindingTerm b)))) False bindings
            isRecursive = Logic.or hasSelfRef hasCycle
            letKind =
                    Logic.ifElse isRecursive Syntax.LetKindRecursive (Logic.ifElse (Equality.lte (Lists.length bindings) 1) Syntax.LetKindParallel Syntax.LetKindSequential)
            lispBindings =
                    Lists.map (\eb -> Syntax.LetBindingSimple (Syntax.SimpleBinding {
                      Syntax.simpleBindingName = (Syntax.Symbol (Pairs.first eb)),
                      Syntax.simpleBindingValue = (Pairs.second eb)})) encodedBindings
        in (Right (Syntax.ExpressionLet (Syntax.LetExpression {
          Syntax.letExpressionKind = letKind,
          Syntax.letExpressionBindings = lispBindings,
          Syntax.letExpressionBody = [
            bodyExpr]}))))))
encodeLiteral :: Core.Literal -> Syntax.Expression
encodeLiteral lit =
    case lit of
      Core.LiteralBoolean v0 -> Syntax.ExpressionLiteral (Syntax.LiteralBoolean v0)
      Core.LiteralDecimal v0 -> Syntax.ExpressionLiteral (Syntax.LiteralFloat (Syntax.FloatLiteral {
        Syntax.floatLiteralValue = (Literals.float64ToBigfloat (Literals.decimalToFloat64 v0)),
        Syntax.floatLiteralPrecision = Nothing}))
      Core.LiteralString v0 -> Syntax.ExpressionLiteral (Syntax.LiteralString v0)
      Core.LiteralFloat v0 -> case v0 of
        Core.FloatValueFloat32 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralFloat (Syntax.FloatLiteral {
          Syntax.floatLiteralValue = (Literals.float32ToBigfloat v1),
          Syntax.floatLiteralPrecision = Nothing}))
        Core.FloatValueFloat64 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralFloat (Syntax.FloatLiteral {
          Syntax.floatLiteralValue = (Literals.float64ToBigfloat v1),
          Syntax.floatLiteralPrecision = Nothing}))
        Core.FloatValueBigfloat v1 -> Syntax.ExpressionLiteral (Syntax.LiteralFloat (Syntax.FloatLiteral {
          Syntax.floatLiteralValue = v1,
          Syntax.floatLiteralPrecision = Nothing}))
      Core.LiteralInteger v0 -> case v0 of
        Core.IntegerValueInt8 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.int8ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueInt16 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.int16ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueInt32 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.int32ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueInt64 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.int64ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueUint8 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.uint8ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueUint16 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.uint16ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueUint32 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.uint32ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueUint64 v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = (Literals.uint64ToBigint v1),
          Syntax.integerLiteralBigint = False}))
        Core.IntegerValueBigint v1 -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
          Syntax.integerLiteralValue = v1,
          Syntax.integerLiteralBigint = True}))
      Core.LiteralBinary v0 ->
        let byteValues = Literals.binaryToBytes v0
        in (Syntax.ExpressionVector (Syntax.VectorLiteral {
          Syntax.vectorLiteralElements = (Lists.map (\bv -> Syntax.ExpressionLiteral (Syntax.LiteralInteger (Syntax.IntegerLiteral {
            Syntax.integerLiteralValue = (Literals.int32ToBigint bv),
            Syntax.integerLiteralBigint = False}))) byteValues)}))
encodeProjectionElim :: Syntax.Dialect -> t0 -> t1 -> Core.Projection -> Maybe Core.Term -> Either t2 Syntax.Expression
encodeProjectionElim dialect cx g proj marg =

      let fname = Formatting.convertCaseCamelToLowerSnake (Core.unName (Core.projectionField proj))
          tname = qualifiedSnakeName (Core.projectionTypeName proj)
      in (Maybes.cases marg (Right (lispLambdaExpr [
        "v"] (Syntax.ExpressionFieldAccess (Syntax.FieldAccess {
        Syntax.fieldAccessRecordType = (Syntax.Symbol tname),
        Syntax.fieldAccessField = (Syntax.Symbol fname),
        Syntax.fieldAccessTarget = (lispVar "v")})))) (\arg -> Eithers.bind (encodeTerm dialect cx g arg) (\sarg -> Right (Syntax.ExpressionFieldAccess (Syntax.FieldAccess {
        Syntax.fieldAccessRecordType = (Syntax.Symbol tname),
        Syntax.fieldAccessField = (Syntax.Symbol fname),
        Syntax.fieldAccessTarget = sarg})))))
encodeTerm :: Syntax.Dialect -> t0 -> t1 -> Core.Term -> Either t2 Syntax.Expression
encodeTerm dialect cx g term =
    case term of
      Core.TermAnnotated v0 -> encodeTerm dialect cx g (Core.annotatedTermBody v0)
      Core.TermApplication v0 ->
        let rawFun = Core.applicationFunction v0
            rawArg = Core.applicationArgument v0
        in (encodeApplication dialect cx g rawFun rawArg)
      Core.TermEither v0 -> Eithers.either (\l -> Eithers.bind (encodeTerm dialect cx g l) (\sl -> Right (lispApp (lispVar "list") [
        lispKeyword "left",
        sl]))) (\r -> Eithers.bind (encodeTerm dialect cx g r) (\sr -> Right (lispApp (lispVar "list") [
        lispKeyword "right",
        sr]))) v0
      Core.TermLambda v0 -> encodeLambdaTerm dialect cx g v0
      Core.TermProject v0 -> encodeProjectionElim dialect cx g v0 Nothing
      Core.TermCases v0 -> encodeUnionElim dialect cx g v0 Nothing
      Core.TermUnwrap v0 -> encodeUnwrapElim dialect cx g v0 Nothing
      Core.TermLet v0 ->
        let bindings = Core.letBindings v0
            body = Core.letBody v0
        in (encodeLetAsNative dialect cx g bindings body)
      Core.TermList v0 -> Eithers.bind (Eithers.mapList (encodeTerm dialect cx g) v0) (\sels -> Right (lispListExpr sels))
      Core.TermLiteral v0 -> Right (encodeLiteral v0)
      Core.TermMap v0 -> Eithers.bind (Eithers.mapList (\entry -> Eithers.bind (encodeTerm dialect cx g (Pairs.first entry)) (\k -> Eithers.bind (encodeTerm dialect cx g (Pairs.second entry)) (\v -> Right (Syntax.MapEntry {
        Syntax.mapEntryKey = k,
        Syntax.mapEntryValue = v})))) (Maps.toList v0)) (\pairs -> Right (Syntax.ExpressionMap (Syntax.MapLiteral {
        Syntax.mapLiteralEntries = pairs})))
      Core.TermMaybe v0 -> Maybes.cases v0 (Right (lispApp (lispVar "list") [
        lispKeyword "nothing"])) (\val -> Eithers.bind (encodeTerm dialect cx g val) (\sval -> Right (lispApp (lispVar "list") [
        lispKeyword "just",
        sval])))
      Core.TermPair v0 -> Eithers.bind (encodeTerm dialect cx g (Pairs.first v0)) (\f -> Eithers.bind (encodeTerm dialect cx g (Pairs.second v0)) (\s -> Right (lispListExpr [
        f,
        s])))
      Core.TermRecord v0 ->
        let rname = Core.recordTypeName v0
            fields = Core.recordFields v0
        in (Eithers.bind (Eithers.mapList (\f -> encodeTerm dialect cx g (Core.fieldTerm f)) fields) (\sfields ->
          let constructorName = Strings.cat2 (dialectConstructorPrefix dialect) (qualifiedSnakeName rname)
          in (Right (lispApp (lispVar constructorName) sfields))))
      Core.TermSet v0 -> Eithers.bind (Eithers.mapList (encodeTerm dialect cx g) (Sets.toList v0)) (\sels -> Right (Syntax.ExpressionSet (Syntax.SetLiteral {
        Syntax.setLiteralElements = sels})))
      Core.TermInject v0 ->
        let tname = Names.localNameOf (Core.injectionTypeName v0)
            field = Core.injectionField v0
            fname = Core.unName (Core.fieldName field)
            fterm = Core.fieldTerm field
            dterm = Strip.deannotateTerm fterm
            isUnit =
                    case dterm of
                      Core.TermUnit -> True
                      Core.TermRecord v1 -> Lists.null (Core.recordFields v1)
                      _ -> False
        in (Logic.ifElse isUnit (Right (lispApp (lispVar "list") [
          lispKeyword (Formatting.convertCaseCamelToLowerSnake fname),
          lispNilExpr])) (Eithers.bind (encodeTerm dialect cx g fterm) (\sval -> Right (lispApp (lispVar "list") [
          lispKeyword (Formatting.convertCaseCamelToLowerSnake fname),
          sval]))))
      Core.TermUnit -> Right lispNilExpr
      Core.TermVariable v0 -> Right (lispVar (Formatting.convertCaseCamelOrUnderscoreToLowerSnake (Formatting.sanitizeWithUnderscores Language.lispReservedWords (Core.unName v0))))
      Core.TermTypeApplication v0 -> encodeTerm dialect cx g (Core.typeApplicationTermBody v0)
      Core.TermTypeLambda v0 -> encodeTerm dialect cx g (Core.typeLambdaBody v0)
      Core.TermWrap v0 -> encodeTerm dialect cx g (Core.wrappedTermBody v0)
encodeTermDefinition :: Syntax.Dialect -> t0 -> t1 -> Packaging.TermDefinition -> Either t2 Syntax.TopLevelFormWithComments
encodeTermDefinition dialect cx g tdef =

      let name = Packaging.termDefinitionName tdef
          term = Packaging.termDefinitionTerm tdef
          lname = qualifiedSnakeName name
          dterm = Strip.deannotateTerm term
      in case dterm of
        Core.TermLambda _ -> Eithers.bind (encodeTerm dialect cx g term) (\sterm -> Right (lispTopForm (Syntax.TopLevelFormVariable (Syntax.VariableDefinition {
          Syntax.variableDefinitionName = (Syntax.Symbol lname),
          Syntax.variableDefinitionValue = sterm,
          Syntax.variableDefinitionDoc = Nothing}))))
        _ -> Eithers.bind (encodeTerm dialect cx g term) (\sterm -> Right (lispTopForm (Syntax.TopLevelFormVariable (Syntax.VariableDefinition {
          Syntax.variableDefinitionName = (Syntax.Symbol lname),
          Syntax.variableDefinitionValue = sterm,
          Syntax.variableDefinitionDoc = Nothing}))))
encodeType :: t0 -> t1 -> Core.Type -> Either t2 Syntax.TypeSpecifier
encodeType cx g t =

      let typ = Strip.deannotateType t
      in case typ of
        Core.TypeAnnotated v0 -> encodeType cx g (Core.annotatedTypeBody v0)
        Core.TypeApplication v0 -> encodeType cx g (Core.applicationTypeFunction v0)
        Core.TypeUnit -> Right Syntax.TypeSpecifierUnit
        Core.TypeLiteral v0 -> Right (case v0 of
          Core.LiteralTypeBinary -> Syntax.TypeSpecifierNamed (Syntax.Symbol "ByteArray")
          Core.LiteralTypeBoolean -> Syntax.TypeSpecifierNamed (Syntax.Symbol "Boolean")
          Core.LiteralTypeDecimal -> Syntax.TypeSpecifierNamed (Syntax.Symbol "Decimal")
          Core.LiteralTypeFloat _ -> Syntax.TypeSpecifierNamed (Syntax.Symbol "Float")
          Core.LiteralTypeInteger _ -> Syntax.TypeSpecifierNamed (Syntax.Symbol "Integer")
          Core.LiteralTypeString -> Syntax.TypeSpecifierNamed (Syntax.Symbol "String"))
        Core.TypeList v0 -> Eithers.map (\enc -> Syntax.TypeSpecifierList enc) (encodeType cx g v0)
        Core.TypeSet v0 -> Eithers.map (\enc -> Syntax.TypeSpecifierSet enc) (encodeType cx g v0)
        Core.TypeMap _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Map"))
        Core.TypeMaybe v0 -> Eithers.map (\enc -> Syntax.TypeSpecifierMaybe enc) (encodeType cx g v0)
        Core.TypeEither _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Either"))
        Core.TypePair _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Pair"))
        Core.TypeFunction _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Function"))
        Core.TypeRecord _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Record"))
        Core.TypeUnion _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Union"))
        Core.TypeWrap _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Wrapper"))
        Core.TypeVariable v0 -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol (Core.unName v0)))
        Core.TypeForall v0 -> encodeType cx g (Core.forallTypeBody v0)
        _ -> Right (Syntax.TypeSpecifierNamed (Syntax.Symbol "Any"))
encodeTypeBody :: String -> Core.Type -> Core.Type -> Either t0 Syntax.TopLevelFormWithComments
encodeTypeBody lname origTyp typ =
    case typ of
      Core.TypeForall v0 -> encodeTypeBody lname origTyp (Core.forallTypeBody v0)
      Core.TypeRecord v0 ->
        let fields = Lists.map encodeFieldDef v0
        in (Right (lispTopForm (Syntax.TopLevelFormRecordType (Syntax.RecordTypeDefinition {
          Syntax.recordTypeDefinitionName = (Syntax.Symbol lname),
          Syntax.recordTypeDefinitionFields = fields,
          Syntax.recordTypeDefinitionDoc = Nothing}))))
      Core.TypeUnion v0 ->
        let variantNames =
                Lists.map (\f -> Syntax.ExpressionLiteral (Syntax.LiteralKeyword (Syntax.Keyword {
                  Syntax.keywordName = (Formatting.convertCaseCamelToLowerSnake (Core.unName (Core.fieldTypeName f))),
                  Syntax.keywordNamespace = Nothing}))) v0
        in (Right (lispTopForm (Syntax.TopLevelFormVariable (Syntax.VariableDefinition {
          Syntax.variableDefinitionName = (Syntax.Symbol (Strings.cat2 lname "-variants")),
          Syntax.variableDefinitionValue = (lispListExpr variantNames),
          Syntax.variableDefinitionDoc = (Just (Syntax.Docstring (Strings.cat2 "Variants of the " lname)))}))))
      Core.TypeWrap _ -> Right (lispTopForm (Syntax.TopLevelFormRecordType (Syntax.RecordTypeDefinition {
        Syntax.recordTypeDefinitionName = (Syntax.Symbol lname),
        Syntax.recordTypeDefinitionFields = [
          Syntax.FieldDefinition {
            Syntax.fieldDefinitionName = (Syntax.Symbol "value"),
            Syntax.fieldDefinitionDefaultValue = Nothing}],
        Syntax.recordTypeDefinitionDoc = Nothing})))
      _ -> Right (Syntax.TopLevelFormWithComments {
        Syntax.topLevelFormWithCommentsDoc = Nothing,
        Syntax.topLevelFormWithCommentsComment = (Just (Syntax.Comment {
          Syntax.commentStyle = Syntax.CommentStyleLine,
          Syntax.commentText = (Strings.cat2 (Strings.cat2 lname " = ") (ShowCore.type_ origTyp))})),
        Syntax.topLevelFormWithCommentsForm = (Syntax.TopLevelFormExpression (Syntax.ExpressionLiteral Syntax.LiteralNil))})
encodeTypeDefinition :: t0 -> t1 -> Packaging.TypeDefinition -> Either t2 Syntax.TopLevelFormWithComments
encodeTypeDefinition cx g tdef =

      let name = Packaging.typeDefinitionName tdef
          typ = Core.typeSchemeBody (Packaging.typeDefinitionTypeScheme tdef)
          lname = qualifiedSnakeName name
          dtyp = Strip.deannotateType typ
      in (encodeTypeBody lname typ dtyp)
encodeUnionElim :: Syntax.Dialect -> t0 -> t1 -> Core.CaseStatement -> Maybe Core.Term -> Either t2 Syntax.Expression
encodeUnionElim dialect cx g cs marg =

      let tname = Names.localNameOf (Core.caseStatementTypeName cs)
          caseFields = Core.caseStatementCases cs
          defCase = Core.caseStatementDefault cs
      in (Eithers.bind (Eithers.mapList (\cf ->
        let cfname = Formatting.convertCaseCamelToLowerSnake (Core.unName (Core.fieldName cf))
            cfterm = Core.fieldTerm cf
            condExpr =
                    lispApp (lispVar (dialectEqual dialect)) [
                      lispApp (lispVar (dialectCar dialect)) [
                        lispVar "match_target"],
                      (lispKeyword cfname)]
        in (Eithers.bind (encodeTerm dialect cx g (Core.TermApplication (Core.Application {
          Core.applicationFunction = cfterm,
          Core.applicationArgument = (Core.TermVariable (Core.Name "match_value"))}))) (\bodyExpr -> Right (Syntax.CondClause {
          Syntax.condClauseCondition = condExpr,
          Syntax.condClauseBody = bodyExpr})))) caseFields) (\clauses -> Eithers.bind (Maybes.cases defCase (Right Nothing) (\dt -> Eithers.bind (encodeTerm dialect cx g dt) (\defBody -> Right (Just defBody)))) (\defExpr ->
        let condExpr =
                Syntax.ExpressionCond (Syntax.CondExpression {
                  Syntax.condExpressionClauses = clauses,
                  Syntax.condExpressionDefault = defExpr})
            innerExpr =
                    lispApp (lispLambdaExpr [
                      "match_value"] condExpr) [
                      lispApp (lispVar (dialectCadr dialect)) [
                        lispVar "match_target"]]
        in (Maybes.cases marg (Right (lispLambdaExpr [
          "match_target"] innerExpr)) (\arg -> Eithers.bind (encodeTerm dialect cx g arg) (\sarg -> Right (lispApp (lispLambdaExpr [
          "match_target"] innerExpr) [
          sarg])))))))
encodeUnwrapElim :: Syntax.Dialect -> t0 -> t1 -> Core.Name -> Maybe Core.Term -> Either t2 Syntax.Expression
encodeUnwrapElim dialect cx g name marg =
    Maybes.cases marg (Right (lispLambdaExpr [
      "v"] (lispVar "v"))) (\arg -> encodeTerm dialect cx g arg)
isCasesPrimitive :: Core.Name -> Bool
isCasesPrimitive name = Equality.equal name (Core.Name "hydra.lib.maybes.cases")
isLazy2ArgPrimitive :: Core.Name -> Bool
isLazy2ArgPrimitive name =
    Logic.or (Equality.equal name (Core.Name "hydra.lib.eithers.fromLeft")) (Logic.or (Equality.equal name (Core.Name "hydra.lib.eithers.fromRight")) (Equality.equal name (Core.Name "hydra.lib.maybes.fromMaybe")))
isLazy3ArgPrimitive :: Core.Name -> Bool
isLazy3ArgPrimitive name = Equality.equal name (Core.Name "hydra.lib.maybes.maybe")
isPrimitiveRef :: String -> Core.Term -> Bool
isPrimitiveRef primName term =
    case term of
      Core.TermVariable v0 -> Equality.equal (Core.unName v0) primName
      Core.TermAnnotated v0 -> isPrimitiveRef primName (Core.annotatedTermBody v0)
      Core.TermTypeApplication v0 -> isPrimitiveRef primName (Core.typeApplicationTermBody v0)
      Core.TermTypeLambda v0 -> isPrimitiveRef primName (Core.typeLambdaBody v0)
      _ -> False
lispApp :: Syntax.Expression -> [Syntax.Expression] -> Syntax.Expression
lispApp fun args =
    Syntax.ExpressionApplication (Syntax.Application {
      Syntax.applicationFunction = fun,
      Syntax.applicationArguments = args})
lispKeyword :: String -> Syntax.Expression
lispKeyword name =
    Syntax.ExpressionLiteral (Syntax.LiteralKeyword (Syntax.Keyword {
      Syntax.keywordName = name,
      Syntax.keywordNamespace = Nothing}))
lispLambdaExpr :: [String] -> Syntax.Expression -> Syntax.Expression
lispLambdaExpr params body =
    Syntax.ExpressionLambda (Syntax.Lambda {
      Syntax.lambdaName = Nothing,
      Syntax.lambdaParams = (Lists.map (\p -> Syntax.Symbol p) params),
      Syntax.lambdaRestParam = Nothing,
      Syntax.lambdaBody = [
        body]})
lispListExpr :: [Syntax.Expression] -> Syntax.Expression
lispListExpr elements =
    Syntax.ExpressionList (Syntax.ListLiteral {
      Syntax.listLiteralElements = elements,
      Syntax.listLiteralQuoted = False})
lispLitExpr :: Syntax.Literal -> Syntax.Expression
lispLitExpr lit = Syntax.ExpressionLiteral lit
lispNamedLambdaExpr :: String -> [String] -> Syntax.Expression -> Syntax.Expression
lispNamedLambdaExpr name params body =
    Syntax.ExpressionLambda (Syntax.Lambda {
      Syntax.lambdaName = (Just (Syntax.Symbol name)),
      Syntax.lambdaParams = (Lists.map (\p -> Syntax.Symbol p) params),
      Syntax.lambdaRestParam = Nothing,
      Syntax.lambdaBody = [
        body]})
lispNilExpr :: Syntax.Expression
lispNilExpr = Syntax.ExpressionLiteral Syntax.LiteralNil
lispSymbol :: String -> Syntax.Symbol
lispSymbol name = Syntax.Symbol name
lispTopForm :: Syntax.TopLevelForm -> Syntax.TopLevelFormWithComments
lispTopForm form =
    Syntax.TopLevelFormWithComments {
      Syntax.topLevelFormWithCommentsDoc = Nothing,
      Syntax.topLevelFormWithCommentsComment = Nothing,
      Syntax.topLevelFormWithCommentsForm = form}
lispTopFormWithComments :: Maybe String -> Syntax.TopLevelForm -> Syntax.TopLevelFormWithComments
lispTopFormWithComments mdoc form =
    Syntax.TopLevelFormWithComments {
      Syntax.topLevelFormWithCommentsDoc = (Maybes.map (\d -> Syntax.Docstring d) mdoc),
      Syntax.topLevelFormWithCommentsComment = Nothing,
      Syntax.topLevelFormWithCommentsForm = form}
lispVar :: String -> Syntax.Expression
lispVar name =
    Syntax.ExpressionVariable (Syntax.VariableReference {
      Syntax.variableReferenceName = (Syntax.Symbol name),
      Syntax.variableReferenceFunctionNamespace = False})
moduleExports :: [Syntax.TopLevelFormWithComments] -> [Syntax.ExportDeclaration]
moduleExports forms =

      let symbols =
              Lists.concat (Lists.map (\fwc ->
                let form = Syntax.topLevelFormWithCommentsForm fwc
                in case form of
                  Syntax.TopLevelFormVariable v0 -> [
                    Syntax.variableDefinitionName v0]
                  Syntax.TopLevelFormRecordType v0 ->
                    let rname = Syntax.unSymbol (Syntax.recordTypeDefinitionName v0)
                        fields = Syntax.recordTypeDefinitionFields v0
                        fieldSyms =
                                Lists.map (\f ->
                                  let fn = Syntax.unSymbol (Syntax.fieldDefinitionName f)
                                  in (Syntax.Symbol (Strings.cat [
                                    rname,
                                    "-",
                                    fn]))) fields
                    in (Lists.concat [
                      [
                        Syntax.Symbol (Strings.cat2 "make-" rname),
                        (Syntax.Symbol (Strings.cat2 rname "?"))],
                      fieldSyms])
                  _ -> []) forms)
      in (Logic.ifElse (Lists.null symbols) [] [
        Syntax.ExportDeclaration {
          Syntax.exportDeclarationSymbols = symbols}])
moduleImports :: Packaging.Namespace -> [Packaging.Definition] -> [Syntax.ImportDeclaration]
moduleImports focusNs defs =

      let depNss = Sets.toList (Sets.delete focusNs (Analysis.definitionDependencyNamespaces defs))
      in (Lists.map (\ns -> Syntax.ImportDeclaration {
        Syntax.importDeclarationModule = (Syntax.NamespaceName (Packaging.unNamespace ns)),
        Syntax.importDeclarationSpec = Syntax.ImportSpecAll}) depNss)
moduleToLisp :: Syntax.Dialect -> Packaging.Module -> [Packaging.Definition] -> t0 -> t1 -> Either t2 Syntax.Program
moduleToLisp dialect mod defs0 cx g =

      let defs = Environment.reorderDefs defs0
          partitioned = Environment.partitionDefinitions defs
          allTypeDefs = Pairs.first partitioned
          termDefs = Pairs.second partitioned
          typeDefs =
                  Lists.filter (\td -> Predicates.isNominalType (Core.typeSchemeBody (Packaging.typeDefinitionTypeScheme td))) allTypeDefs
      in (Eithers.bind (Eithers.mapList (encodeTypeDefinition cx g) typeDefs) (\typeItems -> Eithers.bind (Eithers.mapList (encodeTermDefinition dialect cx g) termDefs) (\termItems ->
        let allItems = Lists.concat2 typeItems termItems
            nsName = Packaging.unNamespace (Packaging.moduleNamespace mod)
            focusNs = Packaging.moduleNamespace mod
            imports = moduleImports focusNs defs
            exports = moduleExports allItems
        in (Right (Syntax.Program {
          Syntax.programDialect = dialect,
          Syntax.programModule = (Just (Syntax.ModuleDeclaration {
            Syntax.moduleDeclarationName = (Syntax.NamespaceName nsName),
            Syntax.moduleDeclarationDoc = Nothing})),
          Syntax.programImports = imports,
          Syntax.programExports = exports,
          Syntax.programForms = allItems})))))
qualifiedSnakeName :: Core.Name -> String
qualifiedSnakeName name =

      let raw = Core.unName name
          parts = Strings.splitOn "." raw
          snakeParts = Lists.map (\p -> Formatting.convertCaseCamelOrUnderscoreToLowerSnake p) parts
          joined = Strings.intercalate "_" snakeParts
      in (Formatting.sanitizeWithUnderscores Language.lispReservedWords joined)
qualifiedTypeName :: Core.Name -> String
qualifiedTypeName name = Formatting.capitalize (Names.localNameOf name)
wrapInThunk :: Syntax.Expression -> Syntax.Expression
wrapInThunk expr =
    Syntax.ExpressionLambda (Syntax.Lambda {
      Syntax.lambdaName = Nothing,
      Syntax.lambdaParams = [],
      Syntax.lambdaRestParam = Nothing,
      Syntax.lambdaBody = [
        expr]})