on master help sign in
Add support for pattern matching on literals.
commite80ea9e43025e4fdfa09ed778b693c6f1fdc39e8 authorEvan Czaplicki <evan@Evans-MacBook-Air.local> dateSun 23 Jun 2013, 01:36 (13 years ago) parentc158155
8 files changed+116−60
compiler/Generate/Cases.hs+56−26 compiler/Generate/JavaScript.hs+13−4 compiler/Parse/Literal.hs−5 compiler/Parse/Pattern.hs+25−12 compiler/SourceSyntax/Literal.hs+1−1 compiler/SourceSyntax/Pattern.hs+1−1 compiler/SourceSyntax/Variable.hs+2 compiler/Types/Constrain.hs+18−11
compiler/Generate/Cases.hs+56−26
@@ -1,4 +1,3 @@
1−
21module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where
32
43import Control.Arrow (first)
@@ -8,6 +7,7 @@ import Data.Maybe (fromMaybe)
87
98import Unique
109import SourceSyntax.Location
10+import SourceSyntax.Literal
1111import SourceSyntax.Pattern
1212import SourceSyntax.Expression
1313import Transform.Substitute
@@ -28,7 +28,7 @@ data Match t v
2828 deriving Show
2929
3030data Clause t v =
31− Clause String [String] (Match t v)
31+ Clause (Either String Literal) [String] (Match t v)
3232 deriving Show
3333
3434matchSubst :: [(String,String)] -> Match t v -> Match t v
@@ -43,8 +43,11 @@ matchSubst pairs (Match n cs m) =
4343 clauseSubst (Clause c vs m) =
4444 Clause c (map varSubst vs) (matchSubst pairs m)
4545
46−isCon (PData _ _ : _, _) = True
47−isCon _ = False
46+isCon (p:ps, _) =
47+ case p of
48+ PData _ _ -> True
49+ PLiteral _ -> True
50+ _ -> False
4851
4952isVar p = not (isCon p)
5053
@@ -58,36 +61,63 @@ match vs cs def
5861 | all isCon cs = matchCon vs cs def
5962 | otherwise = matchMix vs cs def
6063
61−matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> Unique (Match t v)
64+matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v
65+ -> Unique (Match t v)
6266matchVar (v:vs) cs def = match vs (map subVar cs) def
6367 where
64− subVar (p:ps, ce@(L t s e)) =
65− let
68+ subVar (p:ps, ce@(L t s e)) = (ps, L t s $ subOnePattern p)
69+ where
6670 loc = L t s
67− subOnePattern (PVar x) = subst x (Var v) e
68− subOnePattern (PAlias x p) =
69− subst x (Var v) e
70− subOnePattern PAnything = e
71− subOnePattern (PRecord fs) =
72− foldr (\x -> subst x (Access (loc (Var v)) x)) e fs
73− in
74− (ps, L t s $ subOnePattern p)
75−
76−matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> Unique (Match t v)
71+ subOnePattern pattern =
72+ case pattern of
73+ PVar x -> subst x (Var v) e
74+ PAlias x p -> subst x (Var v) e
75+ PAnything -> e
76+ PRecord fs ->
77+ foldr (\x -> subst x (Access (loc (Var v)) x)) e fs
78+
79+matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v
80+ -> Unique (Match t v)
7781matchCon (v:vs) cs def = (flip (Match v) def) `liftM` mapM toClause css
78− where css = groupBy (withName (==)) $ sortBy (withName compare) cs
79− withName f (PData n1 _:_,_) (PData n2 _:_,_) = f n1 n2
80− toClause cs = let (PData name _ : _ , _) = head cs in
81− matchClause name (v:vs) cs Break
82+ where
83+ css = groupBy eq (sortBy cmp cs)
84+
85+ cmp (p1:_,_) (p2:_,_) =
86+ case (p1,p2) of
87+ (PData n1 _, PData n2 _) -> compare n1 n2
88+ _ -> compare p1 p2
89+
90+ eq (p1:_,_) (p2:_,_) =
91+ case (p1,p2) of
92+ (PData n1 _, PData n2 _) -> n1 == n2
93+ _ -> p1 == p2
8294
83−matchClause :: String -> [String] -> [([Pattern],LExpr t v)] -> Match t v -> Unique (Clause t v)
95+ toClause cs =
96+ case head cs of
97+ (PData name _ : _, _) -> matchClause (Left name) (v:vs) cs Break
98+ (PLiteral lit : _, _) -> matchClause (Right lit) (v:vs) cs Break
99+
100+matchClause :: Either String Literal
101+ -> [String]
102+ -> [([Pattern],LExpr t v)]
103+ -> Match t v
104+ -> Unique (Clause t v)
84105matchClause c (v:vs) cs def =
85106 do vs' <- getVars
86107 Clause c vs' `liftM` match (vs' ++ vs) (map flatten cs) def
87− where flatten (PData _ ps' : ps, e) = (ps' ++ ps, e)
88− getVars = let (PData _ ps : _, _) = head cs in
89− mapM (\_ -> newVar) ps
108+ where
109+
110+ flatten (p:ps, e) =
111+ case p of
112+ PData _ ps' -> (ps' ++ ps, e)
113+ PLiteral _ -> (ps, e)
114+
115+ getVars =
116+ case head cs of
117+ (PData _ ps : _, _) -> mapM (\_ -> newVar) ps
118+ (PLiteral _ : _, _) -> return []
90119
91−matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> Unique (Match t v)
120+matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v
121+ -> Unique (Match t v)
92122matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
93123 where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
compiler/Generate/JavaScript.hs+13−4
@@ -299,8 +299,12 @@ matchToJS span match =
299299 Match name clauses def ->
300300 do cases <- concat `liftM` mapM (clauseToJS span name) clauses
301301 finally <- matchToJS span def
302− return $ concat [ "\nswitch (", name, ".ctor) {",
303− indent cases, "\n}", finally ]
302+ let isLiteral p = case p of
303+ Clause (Right _) _ _ -> True
304+ _ -> False
305+ access = if any isLiteral clauses then "" else ".ctor"
306+ return $ concat [ "\nswitch (", name, access, ") {"
307+ , indent cases, "\n}", finally ]
304308 Fail -> return ("_E.Case" ++ parens (quoted (show span)))
305309 Break -> return "break;"
306310 Other e -> ret `liftM` toJS' e
@@ -312,10 +316,15 @@ matchToJS span match =
312316 Other _ -> acc ++ [m]
313317 _ -> dropEnd (acc ++ [m]) ms
314318
315−clauseToJS span var (Clause name vars e) = do
319+clauseToJS span var (Clause value vars e) = do
316320 let vars' = map (\n -> var ++ "._" ++ show n) [0..]
317321 s <- matchToJS span $ matchSubst (zip vars vars') e
318− return $ concat [ "\ncase ", quoted name, ":", indent s ]
322+ return $ concat [ "\ncase ", case value of
323+ Left name -> quoted name
324+ Right (Boolean True) -> "true"
325+ Right (Boolean False) -> "false"
326+ Right lit -> show lit
327+ , ":", indent s ]
319328
320329jsNil = "_L.Nil"
321330jsCons e1 e2 = "_L.Cons(" ++ e1 ++ "," ++ e2 ++ ")"
compiler/Parse/Literal.hs−5
@@ -6,11 +6,6 @@ import Text.Parsec hiding (newline,spaces)
66import Text.Parsec.Indent
77
88import Parse.Helpers
9−import qualified Parse.Pattern as Pattern
10−import qualified Parse.Type as Type
11−import Parse.Binop
12−
13−import SourceSyntax.Pattern hiding (tuple,list)
149import SourceSyntax.Literal
1510
1611literal = num <|> str <|> chr
compiler/Parse/Pattern.hs+25−12
@@ -8,20 +8,27 @@ import Data.Char (isUpper)
88import Unique
99import Text.Parsec hiding (newline,spaces,State)
1010import Text.Parsec.Indent
11−import Parse.Helpers
1211
13−import SourceSyntax.Helpers (isOp)
14−import SourceSyntax.Location
15−import SourceSyntax.Pattern hiding (tuple,list)
12+import Parse.Helpers
13+import Parse.Literal
1614import qualified SourceSyntax.Pattern as Pattern
17−import SourceSyntax.Expression (Expr(..), Def(..), LExpr)
15+import SourceSyntax.Everything hiding (parens, tuple)
16+
1817
1918basic :: IParser Pattern
20−basic =
21− choice [ char '_' >> return PAnything
22− , do x@(c:_) <- var
23− return $ if isUpper c then PData x [] else PVar x
24− ]
19+basic = choice
20+ [ char '_' >> return PAnything
21+ , do v <- var
22+ return $ case v of
23+ "True" -> PLiteral (Boolean True)
24+ "False" -> PLiteral (Boolean False)
25+ c : _ -> if isUpper c then PData v [] else PVar v
26+ , do lit <- literal
27+ return $ case lit of
28+ Str s -> foldr combine (PData "[]" []) s
29+ where combine h t = PData "::" [PLiteral (Chr h),t]
30+ _ -> PLiteral lit
31+ ]
2532
2633asPattern :: Pattern -> IParser Pattern
2734asPattern pattern = do
@@ -41,10 +48,16 @@ list :: IParser Pattern
4148list = Pattern.list <$> braces (commaSep expr)
4249
4350term :: IParser Pattern
44−term = (choice [ record, tuple, list, basic ]) <?> "pattern"
51+term =
52+ (choice [ record, tuple, list, basic ]) <?> "pattern"
4553
4654patternConstructor :: IParser Pattern
47−patternConstructor = PData <$> capVar <*> spacePrefix term
55+patternConstructor = do
56+ v <- capVar
57+ case v of
58+ "True" -> return $ PLiteral (Boolean True)
59+ "False" -> return $ PLiteral (Boolean False)
60+ _ -> PData v <$> spacePrefix term
4861
4962expr :: IParser Pattern
5063expr = do
compiler/SourceSyntax/Literal.hs+1−1
@@ -8,7 +8,7 @@ data Literal = IntNum Int
88 | Chr Char
99 | Str String
1010 | Boolean Bool
11− deriving (Eq, Data, Typeable)
11+ deriving (Eq, Ord, Data, Typeable)
1212
1313
1414instance Show Literal where
compiler/SourceSyntax/Pattern.hs+1−1
@@ -13,7 +13,7 @@ data Pattern = PData String [Pattern]
1313 | PVar String
1414 | PAnything
1515 | PLiteral Literal.Literal
16− deriving (Eq, Data, Typeable)
16+ deriving (Eq, Ord, Data, Typeable)
1717
1818cons h t = PData "::" [h,t]
1919nil = PData "[]" []
compiler/SourceSyntax/Variable.hsnew file+2
@@ -0,0 +1,2 @@
1+module SourceSyntax.Variable where
2+
compiler/Types/Constrain.hs+18−11
@@ -142,13 +142,13 @@ gen (L _ span expr) =
142142 Case e cases ->
143143 do (as,cs,t) <- gen e
144144 (ass,css,ts) <- liftM unzip3 $ mapM (caseGen t) cases
145+ b <- beta
145146 return ( unionsA $ as:ass
146147 , let cases' = map snd cases
147148 locs = zipWith merge cases' (tail cases')
148− csts = zipWith (:=:) ts (tail ts)
149− cs' = zipWith ($) locs csts
149+ cs' = zipWith (\t loc -> loc (b :=: t)) ts locs
150150 in concat $ cs' : cs : css
151− , head ts)
151+ , b)
152152
153153 ExplicitList es ->
154154 do (ass,css,ts) <- unzip3 `liftM` mapM gen es
@@ -221,14 +221,19 @@ gen (L _ span expr) =
221221 , t2 )
222222
223223 Markdown _ -> primitive element
224− Literal lit ->
225− case lit of
226− IntNum _ -> do t <- beta
227− return (Map.empty, [loc' $ t :<: number], t)
228− FloatNum _ -> primitive float
229− Chr _ -> primitive char
230− Str _ -> primitive string
231− Boolean _ -> primitive bool
224+ Literal lit -> literalGen loc' lit
225+
226+literalGen :: (Constraint -> Located Constraint)
227+ -> Literal
228+ -> Unique (TVarMap, Constraints, Type)
229+literalGen loc lit =
230+ case lit of
231+ IntNum _ -> do t <- beta
232+ return (Map.empty, [loc $ t :<: number], t)
233+ FloatNum _ -> primitive float
234+ Boolean _ -> primitive bool
235+ Chr _ -> primitive char
236+ Str _ -> primitive string
232237
233238
234239primitive :: Type -> Unique (TVarMap, Constraints, Type)
@@ -251,6 +256,8 @@ patternGen loc tipe as pattern =
251256 case pattern of
252257 PAnything -> do b <- beta ; return ( as, [], b )
253258
259+ PLiteral lit -> literalGen loc lit
260+
254261 PVar v -> do
255262 b <- beta
256263 let cs = map (loc . (b :=:) . VarT) (Map.findWithDefault [] v as)