4module Transform.SortDefinitions (sortDefs, boundVars, flattenLets) where
6import Control.Monad.State
7import Control.Applicative ((<$>))
8import qualified Data.Set as Set
9import qualified Data.Map as Map
10import qualified SourceSyntax.Type as ST
11import SourceSyntax.Expression
12import SourceSyntax.Location
13import SourceSyntax.Pattern
14import qualified Data.Graph as Graph
15import qualified Data.Map as Map
16import qualified Data.Maybe as Maybe
18boundVars :: Pattern -> Set.Set String
21 PVar x -> Set.singleton x
22 PAlias x p -> Set.insert x (boundVars p)
23 PData _ ps -> Set.unions (map boundVars ps)
24 PRecord fields -> Set.fromList fields
25 PAnything -> Set.empty
26 PLiteral _ -> Set.empty
28ctors :: Pattern -> [String]
33 PData ctor ps -> ctor : concatMap ctors ps
38free :: String -> State (Set.Set String) ()
39free x = modify (Set.insert x)
41bound :: Set.Set String -> State (Set.Set String) ()
42bound boundVars = modify (\freeVars -> Set.difference freeVars boundVars)
44sortDefs :: LExpr t v -> LExpr t v
45sortDefs expr = evalState (reorder expr) Set.empty
47flattenLets defs lexpr@(L _ expr) =
49 Let ds body -> flattenLets (defs ++ ds) body
53reorder :: LExpr t v -> State (Set.Set String) (LExpr t v)
54reorder lexpr@(L s expr) =
57 -- Be careful adding and restricting freeVars
58 Var x -> free x >> return expr
61 uncurry Lambda `liftM` bindingReorder (p,e)
65 Binop op `liftM` reorder e1 `ap` reorder e2
68 Case `liftM` reorder e `ap` mapM bindingReorder cases
72 Data name `liftM` mapM reorder es
74 -- Just pipe the reorder though
75 Literal _ -> return expr
78 Range `liftM` reorder e1 `ap` reorder e2
81 ExplicitList `liftM` mapM reorder es
84 App `liftM` reorder e1 `ap` reorder e2
87 MultiIf `liftM` mapM reorderPair branches
90 Access `liftM` reorder e `ap` return lbl
93 Remove `liftM` reorder e `ap` return lbl
96 Insert `liftM` reorder e `ap` return lbl `ap` reorder v
99 Modify `liftM` reorder e `ap` mapM reorderField fields
102 Record `liftM` mapM reorderField fields
104 Markdown uid md es -> Markdown uid md <$> mapM reorder es
106 GLShader _ _ -> return expr
108 -- Actually do some reordering
110 do body' <- reorder body
112 -- Sort defs into strongly connected components.This
113 -- allows the programmer to write definitions in whatever
114 -- order they please, we can still define things in order
115 -- and generalize polymorphic functions when appropriate.
116 sccs <- Graph.stronglyConnComp <$> buildDefDict defs
117 let defss = map Graph.flattenSCC sccs
119 -- remove let-bound variables from the context
120 let getPatterns def =
122 Def pattern _ -> pattern
123 TypeAnnotation name _ -> PVar name
124 forM (map getPatterns defs) $ \pattern -> do
125 bound (boundVars pattern)
126 mapM free (ctors pattern)
128 let addDefs ds bod = L s (Let (concatMap toDefs ds) bod)
129 L _ let' = foldr addDefs body' defss
136 (pattern, expr, Nothing) -> [ Def pattern expr ]
137 (PVar name, expr, Just tipe) ->
138 [ TypeAnnotation name tipe, Def (PVar name) expr ]
140 [ "The impossible occurred."
141 , "Please report an issue at <https://github.com/evancz/Elm/issues>."
142 , "Be very descriptive because something quite weird probably happened." ]
144reorderField (label, expr) =
145 (,) label `liftM` reorder expr
148 (,) `liftM` reorder e1 `ap` reorder e2
150bindingReorder :: (Pattern, LExpr t v) -> State (Set.Set String) (Pattern, LExpr t v)
151bindingReorder (pattern,expr) =
152 do expr' <- reorder expr
153 bound (boundVars pattern)
154 mapM free (ctors pattern)
155 return (pattern, expr')
158type PDef t v = (Pattern, LExpr t v, Maybe ST.Type)
160reorderAndGetDependencies :: PDef t v -> State (Set.Set String) (PDef t v, [String])
161reorderAndGetDependencies (pattern, expr, mType) =
162 do globalFrees <- get
163 -- work in a fresh environment
165 expr' <- reorder expr
167 -- merge with global frees
168 modify (Set.union globalFrees)
169 return ((pattern, expr', mType), Set.toList localFrees)
172-- This also reorders the all of the sub-expressions in the Def list.
173buildDefDict :: [Def t v] -> State (Set.Set String) [(PDef t v, Int, [Int])]
175 do pdefsDeps <- mapM reorderAndGetDependencies (getPDefs defs)
176 return $ realDeps (addKey pdefsDeps)
179 getPDefs :: [Def t v] -> [PDef t v]
180 getPDefs defs = map (\(p,(e,t)) -> (p,e,t)) $
181 Map.toList $ go defs Map.empty Map.empty
184 Map.unions [ Map.difference ds ts
185 , Map.intersectionWith (\(e,_) t -> (e,Just t)) ds ts ]
187 go (def:defs) ds ts =
189 Def p e -> go defs (Map.insert p (e, Nothing) ds) ts
190 TypeAnnotation name tipe -> go defs ds (Map.insert (PVar name) tipe ts)
192 addKey :: [(PDef t v, [String])] -> [(PDef t v, Int, [String])]
193 addKey = zipWith (\n (pdef,deps) -> (pdef,n,deps)) [0..]
195 variableToKey :: (PDef t v, Int, [String]) -> [(String, Int)]
196 variableToKey ((pattern, _, _), key, _) =
197 [ (var, key) | var <- Set.toList (boundVars pattern) ]
199 variableToKeyMap :: [(PDef t v, Int, [String])] -> Map.Map String Int
200 variableToKeyMap pdefsDeps =
201 Map.fromList (concatMap variableToKey pdefsDeps)
203 realDeps :: [(PDef t v, Int, [String])] -> [(PDef t v, Int, [Int])]
204 realDeps pdefsDeps = map convert pdefsDeps
206 varDict = variableToKeyMap pdefsDeps
207 convert (pdef, key, deps) =
208 (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