Skip to content

Commit

Permalink
Let expression support in frontend (#63)
Browse files Browse the repository at this point in the history
* Added missing module declarations. #37

* Process only those modules that are reachable from exposed ones. Remove package path from module names. #21

* Renaming concepts based on review feedback. #41

* Moved Advanced module up a level. #43

* Removed unused unindent function.

* Moved name to SDK.

* Added missing module to SDK.

* Partial implementation of value mapping.

* Ignore all generated JS.

* Change extra arg position and naming. #46, #25

* Change extra arg position and naming. #46, #25

* Removed remaining references to extra. #5

* Change extra arg position. #46, #25, #5

* Added more coverage. #46, #25, #5

* Changes suggested in the PR. #46, #25, #5

* Use more explicit names.

* All patterns supported.

* Pattern-match supported.

* Added support for SDK operators. #52

* Fix compile errors.

* Prepare Elm module publishing. #2

* Fix repo name. #2

* Support for let expressions. #54
  • Loading branch information
AttilaMihaly committed Apr 16, 2020
1 parent 67b8474 commit 9f7e736
Show file tree
Hide file tree
Showing 7 changed files with 555 additions and 58 deletions.
1 change: 1 addition & 0 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"elm/json": "1.1.3 <= v < 2.0.0",
"elm/parser": "1.1.0 <= v < 2.0.0",
"elm/regex": "1.0.0 <= v < 2.0.0",
"elm-community/graph": "6.0.0 <= v < 7.0.0",
"elm-explorations/test": "1.2.2 <= v < 2.0.0",
"stil4m/elm-syntax": "7.1.1 <= v < 8.0.0"
},
Expand Down
294 changes: 277 additions & 17 deletions src/Morphir/Elm/Frontend.elm

Large diffs are not rendered by default.

64 changes: 32 additions & 32 deletions src/Morphir/Graph.elm
Original file line number Diff line number Diff line change
@@ -1,72 +1,75 @@
module Morphir.Graph exposing (Graph, empty, fromDict, fromList, isEmpty, reachableNodes, topologicalSort)
module Morphir.Graph exposing (Graph, empty, fromList, isEmpty, reachableNodes, topologicalSort)

import Dict exposing (Dict)
import Set exposing (Set)


type Graph comparable
= Graph (Dict comparable (Set comparable))
type Graph node comparable
= Graph (List ( node, comparable, Set comparable ))


fromDict : Dict comparable (Set comparable) -> Graph comparable
fromDict =
Graph


fromList : List ( comparable, List comparable ) -> Graph comparable
fromList : List ( node, comparable, List comparable ) -> Graph node comparable
fromList list =
list
|> List.map (\( from, tos ) -> ( from, Set.fromList tos ))
|> Dict.fromList
|> List.map (\( node, fromKey, toKeys ) -> ( node, fromKey, Set.fromList toKeys ))
|> Graph


empty : Graph comparable
empty : Graph node comparable
empty =
Graph Dict.empty
Graph []


isEmpty : Graph comparable -> Bool
isEmpty : Graph node comparable -> Bool
isEmpty (Graph edges) =
Dict.isEmpty edges
List.isEmpty edges


topologicalSort : Graph comparable -> ( List comparable, Graph comparable )
topologicalSort : Graph node comparable -> ( List comparable, Graph node comparable )
topologicalSort (Graph edges) =
let
normalize : List ( node, comparable, Set comparable ) -> List ( node, comparable, Set comparable )
normalize graphEdges =
let
toNodes =
graphEdges
|> Dict.values
|> List.map (\( _, _, toKeys ) -> toKeys)
|> List.foldl Set.union Set.empty

fromNodes =
graphEdges
|> Dict.keys
|> List.map (\( _, fromKey, _ ) -> fromKey)
|> Set.fromList

