git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Change nested record update syntax and fix bug with depth > 2 (#2580)

* Change nested record update syntax and fix bug with depth > 2 * Build update tree in parser * Remove accidental pragmas

commit32faa7695dc4a3f43498d8c1614e3a8e9b62fb88 authorLiam Goodacre <goodacre.liam@gmail.com> dateSun 29 Jan 2017, 02:20 (10 years ago) parentc05106c
7 files changed+107−126
examples/passing/NestedRecordUpdate.purs+6−5 examples/passing/NestedRecordUpdateWildcards.purs+1−1 src/Language/PureScript/AST/Declarations.hs+37−3 src/Language/PureScript/AST/Traversals.hs+7−7 src/Language/PureScript/Parser/Declarations.hs+22−12 src/Language/PureScript/Pretty/Values.hs+8−10 src/Language/PureScript/Sugar/ObjectWildcards.hs+26−88
examples/passing/NestedRecordUpdate.purs+6−5
@@ -3,21 +3,22 @@ module Main where
33import Prelude
44import Control.Monad.Eff.Console
55
6−type T = { foo :: Int, bar :: { baz :: Int, qux :: Int } }
6+type T = { foo :: Int, bar :: { baz :: Int, qux :: { lhs :: Int, rhs :: Int } } }
77
88init :: T
9−init = { foo: 1, bar: { baz: 2, qux: 3 } }
9+init = { foo: 1, bar: { baz: 2, qux: { lhs: 3, rhs: 4 } } }
1010
1111updated :: T
12−updated = init { foo = 10, bar.baz = 20, bar.qux = 30 }
12+updated = init { foo = 10, bar { baz = 20, qux { lhs = 30, rhs = 40 } } }
1313
1414expected :: T
15−expected = { foo: 10, bar: { baz: 20, qux: 30 } }
15+expected = { foo: 10, bar: { baz: 20, qux: { lhs: 30, rhs: 40 } } }
1616
1717check l r =
1818 l.foo == r.foo &&
1919 l.bar.baz == r.bar.baz &&
20− l.bar.qux == r.bar.qux
20+ l.bar.qux.lhs == r.bar.qux.lhs &&
21+ l.bar.qux.rhs == r.bar.qux.rhs
2122
2223main = do
2324 when (check updated expected) $ log "Done"
examples/passing/NestedRecordUpdateWildcards.purs+1−1
@@ -3,7 +3,7 @@ module Main where
33import Prelude
44import Control.Monad.Eff.Console
55
6−update = _ { foo = _, bar.baz = _, bar.qux = _ }
6+update = _ { foo = _, bar { baz = _, qux = _ } }
77
88init = { foo: 1, bar: { baz: 2, qux: 3 } }
99
src/Language/PureScript/AST/Declarations.hs+37−3
@@ -1,4 +1,6 @@
11{-# LANGUAGE TemplateHaskell #-}
2+{-# LANGUAGE DeriveFoldable #-}
3+{-# LANGUAGE DeriveTraversable #-}
24
35-- |
46-- Data types for modules and declarations
@@ -12,7 +14,6 @@ import Control.Monad.Identity
1214import Data.Aeson.TH
1315import qualified Data.Map as M
1416import Data.Text (Text)
15−import Data.List.NonEmpty (NonEmpty(..))
1617
1718import Language.PureScript.AST.Binders
1819import Language.PureScript.AST.Literals
@@ -587,10 +588,10 @@ data Expr
587588 --
588589 | ObjectUpdate Expr [(PSString, Expr)]
589590 -- |
590− -- Object updates with nested support: `x { foo.bar = e }`
591+ -- Object updates with nested support: `x { foo { bar = e } }`
591592 -- Replaced during desugaring into a `Let` and nested `ObjectUpdate`s
592593 --
593− | ObjectUpdateNested Expr [(NonEmpty PSString, Expr)]
594+ | ObjectUpdateNested Expr (PathTree Expr)
594595 -- |
595596 -- Function introduction
596597 --
@@ -706,5 +707,38 @@ data DoNotationElement
706707 | PositionedDoNotationElement SourceSpan [Comment] DoNotationElement
707708 deriving (Show)
708709
710+
711+-- For a record update such as:
712+--
713+-- x { foo = 0
714+-- , bar { baz = 1
715+-- , qux = 2 } }
716+--
717+-- We represent the updates as the `PathTree`:
718+--
719+-- [ ("foo", Leaf 3)
720+-- , ("bar", Branch [ ("baz", Leaf 1)
721+-- , ("qux", Leaf 2) ]) ]
722+--
723+-- Which we then convert to an expression representing the following:
724+--
725+-- let x' = x
726+-- in x' { foo = 0
727+-- , bar = x'.bar { baz = 1
728+-- , qux = 2 } }
729+--
730+-- The `let` here is required to prevent re-evaluating the object expression `x`.
731+-- However we don't generate this when using an anonymous argument for the object.
732+--
733+
734+newtype PathTree t = PathTree (AssocList PSString (PathNode t))
735+ deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
736+
737+data PathNode t = Leaf t | Branch (PathTree t)
738+ deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
739+
740+newtype AssocList k t = AssocList { runAssocList :: [(k, t)] }
741+ deriving (Show, Eq, Ord, Foldable, Functor, Traversable)
742+
709743$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''DeclarationRef)
710744$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ImportDeclarationType)
src/Language/PureScript/AST/Traversals.hs+7−7
@@ -48,7 +48,7 @@ everywhereOnValues f g h = (f', g', h')
4848 g' (TypeClassDictionaryConstructorApp name v) = g (TypeClassDictionaryConstructorApp name (g' v))
4949 g' (Accessor prop v) = g (Accessor prop (g' v))
5050 g' (ObjectUpdate obj vs) = g (ObjectUpdate (g' obj) (map (fmap g') vs))
51− g' (ObjectUpdateNested obj vs) = g (ObjectUpdateNested (g' obj) (map (fmap g') vs))
51+ g' (ObjectUpdateNested obj vs) = g (ObjectUpdateNested (g' obj) (fmap g' vs))
5252 g' (Abs name v) = g (Abs name (g' v))
5353 g' (App v1 v2) = g (App (g' v1) (g' v2))
5454 g' (IfThenElse v1 v2 v3) = g (IfThenElse (g' v1) (g' v2) (g' v3))
@@ -116,7 +116,7 @@ everywhereOnValuesTopDownM f g h = (f' <=< f, g' <=< g, h' <=< h)
116116 g' (TypeClassDictionaryConstructorApp name v) = TypeClassDictionaryConstructorApp name <$> (g v >>= g')
117117 g' (Accessor prop v) = Accessor prop <$> (g v >>= g')
118118 g' (ObjectUpdate obj vs) = ObjectUpdate <$> (g obj >>= g') <*> traverse (sndM (g' <=< g)) vs
119− g' (ObjectUpdateNested obj vs) = ObjectUpdateNested <$> (g obj >>= g') <*> traverse (sndM (g' <=< g)) vs
119+ g' (ObjectUpdateNested obj vs) = ObjectUpdateNested <$> (g obj >>= g') <*> traverse (g' <=< g) vs
120120 g' (Abs name v) = Abs name <$> (g v >>= g')
121121 g' (App v1 v2) = App <$> (g v1 >>= g') <*> (g v2 >>= g')
122122 g' (IfThenElse v1 v2 v3) = IfThenElse <$> (g v1 >>= g') <*> (g v2 >>= g') <*> (g v3 >>= g')
@@ -184,7 +184,7 @@ everywhereOnValuesM f g h = (f', g', h')
184184 g' (TypeClassDictionaryConstructorApp name v) = (TypeClassDictionaryConstructorApp name <$> g' v) >>= g
185185 g' (Accessor prop v) = (Accessor prop <$> g' v) >>= g
186186 g' (ObjectUpdate obj vs) = (ObjectUpdate <$> g' obj <*> traverse (sndM g') vs) >>= g
187− g' (ObjectUpdateNested obj vs) = (ObjectUpdateNested <$> g' obj <*> traverse (sndM g') vs) >>= g
187+ g' (ObjectUpdateNested obj vs) = (ObjectUpdateNested <$> g' obj <*> traverse g' vs) >>= g
188188 g' (Abs name v) = (Abs name <$> g' v) >>= g
189189 g' (App v1 v2) = (App <$> g' v1 <*> g' v2) >>= g
190190 g' (IfThenElse v1 v2 v3) = (IfThenElse <$> g' v1 <*> g' v2 <*> g' v3) >>= g
@@ -257,7 +257,7 @@ everythingOnValues (<>) f g h i j = (f', g', h', i', j')
257257 g' v@(TypeClassDictionaryConstructorApp _ v1) = g v <> g' v1
258258 g' v@(Accessor _ v1) = g v <> g' v1
259259 g' v@(ObjectUpdate obj vs) = foldl (<>) (g v <> g' obj) (map (g' . snd) vs)
260− g' v@(ObjectUpdateNested obj vs) = foldl (<>) (g v <> g' obj) (map (g' . snd) vs)
260+ g' v@(ObjectUpdateNested obj vs) = foldl (<>) (g v <> g' obj) (fmap g' vs)
261261 g' v@(Abs _ v1) = g v <> g' v1
262262 g' v@(App v1 v2) = g v <> g' v1 <> g' v2
263263 g' v@(IfThenElse v1 v2 v3) = g v <> g' v1 <> g' v2 <> g' v3
@@ -335,7 +335,7 @@ everythingWithContextOnValues s0 r0 (<>) f g h i j = (f'' s0, g'' s0, h'' s0, i'
335335 g' s (TypeClassDictionaryConstructorApp _ v1) = g'' s v1
336336 g' s (Accessor _ v1) = g'' s v1
337337 g' s (ObjectUpdate obj vs) = foldl (<>) (g'' s obj) (map (g'' s . snd) vs)
338− g' s (ObjectUpdateNested obj vs) = foldl (<>) (g'' s obj) (map (g'' s . snd) vs)
338+ g' s (ObjectUpdateNested obj vs) = foldl (<>) (g'' s obj) (fmap (g'' s) vs)
339339 g' s (Abs _ v1) = g'' s v1
340340 g' s (App v1 v2) = g'' s v1 <> g'' s v2
341341 g' s (IfThenElse v1 v2 v3) = g'' s v1 <> g'' s v2 <> g'' s v3
@@ -415,7 +415,7 @@ everywhereWithContextOnValuesM s0 f g h i j = (f'' s0, g'' s0, h'' s0, i'' s0, j
415415 g' s (TypeClassDictionaryConstructorApp name v) = TypeClassDictionaryConstructorApp name <$> g'' s v
416416 g' s (Accessor prop v) = Accessor prop <$> g'' s v
417417 g' s (ObjectUpdate obj vs) = ObjectUpdate <$> g'' s obj <*> traverse (sndM (g'' s)) vs
418− g' s (ObjectUpdateNested obj vs) = ObjectUpdateNested <$> g'' s obj <*> traverse (sndM (g'' s)) vs
418+ g' s (ObjectUpdateNested obj vs) = ObjectUpdateNested <$> g'' s obj <*> traverse (g'' s) vs
419419 g' s (Abs name v) = Abs name <$> g'' s v
420420 g' s (App v1 v2) = App <$> g'' s v1 <*> g'' s v2
421421 g' s (IfThenElse v1 v2 v3) = IfThenElse <$> g'' s v1 <*> g'' s v2 <*> g'' s v3
@@ -506,7 +506,7 @@ everythingWithScope f g h i j = (f'', g'', h'', i'', \s -> snd . j'' s)
506506 g' s (TypeClassDictionaryConstructorApp _ v1) = g'' s v1
507507 g' s (Accessor _ v1) = g'' s v1
508508 g' s (ObjectUpdate obj vs) = g'' s obj <> foldMap (g'' s . snd) vs
509− g' s (ObjectUpdateNested obj vs) = g'' s obj <> foldMap (g'' s . snd) vs
509+ g' s (ObjectUpdateNested obj vs) = g'' s obj <> foldMap (g'' s) vs
510510 g' s (Abs (Left name) v1) =
511511 let s' = S.insert name s
512512 in g'' s' v1
src/Language/PureScript/Parser/Declarations.hs+22−12
@@ -17,13 +17,12 @@ import Prelude hiding (lex)
1717
1818import Control.Applicative
1919import Control.Arrow ((+++))
20+import Control.Monad (foldM)
2021import Control.Monad.Error.Class (MonadError(..))
2122import Control.Parallel.Strategies (withStrategy, parList, rseq)
22−import Data.Bifunctor (first)
2323import Data.Functor (($>))
24−import Data.List.NonEmpty (NonEmpty(..))
25−import qualified Data.List.NonEmpty as N
2624import Data.Maybe (fromMaybe)
25+import qualified Data.Set as S
2726import Data.Text (Text)
2827import Language.PureScript.AST
2928import Language.PureScript.Environment
@@ -399,13 +398,17 @@ parseInfixExpr
399398parseHole :: TokenParser Expr
400399parseHole = Hole <$> holeLit
401400
402−parsePropertyUpdate :: TokenParser (NonEmpty PSString, Expr)
401+parsePropertyUpdate :: TokenParser (PSString, PathNode Expr)
403402parsePropertyUpdate = do
404403 name <- parseLabel
405− rest <- P.many (indented *> dot *> indented *> parseLabel)
406− _ <- indented *> equals
407− value <- indented *> parseValue
408− return (name :| rest, value)
404+ updates <- parseShallowUpdate <|> parseNestedUpdate
405+ return (name, updates)
406+ where
407+ parseShallowUpdate :: TokenParser (PathNode Expr)
408+ parseShallowUpdate = Leaf <$> (indented *> equals *> indented *> parseValue)
409+
410+ parseNestedUpdate :: TokenParser (PathNode Expr)
411+ parseNestedUpdate = Branch <$> parseUpdaterBodyFields
409412
410413parseAccessor :: Expr -> TokenParser Expr
411414parseAccessor (Constructor _) = P.unexpected "constructor"
@@ -455,11 +458,18 @@ parseValue = withSourceSpan PositionedValue
455458 ]
456459 ]
457460
458−parseUpdaterBody :: Expr -> TokenParser Expr
459−parseUpdaterBody v = objectUpdate <$> (indented *> braces (commaSep1 (indented *> parsePropertyUpdate)))
461+parseUpdaterBodyFields :: TokenParser (PathTree Expr)
462+parseUpdaterBodyFields = do
463+ updates <- indented *> braces (commaSep1 (indented *> parsePropertyUpdate))
464+ (_, tree) <- foldM insertUpdate (S.empty, []) updates
465+ return (PathTree (AssocList (reverse tree)))
460466 where
461− objectUpdate xs | all (null . N.tail . fst) xs = ObjectUpdate v (map (first N.head) xs)
462− | otherwise = ObjectUpdateNested v xs
467+ insertUpdate (seen, xs) (key, node)
468+ | S.member key seen = P.unexpected ("Duplicate key in record update: " ++ show key)
469+ | otherwise = return (S.insert key seen, (key, node) : xs)
470+
471+parseUpdaterBody :: Expr -> TokenParser Expr
472+parseUpdaterBody v = ObjectUpdateNested v <$> parseUpdaterBodyFields
463473
464474parseAnonymousArgument :: TokenParser Expr
465475parseAnonymousArgument = underscore *> pure AnonymousArgument
src/Language/PureScript/Pretty/Values.hs+8−10
@@ -12,7 +12,6 @@ import Prelude.Compat
1212import Control.Arrow (second)
1313
1414import qualified Data.Monoid as Monoid ((<>))
15−import Data.List.NonEmpty (NonEmpty(..))
1615
1716import qualified Data.Text as T
1817import Data.Text (Text)
@@ -48,11 +47,8 @@ prettyPrintObject d = list '{' '}' prettyPrintObjectProperty
4847 prettyPrintObjectProperty :: (PSString, Maybe Expr) -> Box
4948 prettyPrintObjectProperty (key, value) = textT (prettyPrintObjectKey key Monoid.<> ": ") <> maybe (text "_") (prettyPrintValue (d - 1)) value
5049
51−prettyPrintObjectUpdate :: forall k. (k -> Box) -> Int -> Expr -> [(k, Expr)] -> Box
52−prettyPrintObjectUpdate printKey d o ps =
53− prettyPrintValueAtom (d - 1) o `beforeWithSpace` list '{' '}' printEntry ps
54− where
55− printEntry (key, val) = printKey key <> text " = " <> prettyPrintValue (d - 1) val
50+prettyPrintUpdateEntry :: Int -> PSString -> Expr -> Box
51+prettyPrintUpdateEntry d key val = textT (prettyPrintObjectKey key) <> text " = " <> prettyPrintValue (d - 1) val
5652
5753-- | Pretty-print an expression
5854prettyPrintValue :: Int -> Expr -> Box
@@ -63,10 +59,12 @@ prettyPrintValue d (IfThenElse cond th el) =
6359 , text "else " <> prettyPrintValueAtom (d - 1) el
6460 ])
6561prettyPrintValue d (Accessor prop val) = prettyPrintValueAtom (d - 1) val `before` textT ("." Monoid.<> prettyPrintObjectKey prop)
66−prettyPrintValue d (ObjectUpdate o ps) = prettyPrintObjectUpdate (textT . prettyPrintObjectKey) d o ps
67−prettyPrintValue d (ObjectUpdateNested o ps) = prettyPrintObjectUpdate printPath d o ps where
68− printPath (hd :| tl) = foldl combine (textT (prettyPrintObjectKey hd)) tl
69− combine acc key = acc <> textT ("." Monoid.<> prettyPrintObjectKey key)
62+prettyPrintValue d (ObjectUpdate o ps) = prettyPrintValueAtom (d - 1) o `beforeWithSpace` list '{' '}' (uncurry (prettyPrintUpdateEntry d)) ps
63+prettyPrintValue d (ObjectUpdateNested o ps) = prettyPrintValueAtom (d - 1) o `beforeWithSpace` prettyPrintUpdate ps
64+ where
65+ prettyPrintUpdate (PathTree tree) = list '{' '}' printNode (runAssocList tree)
66+ printNode (key, Leaf val) = prettyPrintUpdateEntry d key val
67+ printNode (key, Branch val) = textT (prettyPrintObjectKey key) `beforeWithSpace` prettyPrintUpdate val
7068prettyPrintValue d (App val arg) = prettyPrintValueAtom (d - 1) val `beforeWithSpace` prettyPrintValueAtom (d - 1) arg
7169prettyPrintValue d (Abs (Left arg) val) = text ('\\' : T.unpack (showIdent arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
7270prettyPrintValue d (Abs (Right arg) val) = text ('\\' : T.unpack (prettyPrintBinder arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
src/Language/PureScript/Sugar/ObjectWildcards.hs+26−88
@@ -5,46 +5,18 @@ module Language.PureScript.Sugar.ObjectWildcards
55
66import Prelude.Compat
77
8−import Control.Monad (forM, foldM)
8+import Control.Monad (forM)
99import Control.Monad.Error.Class (MonadError(..))
1010import Control.Monad.Supply.Class
11−import Data.List (partition)
12−import Data.List.NonEmpty (NonEmpty(..))
13−import Data.Map (Map)
14−import qualified Data.Map as M
11+import Data.Foldable (toList)
12+import Data.List (foldl')
1513import Data.Maybe (catMaybes)
1614import Language.PureScript.AST
1715import Language.PureScript.Environment (NameKind(..))
1816import Language.PureScript.Errors
19−import Language.PureScript.Label (Label(..))
2017import Language.PureScript.Names
2118import Language.PureScript.PSString (PSString)
2219
23−-- `PathNode` and `PathTree` are used as an intermediate form when desugaring a nested object update.
24−-- For an update such as:
25−--
26−-- x { foo = 0
27−-- , bar.baz = 1
28−-- , bar.qux = 2 }
29−--
30−-- We represent the updates as the `PathTree`:
31−--
32−-- M.fromList [ ("foo", Leaf 3)
33−-- , ("bar", Branch (M.fromList [ ("baz", Leaf 1)
34−-- , ("qux", Leaf 2) ]) ])
35−--
36−-- Which we then convert to an expression representing the following:
37−--
38−-- let x' = x
39−-- in x' { foo = 0
40−-- , bar = x'.bar { baz = 1
41−-- , qux = 2 } }
42−--
43−-- The `let` here is required to prevent re-evaluating the object expression `x`.
44−-- However we don't generate this when using an anonymous argument for the object.
45−--
46−type PathTree = Map PSString PathNode
47−data PathNode = Leaf Expr | Branch PathTree
4820
4921desugarObjectConstructors
5022 :: forall m
@@ -70,11 +42,7 @@ desugarDecl other = fn other
7042 , BinaryNoParens op u val <- b'
7143 , isAnonymousArgument u = do arg <- freshIdent'
7244 return $ Abs (Left arg) $ App (App op (Var (Qualified Nothing arg))) val
73− desugarExpr (Literal (ObjectLiteral ps)) = wrapLambda (Literal . ObjectLiteral) ps
74− desugarExpr (ObjectUpdate u ps) | isAnonymousArgument u = do
75− obj <- freshIdent'
76− Abs (Left obj) <$> wrapLambda (ObjectUpdate (argToExpr obj)) ps
77− desugarExpr (ObjectUpdate obj ps) = wrapLambda (ObjectUpdate obj) ps
45+ desugarExpr (Literal (ObjectLiteral ps)) = wrapLambdaAssoc (Literal . ObjectLiteral) ps
7846 desugarExpr (ObjectUpdateNested obj ps) = transformNestedUpdate obj ps
7947 desugarExpr (Accessor prop u)
8048 | Just props <- peelAnonAccessorChain u = do
@@ -92,67 +60,42 @@ desugarDecl other = fn other
9260 return $ foldr (Abs . Left) if_ (catMaybes [u', t', f'])
9361 desugarExpr e = return e
9462
95− transformNestedUpdate :: Expr -> [(NonEmpty PSString, Expr)] -> m Expr
63+ transformNestedUpdate :: Expr -> PathTree Expr -> m Expr
9664 transformNestedUpdate obj ps = do
9765 -- If we don't have an anonymous argument then we need to generate a let wrapper
9866 -- so that the object expression isn't re-evaluated for each nested update.
9967 val <- freshIdent'
68+ let valExpr = argToExpr val
10069 if isAnonymousArgument obj
101− then Abs (Left val) <$> wrapLambdaM (build val) ps
102− else wrapLambdaM (fmap (buildLet val) . build val) ps
70+ then Abs (Left val) <$> wrapLambda (buildUpdates valExpr) ps
71+ else wrapLambda (buildLet val . buildUpdates valExpr) ps
10372 where
104− build val xs = buildUpdates (argToExpr val) <$> foldM buildTree M.empty xs
10573 buildLet val = Let [ValueDeclaration val Public [] (Right obj)]
10674
107− -- Here we build up the intermediate `PathTree` data structure and check that
108− -- the paths are valid relative to each other - for example, the update
109− -- `{ foo.bar = 2, foo = {bar: 3} }` is invalid because there are conflicting
110− -- paths.
111− buildTree
112− :: PathTree
113− -> (NonEmpty PSString, Expr)
114− -> m PathTree
115− buildTree pathTree (path, e) = go pathTree path where
116− go tree (key :| [])
117− -- path already exists
118− | key `M.member` tree = throwError . errorMessage $ DuplicateLabel (Label key) (Just (ObjectUpdateNested obj ps))
119− -- create new path
120− | otherwise = return (M.insert key (Leaf e) tree)
121− go tree (key :| (x : xs)) = do
122− branch <- case M.lookup key tree of
123− -- nothing at this path yet
124− Nothing -> return M.empty
125− -- already a map at this path
126− Just (Branch branch) -> return branch
127− -- sub-path already exists
128− Just (Leaf _) -> throwError . errorMessage $ DuplicateLabel (Label key) (Just (ObjectUpdateNested obj ps))
129− M.insert key . Branch <$> go branch (x :| xs) <*> pure tree
130−
131− -- Now we have a valid collection of updates in the form of a `PathTree`
132− -- we can recursively build up the nested `ObjectUpdate` expressions.
133− buildUpdates :: Expr -> PathTree -> Expr
134− buildUpdates val vs = ObjectUpdate val (goLayer [] <$> M.toList vs) where
135− goLayer :: [PSString] -> (PSString, PathNode) -> (PSString, Expr)
75+ -- recursively build up the nested `ObjectUpdate` expressions
76+ buildUpdates :: Expr -> PathTree Expr -> Expr
77+ buildUpdates val (PathTree vs) = ObjectUpdate val (goLayer [] <$> runAssocList vs) where
78+ goLayer :: [PSString] -> (PSString, PathNode Expr) -> (PSString, Expr)
13679 goLayer _ (key, Leaf expr) = (key, expr)
137− goLayer path (key, Branch branch) =
80+ goLayer path (key, Branch (PathTree branch)) =
13881 let path' = path ++ [key]
139− updates = goLayer path' <$> M.toList branch
140− accessor = foldr Accessor val path'
82+ updates = goLayer path' <$> runAssocList branch
83+ accessor = foldl' (flip Accessor) val path'
14184 objectUpdate = ObjectUpdate accessor updates
14285 in (key, objectUpdate)
14386
144− wrapLambdaM :: forall k. ([(k, Expr)] -> m Expr) -> [(k, Expr)] -> m Expr
145− wrapLambdaM mkVal ps =
146− let (args, props) = partition (isAnonymousArgument . snd) ps
147− in if null args
148− then mkVal props
149− else do
150− (args', ps') <- unzip <$> mapM mkProp ps
151− val <- mkVal ps'
152− return $ foldr (Abs . Left) val (catMaybes args')
87+ wrapLambda :: forall t. Traversable t => (t Expr -> Expr) -> t Expr -> m Expr
88+ wrapLambda mkVal ps = do
89+ args <- traverse processExpr ps
90+ return $ foldr (Abs . Left) (mkVal (snd <$> args)) (catMaybes $ toList (fst <$> args))
91+ where
92+ processExpr :: Expr -> m (Maybe Ident, Expr)
93+ processExpr e = do
94+ arg <- freshIfAnon e
95+ return (arg, maybe e argToExpr arg)
15396
154− wrapLambda :: forall k. ([(k, Expr)] -> Expr) -> [(k, Expr)] -> m Expr
155− wrapLambda mkVal = wrapLambdaM (return . mkVal)
97+ wrapLambdaAssoc :: ([(PSString, Expr)] -> Expr) -> [(PSString, Expr)] -> m Expr
98+ wrapLambdaAssoc mkVal = wrapLambda (mkVal . runAssocList) . AssocList
15699
157100 stripPositionInfo :: Expr -> Expr
158101 stripPositionInfo (PositionedValue _ _ e) = stripPositionInfo e
@@ -169,11 +112,6 @@ desugarDecl other = fn other
169112 isAnonymousArgument (PositionedValue _ _ e) = isAnonymousArgument e
170113 isAnonymousArgument _ = False
171114
172− mkProp :: forall k. (k, Expr) -> m (Maybe Ident, (k, Expr))
173− mkProp (name, e) = do
174− arg <- freshIfAnon e
175− return (arg, (name, maybe e argToExpr arg))
176−
177115 freshIfAnon :: Expr -> m (Maybe Ident)
178116 freshIfAnon u
179117 | isAnonymousArgument u = Just <$> freshIdent'