66{-# LANGUAGE DeriveFoldable #-}
77{-# LANGUAGE DeriveFunctor #-}
88{-# LANGUAGE DeriveTraversable #-}
9- {-# LANGUAGE ExistentialQuantification #-}
9+ {-# LANGUAGE ExistentialQuantification, DuplicateRecordFields, NoFieldSelectors #-}
1010{-# LANGUAGE ExtendedDefaultRules #-}
1111{-# LANGUAGE FlexibleContexts #-}
1212{-# LANGUAGE FlexibleInstances #-}
@@ -1105,21 +1105,61 @@ desugarExp userDefinedTypeAliases globals = go mempty
11051105 HSE. RecConstr _ qname fields -> go scope $ makeConstructRecord qname fields
11061106 e -> Left $ UnsupportedSyntax $ show e
11071107
1108+ -- | Handles both user-defined case and primitive type case (Maybe, Either, etc.)
1109+ desugarCase
1110+ :: HSE. SrcSpanInfo
1111+ -> HSE. Exp HSE. SrcSpanInfo
1112+ -> [HSE. Alt HSE. SrcSpanInfo ]
1113+ -> Either DesugarError (HSE. Exp HSE. SrcSpanInfo )
1114+ desugarCase _ _ [] = Left $ UnsupportedSyntax " empty case"
1115+ -- Generates this:
1116+ --
1117+ -- Either.either (\a -> e1 a) (\b -> e2 b) scrutinee
1118+ -- Maybe.maybe e1 (\b -> e2 b) scrutinee
1119+ -- etc
1120+ desugarCase l scrutinee alts0 | any isPrimCons alts0 = do
1121+ let (wilds, alts) =
1122+ Either. partitionEithers $
1123+ map (\ x -> maybe (Right x) Left $ desugarWildPat x) alts0
1124+ conses <- traverse desugarPrimCons alts
1125+ let names = map (. accessor) conses
1126+ let consNames = map (. constructor) conses
1127+ let mwildpat = Maybe. listToMaybe wilds
1128+ if
1129+ | length wilds > 1 ->
1130+ Left $ UnsupportedSyntax $
1131+ " at most one catch-all (var/wildcard) in a case is permitted"
1132+ | Set. toList (Set. fromList consNames) /= List. sort consNames ->
1133+ Left $ UnsupportedSyntax $ " duplicate constructors in case: " <>
1134+ show consNames
1135+ <> show consNames
1136+ -- | All constructors below to the same type.
1137+ | Set. size (Set. fromList names) == 1 ->
1138+ HSE. App l <$> desugarPrimAlts l (List. concat (take 1 names)) conses mwildpat
1139+ <*> pure scrutinee
1140+ | otherwise ->
1141+ Left $ UnsupportedSyntax $ " mismatching types for constructors in case: "
1142+ <> show consNames
11081143-- Generates this:
11091144--
11101145-- Variant.run
11111146-- x
11121147-- $ Variant.cons @"Main.Number" (\i -> Show.show i) $
11131148-- Variant.cons @"Main.Text" (\t -> t) $
1114- -- Variant.nil
1115- desugarCase :: HSE. SrcSpanInfo -> HSE. Exp HSE. SrcSpanInfo -> [HSE. Alt HSE. SrcSpanInfo ] -> Either DesugarError (HSE. Exp HSE. SrcSpanInfo )
1116- desugarCase _ _ [] = Left $ UnsupportedSyntax " empty case"
1149+ -- Variant.nil (or `WildP x' for `_ -> x')
11171150desugarCase l scrutinee xs = do
1118- alts <- fmap (List. sortBy (Ord. comparing fst )) $ traverse desugarAlt xs
1119- pure $
1120- HSE. App l (HSE. App l run scrutinee) $
1121- foldr (HSE. App l) nil $
1122- map snd alts
1151+ alts0 <- fmap (List. sortBy (Ord. comparing fst )) $ traverse desugarAlt xs
1152+ let (alts,wild0) = Either. partitionEithers $
1153+ map (\ (x,y) -> bimap (const y) (const y) x) alts0
1154+ if length wild0 > 1
1155+ then
1156+ Left $ UnsupportedSyntax $
1157+ " at most one catch-all (var/wildcard) in a case is permitted"
1158+ else do
1159+ let wild = Maybe. listToMaybe wild0
1160+ pure $
1161+ HSE. App l (HSE. App l run scrutinee) $
1162+ foldr (HSE. App l) (Maybe. fromMaybe nil wild) alts
11231163 where
11241164 tySym s = HSE. TyPromoted l (HSE. PromotedString l s s)
11251165 nil =
@@ -1142,11 +1182,11 @@ desugarCase l scrutinee xs = do
11421182 [HSE. PVar _ (HSE. Ident _ x)]
11431183 )
11441184 (HSE. UnGuardedRhs _ e)
1145- _
1185+ Nothing
11461186 ) =
11471187 -- Variant.cons @name (\x -> e)
11481188 pure $
1149- (name,) $
1189+ (Left name,) $
11501190 HSE. App
11511191 l'
11521192 ( HSE. App
@@ -1168,11 +1208,11 @@ desugarCase l scrutinee xs = do
11681208 []
11691209 )
11701210 (HSE. UnGuardedRhs _ e)
1171- _
1211+ Nothing
11721212 ) =
11731213 -- Variant.cons @name (\_ -> e)
11741214 pure $
1175- (name,) $
1215+ (Left name,) $
11761216 HSE. App
11771217 l'
11781218 ( HSE. App
@@ -1184,8 +1224,99 @@ desugarCase l scrutinee xs = do
11841224 (HSE. TypeApp l' (tySym name))
11851225 )
11861226 (HSE. Lambda l' [HSE. PVar l' (HSE. Ident l' " _" )] e)
1227+ desugarAlt (HSE. Alt l' (HSE. PWildCard l1) (HSE. UnGuardedRhs _ e) Nothing ) =
1228+ pure $ (Right () , HSE. App
1229+ l'
1230+ ( HSE. Var
1231+ l1
1232+ (hellQName l' " WildA" )
1233+ )
1234+ e)
11871235 desugarAlt _ = Left $ UnsupportedSyntax " case alternative syntax"
11881236
1237+ data PrimCons = PrimCons {
1238+ l :: HSE. SrcSpanInfo ,
1239+ accessor :: String ,
1240+ constructor :: String ,
1241+ bindings :: [String ],
1242+ rhs :: HSE. Exp HSE. SrcSpanInfo
1243+ } deriving (Show )
1244+
1245+ data WildPat = WildPat {
1246+ l :: HSE. SrcSpanInfo ,
1247+ rhs :: HSE. Exp HSE. SrcSpanInfo
1248+ } deriving (Show )
1249+
1250+ desugarPrimCons
1251+ :: HSE. Alt HSE. SrcSpanInfo
1252+ -> Either DesugarError PrimCons
1253+ desugarPrimCons (HSE. Alt l (HSE. PApp _ qname slots) (HSE. UnGuardedRhs _ rhs) Nothing )
1254+ | HSE. Qual _ (HSE. ModuleName _ prefix) (HSE. Ident _ string) <- qname,
1255+ let constructor = (prefix ++ " ." ++ string),
1256+ Just (accessor,arity) <- Map. lookup constructor primitiveConstructors =
1257+ if length slots /= arity
1258+ then Left $ UnsupportedSyntax $ " wrong number of arguments to constructor in case alt: " ++ string
1259+ else do bindings <- traverse desugarPVarIdent slots
1260+ pure PrimCons {l, accessor, constructor, bindings, rhs}
1261+ where
1262+ desugarPVarIdent (HSE. PVar _ (HSE. Ident _ i)) = pure i
1263+ desugarPVarIdent _ =
1264+ Left $
1265+ UnsupportedSyntax " only var patterns are allowed in a primitive case (for now)"
1266+ desugarPrimCons (HSE. Alt _ p _ _) =
1267+ Left $ UnsupportedSyntax $
1268+ " unknown primitive constructor in pat: " <> HSE. prettyPrint p
1269+
1270+ desugarWildPat
1271+ :: HSE. Alt HSE. SrcSpanInfo
1272+ -> Maybe WildPat
1273+ desugarWildPat (HSE. Alt _ (HSE. PWildCard l) (HSE. UnGuardedRhs _ rhs) Nothing ) =
1274+ Just WildPat { l, rhs }
1275+ desugarWildPat _ = Nothing
1276+
1277+ isPrimCons :: HSE. Alt HSE. SrcSpanInfo -> Bool
1278+ isPrimCons (HSE. Alt _ (HSE. PApp _ qname _) _ _)
1279+ | HSE. Qual _ (HSE. ModuleName _ prefix) (HSE. Ident _ string) <- qname =
1280+ Map. member (prefix ++ " ." ++ string) primitiveConstructors
1281+ isPrimCons _ = False
1282+
1283+ desugarPrimAlts
1284+ :: HSE. SrcSpanInfo
1285+ -> String -- ^ Accessor e.g. Maybe.maybe
1286+ -> [PrimCons ] -- ^ (cons, bindings, rhs)
1287+ -> Maybe WildPat
1288+ -> Either DesugarError (HSE. Exp HSE. SrcSpanInfo )
1289+ desugarPrimAlts l accessor consesFound mwildpat =
1290+ case lookup accessor primitiveSumTypes of
1291+ Nothing -> Left $ UnsupportedSyntax $ " invalid primitive accessor " <> accessor
1292+ Just cases -> do
1293+ alts <- traverse makeAlt cases
1294+ pure $ foldl' (HSE. App l) accessorE alts
1295+ where
1296+ accessorE =
1297+ HSE. Var l (HSE. Qual l (HSE. ModuleName l prefix) (HSE. Ident l string))
1298+ (prefix,drop 1 -> string) = List. break (== ' .' ) accessor
1299+ makeAlt (cons, arity) =
1300+ case find ((== cons) . (. constructor)) consesFound of
1301+ Nothing ->
1302+ case mwildpat of
1303+ Nothing ->
1304+ Left $ UnsupportedSyntax $ " missing constructor in case: " <> cons
1305+ Just wildpat ->
1306+ pure $ HSE. Lambda
1307+ wildpat. l
1308+ pats
1309+ wildpat. rhs
1310+ where pats = [ HSE. PWildCard wildpat. l
1311+ | _ <- [1 .. arity] ]
1312+ Just primCons ->
1313+ pure $ HSE. Lambda
1314+ primCons. l
1315+ pats
1316+ primCons. rhs
1317+ where pats = [ HSE. PVar primCons. l (HSE. Ident primCons. l b)
1318+ | b <- primCons. bindings ]
1319+
11891320bindingStrings :: Binding -> [String ]
11901321bindingStrings (Singleton string) = [string]
11911322bindingStrings (Tuple tups) = tups
@@ -1233,6 +1364,10 @@ desugarArg _ (HSE.PTuple _ HSE.Boxed idents)
12331364 | Just idents' <- traverse desugarIdent idents =
12341365 pure (Tuple idents', Nothing )
12351366desugarArg userDefinedTypeAliases (HSE. PParen _ p) = desugarArg userDefinedTypeAliases p
1367+ desugarArg _ (HSE. PWildCard l) =
1368+ pure $ (Singleton $
1369+ " $wildcard_" <> show (HSE. startLine l) <> " _" <> show (HSE. startColumn l),
1370+ Nothing )
12361371desugarArg _ p = Left $ BadParameterSyntax $ HSE. prettyPrint p
12371372
12381373desugarIdent :: HSE. Pat HSE. SrcSpanInfo -> Maybe String
@@ -1848,6 +1983,7 @@ polyLits =
18481983 " hell:Hell.LeftV" LeftV :: forall (k :: Symbol ) a (xs :: List ). SSymbol k -> a -> Variant (ConsL k a xs )
18491984 " hell:Hell.RightV" RightV :: forall (k :: Symbol ) a (xs :: List ) (k'' :: Symbol ) a'' . Variant (ConsL k'' a'' xs ) -> Variant (ConsL k a (ConsL k'' a'' xs ))
18501985 " hell:Hell.NilA" NilA :: forall r . Accessor 'NilL r
1986+ " hell:Hell.WildA" WildA :: forall r (xs :: List ). r -> Accessor xs r
18511987 " hell:Hell.ConsA" ConsA :: forall (k :: Symbol ) a r (xs :: List ). (a -> r ) -> Accessor xs r -> Accessor (ConsL k a xs ) r
18521988 " hell:Hell.runAccessor" runAccessor :: forall (t :: Symbol ) r (xs :: List ). Tagged t (Variant xs ) -> Accessor xs r -> r
18531989
@@ -2090,6 +2226,31 @@ polyLits =
20902226 in toplevel
20912227 )
20922228
2229+ --------------------------------------------------------------------------------
2230+ -- Primitive sum types (for case support)
2231+
2232+ -- Easy access lookup for case alt desugaring.
2233+ primitiveConstructors :: Map String (String , Int )
2234+ -- ^ cons ^ type ^ arity
2235+ primitiveConstructors = Map. fromList [
2236+ (cons, (typ, arity))
2237+ | (typ,conses) <- primitiveSumTypes
2238+ , (cons,arity) <- conses
2239+ ]
2240+
2241+ -- | Easier-to-maintain list for me, the author.
2242+ primitiveSumTypes :: [ (String , [(String , Int )]) ]
2243+ -- ^ type ^ cons ^ arity
2244+ primitiveSumTypes =
2245+ [ (" Maybe.maybe" ,[(" Maybe.Nothing" ,0 ),(" Maybe.Just" ,1 )]),
2246+ (" Either.either" , [(" Either.Left" , 1 ),(" Either.Right" , 1 )]),
2247+ (" Exit.exitCode" , [(" Exit.ExitSuccess" , 0 ),(" Exit.ExitFailure" , 1 )]),
2248+ (" Bool.bool" , [(" Bool.False" , 0 ),(" Bool.True" , 0 )]),
2249+ (" These.these" , [(" These.This" , 1 ),(" These.That" , 1 ),(" These.These" ,2 )]),
2250+ (" Json.value" , [(" Json.Null" ,0 ),(" Json.Bool" ,1 ),(" Json.String" ,1 ),(" Json.Number" ,1 ),(" Json.Array" , 1 ),(" Json.Object" , 1 )])
2251+ ]
2252+
2253+
20932254--------------------------------------------------------------------------------
20942255-- Internal-use only, used by the desugarer
20952256
@@ -2438,7 +2599,7 @@ bindingVars l tupleVar (Tuple names) = do
24382599 _ -> lift $ Left $ UnsupportedTupleSize
24392600
24402601equal :: (MonadState Elaborate m ) => HSE. SrcSpanInfo -> IRep IMetaVar -> IRep IMetaVar -> m ()
2441- equal l x y = modify \ elaborate' -> elaborate' {equalities = equalities elaborate' <> Set. singleton (Equality l x y)}
2602+ equal l x y = modify \ elaborate' -> elaborate' {equalities = elaborate'. equalities <> Set. singleton (Equality l x y)}
24422603
24432604freshIMetaVar :: (MonadState Elaborate m ) => HSE. SrcSpanInfo -> m IMetaVar
24442605freshIMetaVar srcSpanInfo = do
@@ -2670,12 +2831,14 @@ data Variant (xs :: List) where
26702831data Accessor (xs :: List ) r where
26712832 NilA :: Accessor 'NilL r
26722833 ConsA :: forall k a r xs . (a -> r ) -> Accessor xs r -> Accessor (ConsL k a xs ) r
2834+ WildA :: forall r xs . r -> Accessor xs r
26732835
26742836-- | Run a total case-analysis against a variant, given an accessor
26752837-- record.
26762838runAccessor :: Tagged s (Variant xs ) -> Accessor xs r -> r
26772839runAccessor (Tagged _ (LeftV _k a)) (ConsA f _) = f a
26782840runAccessor (Tagged t (RightV xs)) (ConsA _ ys) = runAccessor (Tagged t xs) ys
2841+ runAccessor _ (WildA r) = r
26792842
26802843--------------------------------------------------------------------------------
26812844-- Pretty printing
0 commit comments