1module Generate.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.Canonical as Canonical
12import qualified AST.Literal as Literal
13import qualified AST.Pattern as P
14import qualified AST.Variable as Var
15import qualified Generate.Substitute as S
16import qualified Reporting.Annotation as A
22 = Match String [Clause] Match
25 | Other Canonical.Expr
31 Clause (Either Var.Canonical Literal.Literal) [String] Match
36 ([P.CanonicalPattern], Canonical.Expr)
41toMatch :: [(P.CanonicalPattern, Canonical.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)
65 Other . A.A a $ foldr ($) e $ map (\(x,y) -> S.subst x (Expr.localVar y)) pairs
68 Match (varSubst n) (map clauseSubst cs) (matchSubst pairs m)
70 varSubst v = fromMaybe v (lookup v pairs)
71 clauseSubst (Clause c vs m) =
72 Clause c (map varSubst vs) (matchSubst pairs m)
77buildMatch :: [String] -> [Branch] -> Match -> State Int Match
78buildMatch variables branches match =
79 case (variables, branches, match) of
83 ([], [([], expr)], Fail) ->
86 ([], [([], expr)], Break) ->
90 return $ Seq (map (Other . snd) branches ++ [match])
93 | all isVar branches' -> matchVar variables branches' match
94 | all isCon branches' -> matchCon variables branches' match
95 | otherwise -> matchMix variables branches' match
97 branches' = map (dealias var) branches
100dealias :: String -> Branch -> Branch
101dealias _ ([], _) = noMatch "dealias"
102dealias var branch@(p:ps, A.A ann e) =
104 A.A _ (P.Alias alias pattern) ->
106 , A.A ann (S.subst alias (Expr.localVar var) e)
113isCon :: ([P.Pattern ann var], expr) -> Bool
114isCon ([], _) = noMatch "isCon"
115isCon (A.A _ pattern : _, _) =
122isVar :: ([P.Pattern ann var], expr) -> Bool
129matchVar :: [String] -> [Branch] -> Match -> State Int Match
130matchVar [] _ _ = noMatch "matchVar"
131matchVar (var:vars) branches match =
132 buildMatch vars (map subVar branches) match
134 subVar ([], _) = noMatch "matchVar.subVar"
135 subVar (A.A _ pattern : patterns, (A.A ann expr)) =
137 , A.A ann (subOnePattern pattern expr)
140 subOnePattern pattern expr =
146 S.subst x (Expr.localVar var) expr
149 let access = Expr.Access (A.A ann (Expr.localVar var))
151 foldr (\x -> S.subst x (access x)) expr fields
154 noMatch "matchVar.subVar"
157-- CONSTRUCTOR MATCHES
159matchCon :: [String] -> [Branch] -> Match -> State Int Match
160matchCon variables branches match =
162 [] -> noMatch "matchCon"
165 flip (Match var) match <$> mapM toClause caseGroups
167 caseGroups :: [[Branch]]
169 List.groupBy branchEq (List.sortBy branchCmp branches)
171 toClause :: [Branch] -> State Int Clause
173 case head branches of
174 (A.A _ (P.Data name _) : _, _) ->
175 matchClause (Left name) variables branches Break
177 (A.A _ (P.Literal lit) : _, _) ->
178 matchClause (Right lit) variables branches Break
180 _ -> noMatch "matchCon"
184 :: Either Var.Canonical Literal.Literal
189matchClause _ [] _ _ = noMatch "matchClause"
190matchClause c (_:vs) branches match =
192 Clause c vs' <$> buildMatch (vs' ++ vs) (map flatten branches) match
194 flatten ([], _) = noMatch "matchClause.flatten"
195 flatten (A.A _ pattern : patterns, expr) =
197 P.Data _ argPatterns ->
198 (argPatterns ++ patterns, expr)
204 noMatch "matchClause.flatten"
206 getVars :: State Int [String]
208 case head branches of
209 (A.A _ (P.Data _ argPatterns) : _, _) ->
210 State.forM argPatterns (const newVar)
212 (A.A _ (P.Literal _) : _, _) ->
216 noMatch "matchClause.getVars"
219branchEq :: Branch -> Branch -> Bool
220branchEq (A.A _ pattern : _, _) (A.A _ pattern' : _, _) =
221 case (pattern, pattern') of
222 (P.Data name _, P.Data name' _) ->
225 (P.Literal lit, P.Literal lit') ->
229 noMatch "matchCon.branchEq"
231branchEq _ _ = noMatch "matchCon.branchEq"
234branchCmp :: Branch -> Branch -> Ordering
235branchCmp (A.A _ pattern : _, _) (A.A _ pattern' : _, _) =
236 case (pattern, pattern') of
237 (P.Data name _, P.Data name' _) ->
240 (P.Literal lit, P.Literal lit') ->
244 noMatch "matchCon.branchCmp"
246branchCmp _ _ = noMatch "matchCon.branchCmp"
251matchMix :: [String] -> [Branch] -> Match -> State Int Match
252matchMix vs branches def =
253 State.foldM (flip $ buildMatch vs) def (reverse branchGroups)
256 List.groupBy (\p1 p2 -> isCon p1 == isCon p2) branches
259noMatch :: String -> a
261 error $ "unexpected pattern in '" ++ name ++
262 "' 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