% % (c) The GRASP/AQUA Project, Glasgow University, 1992-1994 % \section[PatSyntax]{Abstract Haskell syntax---patterns} \begin{code} #include "HsVersions.h" module HsPat where import AbsPrel ( mkTupleTy, mkListTy IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp) IF_ATTACK_PRAGMAS(COMMA pprPrimOp) #ifdef DPH , mkProcessorTy #endif ) import AbsUniType import HsLit ( Literal ) import HsExpr ( Expr, TypecheckedExpr(..) ) import Id import IdInfo import Maybes ( maybeToBool, Maybe(..) ) import Name ( Name ) import ProtoName ( ProtoName(..) ) -- .. for pragmas only import Outputable import Pretty import Unique ( Unique ) import Util \end{code} Patterns come in distinct before- and after-typechecking flavo(u)rs. \begin{code} data InPat name = WildPatIn --X wild card | VarPatIn name --X variable | LitPatIn Literal -- literal | LazyPatIn (InPat name) --X lazy pattern | AsPatIn name --X as pattern (InPat name) | ConPatIn name --X constructed type [(InPat name)] | ConOpPatIn (InPat name) name (InPat name) | ListPatIn [InPat name] --X syntactic list -- must have >= 1 elements | TuplePatIn [InPat name] --X tuple -- UnitPat is TuplePat [] | NPlusKPatIn name -- n+k pattern Literal #ifdef DPH | ProcessorPatIn [(InPat name)] (InPat name) -- (|pat1,...,patK;pat|) #endif {- Data Parallel Haskell -} type ProtoNamePat = InPat ProtoName type RenamedPat = InPat Name data TypecheckedPat = WildPat UniType -- wild card | VarPat Id -- variable (type is in the Id) | LazyPat TypecheckedPat -- lazy pattern | AsPat Id -- as pattern TypecheckedPat | ConPat Id -- constructed type; UniType -- the type of the pattern [TypecheckedPat] | ConOpPat TypecheckedPat -- just a special case... Id TypecheckedPat UniType | ListPat -- syntactic list UniType -- the type of the elements [TypecheckedPat] | TuplePat [TypecheckedPat] -- tuple -- UnitPat is TuplePat [] | LitPat -- Used for *non-overloaded* literal patterns: -- Int#, Char#, Int, Char, String, etc. Literal UniType -- type of pattern | NPat -- Used for *overloaded* literal patterns Literal -- the literal is retained so that -- the desugarer can readily identify -- equations with identical literal-patterns UniType -- type of pattern, t TypecheckedExpr -- Of type t -> Bool; detects match | NPlusKPat Id Literal -- Same reason as for LitPat -- (This could be an Integer, but then -- it's harder to partitionEqnsByLit -- in the desugarer.) UniType -- Type of pattern, t TypecheckedExpr -- "fromInteger literal"; of type t TypecheckedExpr -- Of type t-> t -> Bool; detects match TypecheckedExpr -- Of type t -> t -> t; subtracts k #ifdef DPH | ProcessorPat [TypecheckedPat] -- Typechecked Pattern [TypecheckedExpr] -- Of type t-> Integer; conversion TypecheckedPat -- Data at that processor #endif {- Data Parallel Haskell -} \end{code} Note: If @typeOfPat@ doesn't bear a strong resemblance to @typeOfCoreExpr@, then something is wrong. \begin{code} typeOfPat :: TypecheckedPat -> UniType typeOfPat (WildPat ty) = ty typeOfPat (VarPat var) = getIdUniType var typeOfPat (LazyPat pat) = typeOfPat pat typeOfPat (AsPat var pat) = getIdUniType var typeOfPat (ConPat _ ty _) = ty typeOfPat (ConOpPat _ _ _ ty) = ty typeOfPat (ListPat ty _) = mkListTy ty typeOfPat (TuplePat pats) = mkTupleTy (length pats) (map typeOfPat pats) typeOfPat (LitPat lit ty) = ty typeOfPat (NPat lit ty _) = ty typeOfPat (NPlusKPat n k ty _ _ _) = ty #ifdef DPH -- Should be more efficient to find type of pid than pats typeOfPat (ProcessorPat pats _ pat) = mkProcessorTy (map typeOfPat pats) (typeOfPat pat) #endif {- Data Parallel Haskell -} \end{code} \begin{code} instance (NamedThing name) => NamedThing (InPat name) where hasType pat = False #ifdef DEBUG getExportFlag = panic "NamedThing.InPat.getExportFlag" isLocallyDefined = panic "NamedThing.InPat.isLocallyDefined" getOrigName = panic "NamedThing.InPat.getOrigName" getOccurrenceName = panic "NamedThing.InPat.getOccurrenceName" getInformingModules = panic "NamedThing.InPat.getOccurrenceName" getSrcLoc = panic "NamedThing.InPat.getSrcLoc" getTheUnique = panic "NamedThing.InPat.getTheUnique" getType pat = panic "NamedThing.InPat.getType" fromPreludeCore = panic "NamedThing.InPat.fromPreludeCore" #endif instance NamedThing TypecheckedPat where hasType pat = True getType = typeOfPat #ifdef DEBUG getExportFlag = panic "NamedThing.TypecheckedPat.getExportFlag" isLocallyDefined = panic "NamedThing.TypecheckedPat.isLocallyDefined" getOrigName = panic "NamedThing.TypecheckedPat.getOrigName" getOccurrenceName = panic "NamedThing.TypecheckedPat.getOccurrenceName" getInformingModules = panic "NamedThing.TypecheckedPat.getOccurrenceName" getSrcLoc = panic "NamedThing.TypecheckedPat.getSrcLoc" getTheUnique = panic "NamedThing.TypecheckedPat.getTheUnique" fromPreludeCore = panic "NamedThing.TypecheckedPat.fromPreludeCore" #endif \end{code} \begin{code} instance (Outputable name) => Outputable (InPat name) where ppr = pprInPat pprInPat :: (Outputable name) => PprStyle -> InPat name -> Pretty pprInPat sty (WildPatIn) = ppStr "_" pprInPat sty (VarPatIn var) = ppr sty var pprInPat sty (LitPatIn s) = ppr sty s pprInPat sty (LazyPatIn pat) = ppBeside (ppChar '~') (ppr sty pat) pprInPat sty (AsPatIn name pat) = ppBesides [ppLparen, ppr sty name, ppChar '@', ppr sty pat, ppRparen] pprInPat sty (ConPatIn c pats) = if null pats then ppr sty c else ppBesides [ppLparen, ppr sty c, ppSP, interppSP sty pats, ppRparen] pprInPat sty (ConOpPatIn pat1 op pat2) = ppBesides [ppLparen, ppr sty pat1, ppSP, ppr sty op, ppSP, ppr sty pat2, ppRparen] -- ToDo: use pprOp to print op (but this involves fiddling various -- contexts & I'm lazy...); *PatIns are *rarely* printed anyway... (WDP) pprInPat sty (ListPatIn pats) = ppBesides [ppLbrack, interpp'SP sty pats, ppRbrack] pprInPat sty (TuplePatIn pats) = ppBesides [ppLparen, interpp'SP sty pats, ppRparen] pprInPat sty (NPlusKPatIn n k) = ppBesides [ppLparen, ppr sty n, ppChar '+', ppr sty k, ppRparen] #ifdef DPH pprInPat sty (ProcessorPatIn pats pat) = ppBesides [ppStr "(|", interpp'SP sty pats,ppSemi , ppr sty pat , ppStr "|)"] #endif {- Data Parallel Haskell -} \end{code} Problems with @Outputable@ instance for @TypecheckedPat@ when no original names. \begin{code} instance Outputable TypecheckedPat where ppr = pprTypecheckedPat \end{code} \begin{code} pprTypecheckedPat sty (WildPat ty) = ppChar '_' pprTypecheckedPat sty (VarPat var) = ppr sty var pprTypecheckedPat sty (LazyPat pat) = ppBesides [ppChar '~', ppr sty pat] pprTypecheckedPat sty (AsPat name pat) = ppBesides [ppLparen, ppr sty name, ppChar '@', ppr sty pat, ppRparen] pprTypecheckedPat sty (ConPat name ty []) = ppBeside (ppr sty name) (ifPprShowAll sty (pprConPatTy sty ty)) pprTypecheckedPat sty (ConPat name ty pats) = ppBesides [ppLparen, ppr sty name, ppSP, interppSP sty pats, ppRparen, ifPprShowAll sty (pprConPatTy sty ty) ] pprTypecheckedPat sty (ConOpPat pat1 op pat2 ty) = ppBesides [ppLparen, ppr sty pat1, ppSP, pprOp sty op, ppSP, ppr sty pat2, ppRparen] pprTypecheckedPat sty (ListPat ty pats) = ppBesides [ppLbrack, interpp'SP sty pats, ppRbrack] pprTypecheckedPat sty (TuplePat pats) = ppBesides [ppLparen, interpp'SP sty pats, ppRparen] pprTypecheckedPat sty (LitPat l ty) = ppr sty l -- ToDo: print more pprTypecheckedPat sty (NPat l ty e) = ppr sty l -- ToDo: print more pprTypecheckedPat sty (NPlusKPat n k ty e1 e2 e3) = case sty of PprForUser -> basic_ppr _ -> ppHang basic_ppr 4 exprs_ppr where basic_ppr = ppBesides [ppLparen, ppr sty n, ppChar '+', ppr sty k, ppRparen] exprs_ppr = ppSep [ ppBeside (ppStr "{- ") (ppr sty ty), ppr sty e1, ppr sty e2, ppBeside (ppr sty e3) (ppStr " -}")] #ifdef DPH pprTypecheckedPat sty (ProcessorPat pats convs pat) = case sty of PprForUser -> basic_ppr _ -> ppHang basic_ppr 4 exprs_ppr where basic_ppr = ppBesides [ppStr "(|", interpp'SP sty pats,ppSemi , ppr sty pat , ppStr "|)"] exprs_ppr = ppBesides [ppStr "{- " , ppr sty convs, ppStr " -}"] #endif {- Data Parallel Haskell -} pprConPatTy :: PprStyle -> UniType -> Pretty pprConPatTy sty ty = ppBesides [ppLparen, ppr sty ty, ppRparen] \end{code} %************************************************************************ %* * %* predicates for checking things about pattern-lists in EquationInfo * %* * %************************************************************************ \subsection[Pat-list-predicates]{Look for interesting things in patterns} Unlike in the Wadler chapter, where patterns are either ``variables'' or ``constructors,'' here we distinguish between: \begin{description} \item[unfailable:] Patterns that cannot fail to match: variables, wildcards, and lazy patterns. These are the irrefutable patterns; the two other categories are refutable patterns. \item[constructor:] A non-literal constructor pattern (see next category). \item[literal (including n+k patterns):] At least the numeric ones may be overloaded. \end{description} A pattern is in {\em exactly one} of the above three categories; `as' patterns are treated specially, of course. \begin{code} unfailablePats :: [TypecheckedPat] -> Bool unfailablePats pat_list = all unfailablePat pat_list unfailablePat (AsPat _ pat) = unfailablePat pat unfailablePat (WildPat _) = True unfailablePat (VarPat _) = True unfailablePat (LazyPat _) = True unfailablePat other = False patsAreAllCons :: [TypecheckedPat] -> Bool patsAreAllCons pat_list = all isConPat pat_list isConPat (AsPat _ pat) = isConPat pat isConPat (ConPat _ _ _) = True isConPat (ConOpPat _ _ _ _) = True isConPat (ListPat _ _) = True isConPat (TuplePat _) = True #ifdef DPH isConPat (ProcessorPat _ _ _) = True #endif {- Data Parallel Haskell -} isConPat other = False patsAreAllLits :: [TypecheckedPat] -> Bool patsAreAllLits pat_list = all isLitPat pat_list isLitPat (AsPat _ pat) = isLitPat pat isLitPat (LitPat _ _) = True isLitPat (NPat _ _ _) = True isLitPat (NPlusKPat _ _ _ _ _ _)= True isLitPat other = False #ifdef DPH patsAreAllProcessor :: [TypecheckedPat] -> Bool patsAreAllProcessor pat_list = all isProcessorPat pat_list where isProcessorPat (ProcessorPat _ _ _) = True isProcessorPat _ = False #endif \end{code} \begin{code} -- A pattern is irrefutable if a match on it cannot fail -- (at any depth) irrefutablePat :: TypecheckedPat -> Bool irrefutablePat (WildPat _) = True irrefutablePat (VarPat _) = True irrefutablePat (LazyPat _) = True irrefutablePat (AsPat _ pat) = irrefutablePat pat irrefutablePat (ConPat con tys pats) = all irrefutablePat pats && only_con con irrefutablePat (ConOpPat pat1 con pat2 _) = irrefutablePat pat1 && irrefutablePat pat1 && only_con con irrefutablePat (ListPat _ _) = False irrefutablePat (TuplePat pats) = all irrefutablePat pats irrefutablePat other_pat = False -- Literals, NPlusK, NPat only_con con = maybeToBool (maybeSingleConstructorTyCon tycon) where (_,_,_, tycon) = getDataConSig con \end{code}