hydra-0.8.0: src/main/haskell/Hydra/Sources/Tier1/Decode.hs
module Hydra.Sources.Tier1.Decode where
-- Standard Tier-1 imports
import Prelude hiding ((++))
import qualified Data.List as L
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Maybe as Y
import Hydra.Dsl.Base as Base
import qualified Hydra.Dsl.Core as Core
import qualified Hydra.Dsl.Graph as Graph
import qualified Hydra.Dsl.Lib.Equality as Equality
import qualified Hydra.Dsl.Lib.Flows as Flows
import qualified Hydra.Dsl.Lib.Io as Io
import qualified Hydra.Dsl.Lib.Lists as Lists
import qualified Hydra.Dsl.Lib.Literals as Literals
import qualified Hydra.Dsl.Lib.Logic as Logic
import qualified Hydra.Dsl.Lib.Maps as Maps
import qualified Hydra.Dsl.Lib.Math as Math
import qualified Hydra.Dsl.Lib.Optionals as Optionals
import qualified Hydra.Dsl.Lib.Sets as Sets
import Hydra.Dsl.Lib.Strings as Strings
import qualified Hydra.Dsl.Module as Module
import qualified Hydra.Dsl.Terms as Terms
import qualified Hydra.Dsl.Types as Types
import Hydra.Sources.Tier0.All
import Hydra.Sources.Tier1.Strip
import qualified Data.Map as M
import qualified Data.Set as S
decodeDefinition :: String -> TTerm a -> TElement a
decodeDefinition = definitionInModule decodeModule
decodeFunctionDefinition :: String -> Type -> Type -> TTerm a -> TElement a
decodeFunctionDefinition name dom cod term = decodeDefinition name $
function dom (optionalT cod) term
decodeNominalFunctionDefinition :: String -> Type -> TTerm a -> TElement a
decodeNominalFunctionDefinition name cod term = decodeDefinition name $
function nameT (funT termT $ optionalT cod) term
decodeModule :: Module
decodeModule = Module (Namespace "hydra/decode") elements [hydraStripModule] tier0Modules $
Just "A module for decoding terms to native objects"
where
elements = [
el bigfloatDef,
el bigfloatValueDef,
el bigintDef,
el bigintValueDef,
el binaryDef,
el binaryLiteralDef,
el booleanDef,
el booleanLiteralDef,
el casesCaseDef,
el casesDef,
el fieldDef,
el float32Def,
el float32ValueDef,
el float64Def,
el float64ValueDef,
el floatLiteralDef,
el int16Def,
el int16ValueDef,
el int32Def,
el int32ValueDef,
el int64Def,
el int64ValueDef,
el int8Def,
el int8ValueDef,
el integerLiteralDef,
el lambdaDef,
el letBindingDef,
el letBindingWithKeyDef,
el letTermDef,
el listDef,
el literalDef,
el mapDef,
el nameDef,
el nominalDef,
el optCasesDef,
el optCasesJustDef,
el optCasesNothingDef,
el optionalDef,
el pairDef,
el recordDef,
el setDef,
el stringDef,
el stringLiteralDef,
el uint16Def,
el uint16ValueDef,
el uint32Def,
el uint32ValueDef,
el uint64Def,
el uint64ValueDef,
el uint8Def,
el uint8ValueDef,
el unitDef,
el unitVariantDef,
el variableDef,
el variantDef,
el wrapDef]
bigfloatDef :: TElement (Term -> Maybe Float)
bigfloatDef = decodeFunctionDefinition "bigfloat" termT bigfloatT $
compose3 (ref literalDef) (ref floatLiteralDef) (ref bigfloatValueDef)
bigfloatValueDef :: TElement (FloatValue -> Maybe Float)
bigfloatValueDef = decodeFunctionDefinition "bigfloatValue" floatValueT bigfloatT $
matchVariant _FloatValue _FloatValue_bigfloat
bigintDef :: TElement (Term -> Maybe Int)
bigintDef = decodeFunctionDefinition "bigint" termT bigintT $
compose3 (ref literalDef) (ref integerLiteralDef) (ref bigintValueDef)
bigintValueDef :: TElement (IntegerValue -> Maybe Int)
bigintValueDef = decodeFunctionDefinition "bigintValue" integerValueT bigintT $
matchVariant _IntegerValue _IntegerValue_bigint
binaryDef :: TElement (Term -> Maybe String)
binaryDef = decodeFunctionDefinition "binary" termT binaryT $
compose2 (ref literalDef) (ref binaryLiteralDef)
binaryLiteralDef :: TElement (Literal -> Maybe String)
binaryLiteralDef = decodeFunctionDefinition "binaryLiteral" literalT binaryT $
matchVariant _Literal _Literal_binary
booleanDef :: TElement (Term -> Maybe Bool)
booleanDef = decodeFunctionDefinition "boolean" termT booleanT $
compose2 (ref literalDef) (ref booleanLiteralDef)
booleanLiteralDef :: TElement (Literal -> Maybe Bool)
booleanLiteralDef = decodeFunctionDefinition "booleanLiteral" literalT booleanT $
matchVariant _Literal _Literal_boolean
casesDef :: TElement (Name -> Term -> Maybe [Field])
casesDef = decodeNominalFunctionDefinition "cases" (listT fieldT) $
ref nominalDef
@@ Core.caseStatementTypeName
@@ Core.caseStatementCases
@@ compose3
(matchTermVariant _Term_function)
(matchVariant _Function _Function_elimination)
(matchVariant _Elimination _Elimination_union)
casesCaseDef :: TElement (Name -> Name -> Term -> Y.Maybe Term)
casesCaseDef = decodeDefinition "casesCase" $
functionN [nameT, nameT, termT, optionalT termT] $
lambda "tname" $ lambda "fname" $
compose2
(ref casesDef @@ var "tname" )
(ref fieldDef @@ var "fname")
fieldDef :: TElement (Name -> [Field] -> Maybe Term)
fieldDef = decodeDefinition "field" $
functionN [nameT, listT fieldT, optionalT termT] $
lambda "fname" $ lambda "fields" ((Logic.ifElse
@@ just (Core.fieldTerm @@ (Lists.head @@ var "matches"))
@@ nothing
@@ (Equality.equal @@ int32 1 @@ (Lists.length @@ var "matches"))
) `with` [
"matches">: Lists.filter @@ (lambda "f" $ Equality.equal @@ (Core.fieldName @@ var "f") @@ var "fname") @@ var "fields"])
float32Def :: TElement (Term -> Maybe Float)
float32Def = decodeFunctionDefinition "float32" termT float32T $
compose3
(ref literalDef)
(ref floatLiteralDef)
(ref float32ValueDef)
float32ValueDef :: TElement (FloatValue -> Maybe Float)
float32ValueDef = decodeFunctionDefinition "float32Value" floatValueT float32T $
matchVariant _FloatValue _FloatValue_float32
float64Def :: TElement (Term -> Maybe Float)
float64Def = decodeFunctionDefinition "float64" termT float64T $
compose3
(ref literalDef)
(ref floatLiteralDef)
(ref float64ValueDef)
float64ValueDef :: TElement (FloatValue -> Maybe Float)
float64ValueDef = decodeFunctionDefinition "float64Value" floatValueT float64T $
matchVariant _FloatValue _FloatValue_float64
floatLiteralDef = decodeFunctionDefinition "floatLiteral" literalT floatValueT $
matchVariant _Literal _Literal_float
int8Def :: TElement (Term -> Maybe Int)
int8Def = decodeFunctionDefinition "int8" termT int8T $
compose3
(ref literalDef)
(ref integerLiteralDef)
(ref int8ValueDef)
int8ValueDef :: TElement (IntegerValue -> Maybe Int)
int8ValueDef = decodeFunctionDefinition "int8Value" integerValueT int8T $
matchVariant _IntegerValue _IntegerValue_int8
int16Def :: TElement (Term -> Maybe Int)
int16Def = decodeFunctionDefinition "int16" termT int16T $
compose3
(ref literalDef)
(ref integerLiteralDef)
(ref int16ValueDef)
int16ValueDef :: TElement (IntegerValue -> Maybe Int)
int16ValueDef = decodeFunctionDefinition "int16Value" integerValueT int16T $
matchVariant _IntegerValue _IntegerValue_int16
int32Def :: TElement (Term -> Maybe Int)
int32Def = decodeFunctionDefinition "int32" termT int32T $
compose3
(ref literalDef)
(ref integerLiteralDef)
(ref int32ValueDef)
int32ValueDef :: TElement (IntegerValue -> Maybe Int)
int32ValueDef = decodeFunctionDefinition "int32Value" integerValueT int32T $
matchVariant _IntegerValue _IntegerValue_int32
int64Def :: TElement (Term -> Maybe Int)
int64Def = decodeFunctionDefinition "int64" termT int64T $
compose3
(ref literalDef)
(ref integerLiteralDef)
(ref int64ValueDef)
int64ValueDef :: TElement (IntegerValue -> Maybe Int)
int64ValueDef = decodeFunctionDefinition "int64Value" integerValueT int64T $
matchVariant _IntegerValue _IntegerValue_int64
integerLiteralDef :: TElement (Literal -> Maybe IntegerValue)
integerLiteralDef = decodeFunctionDefinition "integerLiteral" literalT integerValueT $
matchVariant _Literal _Literal_integer
lambdaDef :: TElement (Term -> Maybe Lambda)
lambdaDef = decodeFunctionDefinition "lambda" termT lambdaT $
compose2
(matchTermVariant _Term_function)
(matchVariant _Function _Function_lambda)
letBindingDef :: TElement (Name -> Term -> Maybe LetBinding)
letBindingDef = decodeDefinition "letBinding" $
functionN [nameT, termT, optionalT letBindingT] $
lambda "fname" $ lambda "term" $ Optionals.bind
@@ (Optionals.map
@@ Core.letBindings
@@ (ref letTermDef @@ var "term"))
@@ (ref letBindingWithKeyDef @@ var "fname")
letBindingWithKeyDef :: TElement (Name -> [LetBinding] -> Maybe LetBinding)
letBindingWithKeyDef = decodeDefinition "letBindingWithKey" $
functionN [nameT, listT letBindingT, optionalT letBindingT] $
lambda "fname" $ lambda "bindings" ((Logic.ifElse
@@ just (Lists.head @@ var "matches")
@@ nothing
@@ (Equality.equal @@ int32 1 @@ (Lists.length @@ var "matches"))
) `with` [
"matches">: Lists.filter @@ (lambda "b" $ Equality.equal @@ (Core.letBindingName @@ var "b") @@ var "fname") @@ var "bindings"])
letTermDef :: TElement (Term -> Maybe Let)
letTermDef = decodeFunctionDefinition "letTerm" termT letT $
matchTermVariant _Term_let
listDef :: TElement (Term -> Maybe [Term])
listDef = decodeFunctionDefinition "list" termT (listT termT) $
matchTermVariant _Term_list
literalDef :: TElement (Term -> Maybe Literal)
literalDef = decodeFunctionDefinition "literal" termT literalT $
matchTermVariant _Term_literal
mapDef :: TElement (Term -> Maybe (M.Map Term Term))
mapDef = decodeFunctionDefinition "map" termT (mapT termT termT) $
matchTermVariant _Term_map
nameDef :: TElement (Term -> Name)
nameDef = decodeFunctionDefinition "name" termT nameT $
lambda "term" $ Optionals.map
@@ nm
@@ (Optionals.bind
@@ (ref wrapDef @@ Core.name _Name @@ var "term")
@@ ref stringDef)
where
nm :: TTerm (String -> Name)
nm = TTerm $ Terms.lambda "s" $ TermWrap $ WrappedTerm _Name $ Terms.var "s"
nominalDef :: TElement ((a -> Name) -> (a -> b) -> (c -> Maybe a) -> Name -> c -> Maybe b)
nominalDef = decodeDefinition "nominal" $
functionN [funT aT nameT, funT aT bT, funT cT (optionalT aT), nameT, cT, optionalT bT] $
lambda "getName" $ lambda "getB" $ lambda "getA" $ lambda "expected" $
compose2
(var "getA")
(lambda "a" $ (Logic.ifElse
@@ (just (var "getB" @@ var "a"))
@@ nothing
@@ (Equality.equal @@ (var "getName" @@ var "a") @@ var "expected")))
optCasesDef :: TElement (Term -> Maybe OptionalCases)
optCasesDef = decodeFunctionDefinition "optCases" termT optionalCasesT $
compose3
(matchTermVariant _Term_function)
(matchVariant _Function _Function_elimination)
(matchVariant _Elimination _Elimination_optional)
optCasesJustDef :: TElement (Term -> Maybe Term)
optCasesJustDef = decodeFunctionDefinition "optCasesJust" termT termT $
lambda "term" $ Optionals.map @@ Core.optionalCasesJust @@ (ref optCasesDef @@ var "term")
optCasesNothingDef :: TElement (Term -> Maybe Term)
optCasesNothingDef = decodeFunctionDefinition "optCasesNothing" termT termT $
lambda "term" $ Optionals.map @@ Core.optionalCasesNothing @@ (ref optCasesDef @@ var "term")
optionalDef :: TElement (Term -> Maybe (Maybe Term))
optionalDef = decodeFunctionDefinition "optional" termT (optionalT termT) $
matchTermVariant _Term_optional
pairDef :: TElement (Term -> Maybe (Term, Term))
pairDef = decodeFunctionDefinition "pair" termT (pairT termT termT) $
compose2
(matchTermVariant _Term_product)
(lambda "l" $ Logic.ifElse
@@ (just $ pair (Lists.at @@ int32 0 @@ var "l") (Lists.at @@ int32 1 @@ var "l"))
@@ nothing
@@ (Equality.equal @@ int32 2 @@ (Lists.length @@ var "l")))
recordDef :: TElement (Name -> Term -> Maybe [Field])
recordDef = decodeNominalFunctionDefinition "record" (listT fieldT) $
matchNominal _Term_record Core.recordTypeName Core.recordFields
setDef :: TElement (Term -> Maybe (S.Set Term))
setDef = decodeFunctionDefinition "set" termT (setT termT) $
matchTermVariant _Term_set
stringDef :: TElement (Term -> Maybe String)
stringDef = decodeFunctionDefinition "string" termT stringT $
compose2 (ref literalDef) (ref stringLiteralDef)
stringLiteralDef :: TElement (Literal -> Maybe String)
stringLiteralDef = decodeFunctionDefinition "stringLiteral" literalT stringT $
matchVariant _Literal _Literal_string
uint8Def :: TElement (Term -> Maybe Int)
uint8Def = decodeFunctionDefinition "uint8" termT uint8T $
compose3 (ref literalDef) (ref integerLiteralDef) (ref uint8ValueDef)
uint8ValueDef :: TElement (IntegerValue -> Maybe Int)
uint8ValueDef = decodeFunctionDefinition "uint8Value" integerValueT uint8T $
matchVariant _IntegerValue _IntegerValue_uint8
uint16Def :: TElement (Term -> Maybe Int)
uint16Def = decodeFunctionDefinition "uint16" termT uint16T $
compose3 (ref literalDef) (ref integerLiteralDef) (ref uint16ValueDef)
uint16ValueDef :: TElement (IntegerValue -> Maybe Int)
uint16ValueDef = decodeFunctionDefinition "uint16Value" integerValueT uint16T $
matchVariant _IntegerValue _IntegerValue_uint16
uint32Def :: TElement (Term -> Maybe Int)
uint32Def = decodeFunctionDefinition "uint32" termT uint32T $
compose3 (ref literalDef) (ref integerLiteralDef) (ref uint32ValueDef)
uint32ValueDef :: TElement (IntegerValue -> Maybe Int)
uint32ValueDef = decodeFunctionDefinition "uint32Value" integerValueT uint32T $
matchVariant _IntegerValue _IntegerValue_uint32
uint64Def :: TElement (Term -> Maybe Int)
uint64Def = decodeFunctionDefinition "uint64" termT uint64T $
compose3 (ref literalDef) (ref integerLiteralDef) (ref uint64ValueDef)
uint64ValueDef :: TElement (IntegerValue -> Maybe Int)
uint64ValueDef = decodeFunctionDefinition "uint64Value" integerValueT uint64T $
matchVariant _IntegerValue _IntegerValue_uint64
unitDef :: TElement (Term -> Maybe ())
unitDef = decodeFunctionDefinition "unit" termT unitT $
lambda "term" $ Optionals.map
@@ (constant unit)
@@ (ref recordDef @@ Core.name _Unit @@ var "term")
unitVariantDef :: TElement (Name -> Term -> Maybe Name)
unitVariantDef = decodeDefinition "unitVariant" $
functionN [nameT, termT, optionalT nameT] $
lambda "tname" $ lambda "term" $ Optionals.map
@@ Core.fieldName
@@ (ref variantDef @@ var "tname" @@ var "term")
variableDef :: TElement (Term -> Y.Maybe Name)
variableDef = decodeFunctionDefinition "variable" termT nameT $
matchTermVariant _Term_variable <.> ref fullyStripTermDef
variantDef :: TElement (Name -> Term -> Maybe Field)
variantDef = decodeNominalFunctionDefinition "variant" fieldT $
matchNominal _Term_union Core.injectionTypeName Core.injectionField
wrapDef :: TElement (Name -> Term -> Maybe Term)
wrapDef = decodeNominalFunctionDefinition "wrap" termT $
matchNominal _Term_wrap Core.wrappedTermTypeName Core.wrappedTermObject
--
compose2 :: TTerm (a -> Maybe b) -> TTerm (b -> Maybe c) -> TTerm (a -> Maybe c)
compose2 f g = Optionals.compose @@ f @@ g
compose3 :: TTerm (a -> Maybe b) -> TTerm (b -> Maybe c) -> TTerm (c -> Maybe d) -> TTerm (a -> Maybe d)
compose3 f g h = Optionals.compose @@ (Optionals.compose @@ f @@ g) @@ h
matchNominal :: Name -> TTerm (a -> Name) -> TTerm (a -> b) -> TTerm (Name -> Term -> Maybe b)
matchNominal fname getName getB = ref nominalDef @@ getName @@ getB @@ matchTermVariant fname
matchTermVariant :: Name -> TTerm (Term -> Maybe a)
matchTermVariant fname = matchVariant _Term fname <.> ref fullyStripTermDef
matchVariant :: Name -> Name -> TTerm (a -> Maybe b)
matchVariant tname fname = match tname (Just nothing) [TCase fname --> Optionals.pure]