Skip to content

Commit

Permalink
Add support for a couple of elements (finos#60)
Browse files Browse the repository at this point in the history
* Add support for a couple of elements

- Adds basic support for case/of with Union types with params

```
  case x of
    First a b c -> a
    Second y -> y
```

- Adds support for Maybe case/of patterns

```
  case x of
    Just w -> w
    Nothing -> 19
```

- Adds basic support for conversion of `Maybe.Just` and `Maybe.Nothing`

- Adds a new Scala literal for `null`

* Code review changes
  • Loading branch information
sfc-gh-lfallasavendano committed Dec 13, 2023
1 parent 28877eb commit 09330f5
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 44 deletions.
1 change: 1 addition & 0 deletions src/Morphir/Scala/AST.elm
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ type Lit
| IntegerLit Int
| FloatLit Float
| DecimalLit Decimal
| NullLit


{-| -}
Expand Down
3 changes: 3 additions & 0 deletions src/Morphir/Scala/PrettyPrinter.elm
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,9 @@ mapLit lit =
DecimalLit decimal ->
Decimal.toString decimal

NullLit ->
"null"


statementBlock : Options -> List String -> Doc
statementBlock opt statements =
Expand Down
45 changes: 30 additions & 15 deletions src/Morphir/Snowpark/AccessElementMapping.elm
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,58 @@ import Morphir.Snowpark.MappingContext as MappingContext
import Morphir.IR.FQName as FQName
import Morphir.IR.Literal exposing (Literal(..))
import Morphir.Snowpark.MappingContext exposing (ValueMappingContext)
import Morphir.Snowpark.MappingContext exposing (isUnionTypeWithoutParams)
import Morphir.Snowpark.MappingContext exposing (isUnionTypeWithoutParams
, getReplacementForIdentifier)
import Html.Attributes exposing (name)
import Morphir.IR.FQName as FQName
import Morphir.IR.Value exposing (Value(..))
import Morphir.Snowpark.ReferenceUtils exposing (isValueReferenceToSimpleTypesRecord
, scalaReferenceToUnionTypeCase
, scalaPathToModule)
import Morphir.IR.Value as Value
import Morphir.Snowpark.MappingContext exposing (isAnonymousRecordWithSimpleTypes)
import Morphir.Snowpark.Constants exposing (applySnowparkFunc)

mapFieldAccess : va -> (Value ta (IrType.Type a)) -> Name.Name -> ValueMappingContext -> Scala.Value
mapFieldAccess : va -> (Value ta (IrType.Type ())) -> Name.Name -> ValueMappingContext -> Scala.Value
mapFieldAccess _ value name ctx =
let
(let
simpleFieldName = name |> Name.toCamelCase
valueIsFunctionParameter =
case value of
Value.Variable _ varName -> (varName, List.member varName ctx.parameters)
_ -> (Name.fromString "a",False)
in
case (isValueReferenceToSimpleTypesRecord value ctx.typesContextInfo, valueIsFunctionParameter) of
(_, (paramName, True)) -> Scala.Ref [paramName |> Name.toCamelCase] simpleFieldName
(Just (path, refererName), (_, False)) -> Scala.Ref (path ++ [refererName |> Name.toTitleCase]) simpleFieldName
_ -> Scala.Literal (Scala.StringLit "Field access not converted")

in
case (isValueReferenceToSimpleTypesRecord value ctx.typesContextInfo, valueIsFunctionParameter, value) of
(_, (paramName, True), _) ->
Scala.Ref [paramName |> Name.toCamelCase] simpleFieldName
(Just (path, refererName), (_, False), _) ->
Scala.Ref (path ++ [refererName |> Name.toTitleCase]) simpleFieldName
_ ->
(if isAnonymousRecordWithSimpleTypes (value |> Value.valueAttribute) ctx.typesContextInfo then
applySnowparkFunc "col" [Scala.Literal (Scala.StringLit (Name.toCamelCase name)) ]
else
Scala.Literal (Scala.StringLit "Field access to not converted")))

mapVariableAccess : (IrType.Type a) -> Name.Name -> ValueMappingContext -> Scala.Value
mapVariableAccess _ name _ =
Scala.Variable (name |> Name.toCamelCase)
mapVariableAccess _ name ctx =
case getReplacementForIdentifier name ctx of
Just replacement ->
replacement
_ ->
Scala.Variable (name |> Name.toCamelCase)

mapConstructorAccess : (IrType.Type a) -> FQName.FQName -> ValueMappingContext -> Scala.Value
mapConstructorAccess tpe name ctx =
case tpe of
IrType.Reference _ typeName _ ->
case (tpe, name) of
((IrType.Reference _ _ _), ([ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "nothing" ])) ->
applySnowparkFunc "lit" [Scala.Literal Scala.NullLit]
(IrType.Reference _ typeName _, _) ->
if isUnionTypeWithoutParams typeName ctx.typesContextInfo then
scalaReferenceToUnionTypeCase typeName name
else
(Scala.Literal (Scala.StringLit "Field access not converted"))
_ -> (Scala.Literal (Scala.StringLit "Field access not converted"))
Scala.Literal (Scala.StringLit "Constructor access not converted")
_ ->
Scala.Literal (Scala.StringLit "Constructor access not converted")

mapReferenceAccess : (IrType.Type a) -> FQName.FQName -> Scala.Value
mapReferenceAccess tpe name =
Expand Down
23 changes: 15 additions & 8 deletions src/Morphir/Snowpark/Backend.elm
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Morphir.Scala.PrettyPrinter as PrettyPrinter
import Morphir.TypeSpec.Backend exposing (mapModuleDefinition)
import Morphir.Scala.Common exposing (mapValueName)
import Morphir.IR.Value as Value exposing (Pattern(..), Value(..))
import Morphir.Snowpark.MappingContext as MappingContext
import Morphir.Snowpark.MappingContext as MappingContext exposing (emptyValueMappingContext)
import Morphir.IR.Literal exposing (Literal(..))
import Morphir.Snowpark.Constants as Constants
import Morphir.Snowpark.RecordWrapperGenerator as RecordWrapperGenerator
Expand Down Expand Up @@ -97,7 +97,7 @@ mapModuleDefinition currentPackagePath currentModulePath accessControlledModuleD
|> Dict.toList
|> List.concatMap
(\( valueName, accessControlledValueDef ) ->
[ mapFunctionDefinition valueName accessControlledValueDef mappingCtx
[ mapFunctionDefinition valueName accessControlledValueDef currentPackagePath mappingCtx
]
)
|> List.map Scala.withoutAnnotation
Expand Down Expand Up @@ -133,12 +133,12 @@ mapModuleDefinition currentPackagePath currentModulePath accessControlledModuleD
[ moduleUnit ]


mapFunctionDefinition : Name.Name -> AccessControlled (Documented (Value.Definition () (Type ()))) -> MappingContextInfo () -> Scala.MemberDecl
mapFunctionDefinition functionName body mappingCtx =
mapFunctionDefinition : Name.Name -> AccessControlled (Documented (Value.Definition () (Type ()))) -> Path -> MappingContextInfo () -> Scala.MemberDecl
mapFunctionDefinition functionName body currentPackagePath mappingCtx =
let
(parameters, localVariables) = processParameters body.value.value.inputTypes mappingCtx
parameterNames = body.value.value.inputTypes |> List.map (\(name, _, _) -> name)
valueMappingContext = { typesContextInfo = mappingCtx, parameters = parameterNames }
valueMappingContext = { emptyValueMappingContext | typesContextInfo = mappingCtx, parameters = parameterNames, packagePath = currentPackagePath}
bodyCandidate = mapFunctionBody body.value.value valueMappingContext

resultingBody = case (localVariables, bodyCandidate) of
Expand Down Expand Up @@ -220,9 +220,16 @@ mapValue value ctx =
MapFunctionsMapping.mapFunctionsMapping value mapValue ctx
PatternMatch tpe expr cases ->
mapPatternMatch (tpe, expr, cases) mapValue ctx
IfThenElse _ condition thenExpr elseExpr ->
mapIfThenElse condition thenExpr elseExpr ctx
_ ->
Scala.Literal (Scala.StringLit "To Do")


Scala.Literal (Scala.StringLit ("Unsupported element"))


mapIfThenElse : Value ta (Type ()) -> Value ta (Type ()) -> Value ta (Type ()) -> ValueMappingContext -> Scala.Value
mapIfThenElse condition thenExpr elseExpr ctx =
let
whenCall =
Constants.applySnowparkFunc "when" [ mapValue condition ctx, mapValue thenExpr ctx ]
in
Scala.Apply (Scala.Select whenCall "otherwise") [Scala.ArgValue Nothing (mapValue elseExpr ctx)]
32 changes: 26 additions & 6 deletions src/Morphir/Snowpark/MapFunctionsMapping.elm
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ import Morphir.IR.Type exposing (Type)
import Morphir.Snowpark.MappingContext exposing (ValueMappingContext, isCandidateForDataFrame)
import Morphir.IR.Value exposing (valueAttribute)
import Morphir.IR.Type as TypeIR
import Morphir.Snowpark.MappingContext exposing (isAnonymousRecordWithSimpleTypes)
import Morphir.Snowpark.MappingContext exposing (isAnonymousRecordWithSimpleTypes
, isLocalFunctionName)
import Morphir.IR.Name as Name
import Morphir.Snowpark.Constants exposing (applySnowparkFunc)
import Morphir.Snowpark.MappingContext exposing (isBasicType)
import Morphir.Snowpark.Operatorsmaps exposing (mapOperator)
import Morphir.Snowpark.ReferenceUtils exposing (scalaPathToModule)
import Morphir.Visual.BoolOperatorTree exposing (functionName)
import Morphir.IR.FQName exposing (FQName)
import Morphir.IR.FQName as FQName
import Morphir.Snowpark.MappingContext exposing (isTypeRefToRecordWithSimpleTypes)

type alias MapValueType ta = ValueIR.Value ta (TypeIR.Type ()) -> ValueMappingContext -> Scala.Value

Expand All @@ -33,6 +39,8 @@ mapFunctionsMapping value mapValue ctx =
generateForListFilterMap predicateAction sourceRelation ctx mapValue
ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "sum" ] )) collection ->
generateForListSum collection ctx mapValue
ValueIR.Apply _ (ValueIR.Constructor _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "just" ] )) justValue ->
mapValue justValue ctx
ValueIR.Apply
(TypeIR.Reference () ([["morphir"],["s","d","k"]],[["basics"]], _) [])
(ValueIR.Apply
Expand Down Expand Up @@ -114,12 +122,23 @@ generateForListSum collection ctx mapValue =

generateForListFilter : Value ta (Type ()) -> (Value ta (Type ())) -> ValueMappingContext -> MapValueType ta -> Scala.Value
generateForListFilter predicate sourceRelation ctx mapValue =
let
generateFilterCall functionExpr =
Scala.Apply
(Scala.Select (mapValue sourceRelation ctx) "filter")
[Scala.ArgValue Nothing functionExpr]
in
if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then
case predicate of
ValueIR.Lambda _ _ binExpr ->
Scala.Apply (Scala.Select (mapValue sourceRelation ctx) "filter") [Scala.ArgValue Nothing <| mapValue binExpr ctx]
generateFilterCall <| mapValue binExpr ctx
ValueIR.Reference _ functionName ->
if isLocalFunctionName functionName ctx then
generateFilterCall <| Scala.Ref (scalaPathToModule functionName) (functionName |> FQName.getLocalName |> Name.toCamelCase)
else
Scala.Literal (Scala.StringLit ("Unsupported filter function scenario2" ))
_ ->
Scala.Literal (Scala.StringLit "To Do")
Scala.Literal (Scala.StringLit ("Unsupported filter function scenario" ))
else
Scala.Literal (Scala.StringLit "Unsupported filter scenario")

Expand Down Expand Up @@ -148,15 +167,16 @@ generateForListMap projection sourceRelation ctx mapValue =
Just arguments ->
Scala.Apply (Scala.Select (mapValue sourceRelation ctx) "select") arguments
Nothing ->
Scala.Literal (Scala.StringLit "Unsupported map scenario")
Scala.Literal (Scala.StringLit "Unsupported map scenario 1")
else
Scala.Literal (Scala.StringLit "Unsupported map scenario")
Scala.Literal (Scala.StringLit "Unsupported map scenario 2")

processLambdaWithRecordBody : Value ta (Type ()) -> ValueMappingContext -> MapValueType ta -> Maybe (List Scala.ArgValue)
processLambdaWithRecordBody functionExpr ctx mapValue =
case functionExpr of
ValueIR.Lambda (TypeIR.Function _ _ returnType) (ValueIR.AsPattern _ _ _) (ValueIR.Record _ fields) ->
if isAnonymousRecordWithSimpleTypes returnType ctx.typesContextInfo then
if isAnonymousRecordWithSimpleTypes returnType ctx.typesContextInfo
|| isTypeRefToRecordWithSimpleTypes returnType ctx.typesContextInfo then
Just (fields
|> Dict.toList
|> List.map (\(fieldName, value) -> (Name.toCamelCase fieldName, (mapValue value ctx)))
Expand Down
48 changes: 42 additions & 6 deletions src/Morphir/Snowpark/MappingContext.elm
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ module Morphir.Snowpark.MappingContext exposing
, isTypeAlias
, isUnionTypeWithoutParams
, isUnionTypeWithParams
, isUnionTypeRefWithParams
, isUnionTypeRefWithoutParams
, isBasicType
, MappingContextInfo
, emptyContext
, isCandidateForDataFrame
, ValueMappingContext
, emptyValueMappingContext
, isAnonymousRecordWithSimpleTypes )
, isAnonymousRecordWithSimpleTypes
, getReplacementForIdentifier
, isDataFrameFriendlyType
, isLocalFunctionName
, isTypeRefToRecordWithSimpleTypes )

