2module Transform.SortDefinitions (sortDefs, boundVars, flattenLets) where
4import Control.Monad.State
5import Control.Applicative ((<$>))
6import qualified Data.Set as Set
7import qualified Data.Map as Map
8import qualified SourceSyntax.Type as ST
9import SourceSyntax.Expression
10import SourceSyntax.Location
11import SourceSyntax.Pattern
12import qualified Data.Graph as Graph
13import qualified Data.Map as Map
14import qualified Data.Maybe as Maybe
16boundVars :: Pattern -> Set.Set String
19 PVar x -> Set.singleton x
20 PAlias x p -> Set.insert x (boundVars p)
21 PData _ ps -> Set.unions (map boundVars ps)
22 PRecord fields -> Set.fromList fields
23 PAnything -> Set.empty
24 PLiteral _ -> Set.empty
26ctors :: Pattern -> [String]
31 PData ctor ps -> ctor : concatMap ctors ps
36free :: String -> State (Set.Set String) ()
37free x = modify (Set.insert x)
39bound :: Set.Set String -> State (Set.Set String) ()
40bound boundVars = modify (\freeVars -> Set.difference freeVars boundVars)
42sortDefs :: LExpr t v -> LExpr t v
43sortDefs expr = evalState (reorder expr) Set.empty
45flattenLets defs lexpr@(L _ expr) =
47 Let ds body -> flattenLets (defs ++ ds) body
51reorder :: LExpr t v -> State (Set.Set String) (LExpr t v)
52reorder lexpr@(L s expr) =
55 -- Be careful adding and restricting freeVars
56 Var x -> free x >> return expr
59 uncurry Lambda `liftM` bindingReorder (p,e)
63 Binop op `liftM` reorder e1 `ap` reorder e2
66 Case `liftM` reorder e `ap` mapM bindingReorder cases
70 Data name `liftM` mapM reorder es
72 -- Just pipe the reorder though
73 Literal _ -> return expr
76 Range `liftM` reorder e1 `ap` reorder e2
79 ExplicitList `liftM` mapM reorder es
82 App `liftM` reorder e1 `ap` reorder e2
85 MultiIf `liftM` mapM reorderPair branches
88 Access `liftM` reorder e `ap` return lbl
91 Remove `liftM` reorder e `ap` return lbl
94 Insert `liftM` reorder e `ap` return lbl `ap` reorder v
97 Modify `liftM` reorder e `ap` mapM reorderField fields
100 Record `liftM` mapM reorderField fields
102 Markdown uid md es -> Markdown uid md <$> mapM reorder es
104 -- Actually do some reordering
106 do body' <- reorder body
108 -- Sort defs into strongly connected components.This
109 -- allows the programmer to write definitions in whatever
110 -- order they please, we can still define things in order
111 -- and generalize polymorphic functions when appropriate.
112 sccs <- Graph.stronglyConnComp <$> buildDefDict defs
113 let defss = map Graph.flattenSCC sccs
115 -- remove let-bound variables from the context
116 let getPatterns def =
118 Def pattern _ -> pattern
119 TypeAnnotation name _ -> PVar name
120 forM (map getPatterns defs) $ \pattern -> do
121 bound (boundVars pattern)
122 mapM free (ctors pattern)
124 let addDefs ds bod = L s (Let (concatMap toDefs ds) bod)
125 L _ let' = foldr addDefs body' defss
132 (pattern, expr, Nothing) -> [ Def pattern expr ]
133 (PVar name, expr, Just tipe) ->
134 [ TypeAnnotation name tipe, Def (PVar name) expr ]
136 [ "The impossible occurred."
137 , "Please report an issue at <https://github.com/evancz/Elm/issues>."
138 , "Be very descriptive because something quite weird probably happened." ]
140reorderField (label, expr) =
141 (,) label `liftM` reorder expr
144 (,) `liftM` reorder e1 `ap` reorder e2
146bindingReorder :: (Pattern, LExpr t v) -> State (Set.Set String) (Pattern, LExpr t v)
147bindingReorder (pattern,expr) =
148 do expr' <- reorder expr
149 bound (boundVars pattern)
150 mapM free (ctors pattern)
151 return (pattern, expr')
154type PDef t v = (Pattern, LExpr t v, Maybe ST.Type)
156reorderAndGetDependencies :: PDef t v -> State (Set.Set String) (PDef t v, [String])
157reorderAndGetDependencies (pattern, expr, mType) =
158 do globalFrees <- get
159 -- work in a fresh environment
161 expr' <- reorder expr
163 -- merge with global frees
164 modify (Set.union globalFrees)
165 return ((pattern, expr', mType), Set.toList localFrees)
168-- This also reorders the all of the sub-expressions in the Def list.
169buildDefDict :: [Def t v] -> State (Set.Set String) [(PDef t v, Int, [Int])]
171 do pdefsDeps <- mapM reorderAndGetDependencies (getPDefs defs)
172 return $ realDeps (addKey pdefsDeps)
175 getPDefs :: [Def t v] -> [PDef t v]
176 getPDefs defs = map (\(p,(e,t)) -> (p,e,t)) $
177 Map.toList $ go defs Map.empty Map.empty
180 Map.unions [ Map.difference ds ts
181 , Map.intersectionWith (\(e,_) t -> (e,Just t)) ds ts ]
183 go (def:defs) ds ts =
185 Def p e -> go defs (Map.insert p (e, Nothing) ds) ts
186 TypeAnnotation name tipe -> go defs ds (Map.insert (PVar name) tipe ts)
188 addKey :: [(PDef t v, [String])] -> [(PDef t v, Int, [String])]
189 addKey = zipWith (\n (pdef,deps) -> (pdef,n,deps)) [0..]
191 variableToKey :: (PDef t v, Int, [String]) -> [(String, Int)]
192 variableToKey ((pattern, _, _), key, _) =
193 [ (var, key) | var <- Set.toList (boundVars pattern) ]
195 variableToKeyMap :: [(PDef t v, Int, [String])] -> Map.Map String Int
196 variableToKeyMap pdefsDeps =
197 Map.fromList (concatMap variableToKey pdefsDeps)
199 realDeps :: [(PDef t v, Int, [String])] -> [(PDef t v, Int, [Int])]
200 realDeps pdefsDeps = map convert pdefsDeps
202 varDict = variableToKeyMap pdefsDeps
203 convert (pdef, key, deps) =
204 (pdef, key, Maybe.mapMaybe (flip Map.lookup varDict) deps)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list