emptyFromNodes =
Set.diff toNodes fromNodes
|> Set.toList
|> List.map
(\from ->
( from, Set.empty )
|> List.concatMap
(\fromKey ->
graphEdges
|> List.filterMap
(\( node, key, _ ) ->
if key == fromKey then
Just ( node, fromKey, Set.empty )

else
Nothing
)
)
|> Dict.fromList
in
Dict.union graphEdges emptyFromNodes
graphEdges ++ emptyFromNodes

step : List ( node, comparable, Set comparable ) -> List comparable -> ( List comparable, Graph node comparable )
step graphEdges sorting =
let
toNodes =
graphEdges
|> Dict.values
|> List.map (\( _, _, toKeys ) -> toKeys)
|> List.foldl Set.union Set.empty

fromNodes =
graphEdges
|> Dict.keys
|> List.map (\( _, fromKey, _ ) -> fromKey)
|> Set.fromList

startNodes =
Expand All @@ -77,12 +80,10 @@ topologicalSort (Graph edges) =
let
newGraphEdges =
graphEdges
|> Dict.toList
|> List.filter
(\( from, tos ) ->
from /= startNode
(\( _, fromKey, _ ) ->
fromKey /= startNode
)
|> Dict.fromList
in
step newGraphEdges (startNode :: sorting)

Expand All @@ -92,15 +93,14 @@ topologicalSort (Graph edges) =
step (normalize edges) []


reachableNodes : Set comparable -> Graph comparable -> Set comparable
reachableNodes : Set comparable -> Graph node comparable -> Set comparable
reachableNodes startNodes (Graph edges) =
let
directlyReachable : Set comparable -> Set comparable
directlyReachable fromNodes =
edges
|> Dict.toList
|> List.filterMap
(\( fromNode, toNodes ) ->
(\( _, fromNode, toNodes ) ->
if fromNodes |> Set.member fromNode then
Just toNodes

Expand Down
98 changes: 93 additions & 5 deletions src/Morphir/IR/Value.elm
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ which is just the specification of those. Value definitions can be typed or unty
-}

import Dict exposing (Dict)
import Json.Decode as Decode
import Json.Encode as Encode
import Morphir.IR.FQName exposing (FQName, decodeFQName, encodeFQName)
import Morphir.IR.Name exposing (Name, decodeName, encodeName)
import Morphir.IR.Type as Type exposing (Type, decodeType, encodeType)
import Morphir.ResultList as ResultList
import Morphir.Rewrite exposing (Rewrite)
import String


Expand All @@ -88,7 +90,7 @@ type Value a
| Apply a (Value a) (Value a)
| Lambda a (Pattern a) (Value a)
| LetDefinition a Name (Definition a) (Value a)
| LetRecursion a (List ( Name, Definition a )) (Value a)
| LetRecursion a (Dict Name (Definition a)) (Value a)
| Destructure a (Pattern a) (Value a) (Value a)
| IfThenElse a (Value a) (Value a) (Value a)
| PatternMatch a (Value a) (List ( Pattern a, Value a ))
Expand Down Expand Up @@ -246,9 +248,9 @@ mapValueAttributes f v =
LetRecursion a valueDefinitions inValue ->
LetRecursion (f a)
(valueDefinitions
|> List.map
(\( name, def ) ->
( name, mapDefinitionAttributes f def )
|> Dict.map
(\_ def ->
mapDefinitionAttributes f def
)
)
(mapValueAttributes f inValue)
Expand Down Expand Up @@ -324,6 +326,90 @@ mapDefinitionAttributes f d =
UntypedDefinition args (mapValueAttributes f body)



--rewriteValue : Rewrite e (Value a)
--rewriteValue rewriteBranch rewriteLeaf valueToRewrite =
-- case valueToRewrite of
-- Tuple a elements ->
-- elements
-- |> List.map rewriteBranch
-- |> ResultList.liftLastError
-- |> Result.map (Tuple a)
--
-- List a items ->
-- items
-- |> List.map rewriteBranch
-- |> ResultList.liftLastError
-- |> Result.map (List a)
--
-- Record a fields ->
-- fields
-- |> List.map
-- (\( fieldName, fieldValue ) ->
-- rewriteBranch fieldValue
-- |> Result.map (Tuple.pair fieldName)
-- )
-- |> ResultList.liftLastError
-- |> Result.map (Record a)
--
-- Field a subjectValue fieldName ->
-- rewriteBranch subjectValue
-- |> Result.map
-- (\subject ->
-- Field a subject fieldName
-- )
--
-- Apply a function argument ->
-- Result.map2 (Apply a)
-- (rewriteBranch function)
-- (rewriteBranch argument)
--
-- Lambda a argumentPattern body ->
-- Lambda (f a) (mapPatternAttributes f argumentPattern) (mapValueAttributes f body)
--
-- LetDefinition a valueName valueDefinition inValue ->
-- LetDefinition (f a) valueName (mapDefinitionAttributes f valueDefinition) (mapValueAttributes f inValue)
--
-- LetRecursion a valueDefinitions inValue ->
-- LetRecursion (f a)
-- (valueDefinitions
-- |> List.map
-- (\( name, def ) ->
-- ( name, mapDefinitionAttributes f def )
-- )
-- )
-- (mapValueAttributes f inValue)
--
-- Destructure a pattern valueToDestruct inValue ->
-- Destructure (f a) (mapPatternAttributes f pattern) (mapValueAttributes f valueToDestruct) (mapValueAttributes f inValue)
--
-- IfThenElse a condition thenBranch elseBranch ->
-- IfThenElse (f a) (mapValueAttributes f condition) (mapValueAttributes f thenBranch) (mapValueAttributes f elseBranch)
--
-- PatternMatch a branchOutOn cases ->
-- PatternMatch (f a)
-- (mapValueAttributes f branchOutOn)
-- (cases
-- |> List.map
-- (\( pattern, body ) ->
-- ( mapPatternAttributes f pattern, mapValueAttributes f body )
-- )
-- )
--
-- UpdateRecord a valueToUpdate fieldsToUpdate ->
-- UpdateRecord (f a)
-- (mapValueAttributes f valueToUpdate)
-- (fieldsToUpdate
-- |> List.map
-- (\( fieldName, fieldValue ) ->
-- ( fieldName, mapValueAttributes f fieldValue )
-- )
-- )
--
-- _ ->
-- rewriteLeaf valueToRewrite


{-| A [literal][lit] represents a fixed value in the IR. We only allow values of basic types: bool, char, string, int, float.
True -- Literal (BoolLiteral True)
Expand Down Expand Up @@ -533,7 +619,7 @@ letDef attributes valueName valueDefinition inValue =
-- (Variable [ "a" ])
-}
letRec : a -> List ( Name, Definition a ) -> Value a -> Value a
letRec : a -> Dict Name (Definition a) -> Value a -> Value a
letRec attributes valueDefinitions inValue =
LetRecursion attributes valueDefinitions inValue

Expand Down Expand Up @@ -921,6 +1007,7 @@ encodeValue encodeAttributes v =
[ Encode.string "LetRecursion"
, encodeAttributes a
, valueDefinitions
|> Dict.toList
|> Encode.list
(\( name, def ) ->
Encode.list identity
Expand Down Expand Up @@ -1079,6 +1166,7 @@ decodeValue decodeAttributes =
(Decode.index 0 decodeName)
(Decode.index 1 <| decodeDefinition decodeAttributes)
)
|> Decode.map Dict.fromList
)
)
(Decode.index 3 <| decodeValue decodeAttributes)
Expand Down
9 changes: 8 additions & 1 deletion src/Morphir/ResultList.elm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Morphir.ResultList exposing (reduce, toResult)
module Morphir.ResultList exposing (liftLastError, reduce, toResult)


reduce : (List a -> b) -> List (Result e a) -> Result e b
Expand Down Expand Up @@ -61,3 +61,10 @@ toResult results =

_ ->
Err errs


{-| Turn a list of results into a single result of a list returning only the last error in the list.
-}
liftLastError : List (Result e a) -> Result e (List a)
liftLastError results =
List.foldr (Result.map2 (::)) (Ok []) results
Loading

0 comments on commit 9f7e736

Please sign in to comment.