{-| This module contains functions to collect information about type definitions in a distribution.
It classifies type definitions in the following kinds:
Expand All @@ -24,6 +29,7 @@ It classifies type definitions in the following kinds:
|-}

import Dict exposing (Dict)
import Morphir.Scala.AST as Scala
import Morphir.IR.Type as Type exposing (Type, Type(..), Definition(..))
import Morphir.IR.Module as Module
import Morphir.IR.AccessControlled exposing (AccessControlled)
Expand All @@ -32,6 +38,7 @@ import Morphir.IR.FQName as FQName
import Morphir.IR.Package as Package
import Morphir.IR.Module exposing (ModuleName)
import Morphir.IR.Name exposing (Name)
import Morphir.IR.Path as Path

type TypeDefinitionClassification a =
RecordWithSimpleTypes
Expand All @@ -46,22 +53,38 @@ type alias MappingContextInfo a =
type alias ValueMappingContext =
{ parameters: List Name
, typesContextInfo : MappingContextInfo ()
, inlinedIds: Dict Name Scala.Value
, packagePath: Path.Path
}

emptyValueMappingContext : ValueMappingContext
emptyValueMappingContext = { parameters = []
, typesContextInfo = emptyContext }
, inlinedIds = Dict.empty
, typesContextInfo = emptyContext
, packagePath = Path.fromString "default"
}

