1module Optimize.Cases (toMatch, Match (..), Clause (..), matchSubst, newVar) where
3import Control.Applicative ((<$>))
4import Control.Arrow (first)
5import Control.Monad.State (State)
6import qualified Control.Monad.State as State
7import qualified Data.List as List
8import Data.Maybe (fromMaybe)
10import qualified AST.Expression.General as Expr
11import qualified AST.Expression.Optimized as Optimized
12import qualified AST.Literal as Literal
13import qualified AST.Pattern as P
14import qualified AST.Variable as Var
15import qualified Optimize.Substitute as S
16import qualified Reporting.Annotation as A
22 = Match String [Clause] Match
25 | Other Optimized.Expr
31 Clause (Either Var.Canonical Literal.Literal) [String] Match
36 ([P.Optimized], Optimized.Expr)
41toMatch :: [(P.Optimized, Optimized.Expr)] -> State Int (String, Match)
44 (,) v <$> buildMatch [v] (map (first (:[])) patterns) Fail
47newVar :: State Int String
51 return $ "_v" ++ show n
54matchSubst :: [(String,String)] -> Match -> Match
55matchSubst pairs match =
62 Seq (map (matchSubst pairs) ms)
64 Other (A.A ann expr) ->
67 map (\(x,y) -> S.subst x (Expr.localVar y)) pairs
69 Other $ A.A ann $ foldr ($) expr substitutions
72 Match (varSubst n) (map clauseSubst cs) (matchSubst pairs m)
74 varSubst v = fromMaybe v (lookup v pairs)
75 clauseSubst (Clause c vs m) =
76 Clause c (map varSubst vs) (matchSubst pairs m)
81buildMatch :: [String] -> [Branch] -> Match -> State Int Match
82buildMatch variables branches match =
83 case (variables, branches, match) of
87 ([], [([], expr)], Fail) ->
90 ([], [([], expr)], Break) ->
94 return $ Seq (map (Other . snd) branches ++ [match])
97 | all isVar branches' -> matchVar variables branches' match
98 | all isCon branches' -> matchCon variables branches' match
99 | otherwise -> matchMix variables branches' match
101 branches' = map (dealias var) branches
104dealias :: String -> Branch -> Branch
105dealias _ ([], _) = noMatch "dealias"
106dealias var branch@(p:ps, A.A ann e) =
108 A.A _ (P.Alias alias pattern) ->
110 , A.A ann (S.subst alias (Expr.localVar var) e)
117isCon :: ([P.Pattern ann var], expr) -> Bool
118isCon ([], _) = noMatch "isCon"
119isCon (A.A _ pattern : _, _) =
126isVar :: ([P.Pattern ann var], expr) -> Bool
133matchVar :: [String] -> [Branch] -> Match -> State Int Match
134matchVar [] _ _ = noMatch "matchVar"
135matchVar (var:vars) branches match =
136 buildMatch vars (map subVar branches) match
138 subVar ([], _) = noMatch "matchVar.subVar"
139 subVar (A.A _ pattern : patterns, (A.A ann expr)) =
141 , A.A ann (subOnePattern pattern expr)
144 subOnePattern pattern expr =
150 S.subst x (Expr.localVar var) expr
153 let access = Expr.Access (A.A ann (Expr.localVar var))
155 foldr (\x -> S.subst x (access x)) expr fields
158 noMatch "matchVar.subVar"
161-- CONSTRUCTOR MATCHES
163matchCon :: [String] -> [Branch] -> Match -> State Int Match
164matchCon variables branches match =
166 [] -> noMatch "matchCon"
169 flip (Match var) match <$> mapM toClause caseGroups
171 caseGroups :: [[Branch]]
173 List.groupBy branchEq (List.sortBy branchCmp branches)
175 toClause :: [Branch] -> State Int Clause
177 case head branches of
178 (A.A _ (P.Data name _) : _, _) ->
179 matchClause (Left name) variables branches Break
181 (A.A _ (P.Literal lit) : _, _) ->
182 matchClause (Right lit) variables branches Break
184 _ -> noMatch "matchCon"
188 :: Either Var.Canonical Literal.Literal
193matchClause _ [] _ _ = noMatch "matchClause"
194matchClause c (_:vs) branches match =
196 Clause c vs' <$> buildMatch (vs' ++ vs) (map flatten branches) match
198 flatten ([], _) = noMatch "matchClause.flatten"
199 flatten (A.A _ pattern : patterns, expr) =
201 P.Data _ argPatterns ->
202 (argPatterns ++ patterns, expr)
208 noMatch "matchClause.flatten"
210 getVars :: State Int [String]
212 case head branches of
213 (A.A _ (P.Data _ argPatterns) : _, _) ->
214 State.forM argPatterns (const newVar)
216 (A.A _ (P.Literal _) : _, _) ->
220 noMatch "matchClause.getVars"
223branchEq :: Branch -> Branch -> Bool
224branchEq (A.A _ pattern : _, _) (A.A _ pattern' : _, _) =
225 case (pattern, pattern') of
226 (P.Data name _, P.Data name' _) ->
229 (P.Literal lit, P.Literal lit') ->
233 noMatch "matchCon.branchEq"
235branchEq _ _ = noMatch "matchCon.branchEq"
238branchCmp :: Branch -> Branch -> Ordering
239branchCmp (A.A _ pattern : _, _) (A.A _ pattern' : _, _) =
240 case (pattern, pattern') of
241 (P.Data name _, P.Data name' _) ->
244 (P.Literal lit, P.Literal lit') ->
248 noMatch "matchCon.branchCmp"
250branchCmp _ _ = noMatch "matchCon.branchCmp"
255matchMix :: [String] -> [Branch] -> Match -> State Int Match
256matchMix vs branches def =
257 State.foldM (flip $ buildMatch vs) def (reverse branchGroups)
260 List.groupBy (\p1 p2 -> isCon p1 == isCon p2) branches
263noMatch :: String -> a
265 error $ "unexpected pattern in `" ++ name ++
266 "` function. Report a compiler issue to <https://github.com/elm-lang/Elm>."
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