getReplacementForIdentifier : Name -> ValueMappingContext -> Maybe Scala.Value
getReplacementForIdentifier name ctx =
Dict.get name ctx.inlinedIds

emptyContext : MappingContextInfo a
emptyContext = Dict.empty

isLocalFunctionName : FQName -> ValueMappingContext -> Bool
isLocalFunctionName name ctx =
(FQName.getPackagePath name) == ctx.packagePath

isRecordWithSimpleTypes : FQName -> MappingContextInfo a -> Bool
isRecordWithSimpleTypes name ctx =
case Dict.get name ctx of
Just (TypeClassified RecordWithSimpleTypes) -> True
_ -> False

isTypeRefToRecordWithSimpleTypes : Type a -> MappingContextInfo a -> Bool
isTypeRefToRecordWithSimpleTypes tpe ctx =
typeRefNamePredicate tpe isRecordWithSimpleTypes ctx

isRecordWithComplexTypes : FQName -> MappingContextInfo a -> Bool
isRecordWithComplexTypes name ctx =
case Dict.get name ctx of
Expand All @@ -74,12 +97,20 @@ isUnionTypeWithoutParams name ctx =
Just (TypeClassified UnionTypeWithoutParams) -> True
_ -> False

isUnionTypeRefWithoutParams : Type a -> MappingContextInfo a -> Bool
isUnionTypeRefWithoutParams tpe ctx =
typeRefNamePredicate : Type a -> (FQName -> MappingContextInfo a -> Bool) -> MappingContextInfo a -> Bool
typeRefNamePredicate tpe predicateToCheckOnName ctx =
case tpe of
Type.Reference _ name _ -> isUnionTypeWithoutParams name ctx
Type.Reference _ name _ -> predicateToCheckOnName name ctx
_ -> False

isUnionTypeRefWithoutParams : Type a -> MappingContextInfo a -> Bool
isUnionTypeRefWithoutParams tpe ctx =
typeRefNamePredicate tpe isUnionTypeWithoutParams ctx

isUnionTypeRefWithParams : Type a -> MappingContextInfo a -> Bool
isUnionTypeRefWithParams tpe ctx =
typeRefNamePredicate tpe isUnionTypeWithParams ctx

isUnionTypeWithParams : FQName -> MappingContextInfo a -> Bool
isUnionTypeWithParams name ctx =
case Dict.get name ctx of
Expand All @@ -92,12 +123,17 @@ isTypeAlias name ctx =
_ -> False

isCandidateForDataFrame : (Type ()) -> MappingContextInfo () -> Bool
isCandidateForDataFrame typeRef ctx=
isCandidateForDataFrame typeRef ctx =
case typeRef of
Type.Reference _
( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] )
[ Type.Reference _ itemTypeName [] ] ->
isRecordWithSimpleTypes itemTypeName ctx
Type.Reference _
( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] )
[ Type.Record _ fields ] ->
fields
|> List.all (\{tpe} -> isDataFrameFriendlyType tpe ctx )
_ -> False

isAnonymousRecordWithSimpleTypes : Type.Type () -> MappingContextInfo () -> Bool
Expand Down
Loading

0 comments on commit 09330f5

Please sign in to comment.