{-# LANGUAGE PatternSynonyms #-} ----------------------------------------------------------------------------- -- | -- Module : Disco.AST.Desugared -- Copyright : disco team and contributors -- Maintainer : byorgey@gmail.com -- -- SPDX-License-Identifier: BSD-3-Clause -- -- Typed abstract syntax trees representing the typechecked, desugared -- Disco language. -- ----------------------------------------------------------------------------- module Disco.AST.Desugared ( -- * Desugared, type-annotated terms DTerm , pattern DTVar , pattern DTPrim , pattern DTUnit , pattern DTBool , pattern DTChar , pattern DTNat , pattern DTRat , pattern DTAbs , pattern DTApp , pattern DTPair , pattern DTCase , pattern DTTyOp , pattern DTNil , pattern DTTest , Container(..) , DBinding , pattern DBinding -- * Branches and guards , DBranch , DGuard , pattern DGPat , DPattern , pattern DPVar , pattern DPWild , pattern DPUnit , pattern DPPair , pattern DPInj , DProperty ) where import GHC.Generics import Data.Void import Unbound.Generics.LocallyNameless import Disco.AST.Generic import Disco.Names (QName (..)) import Disco.Syntax.Operators import Disco.Syntax.Prims import Disco.Types data DS type DProperty = Property_ DS -- | A @DTerm@ is a term which has been typechecked and desugared, so -- it has fewer constructors and complex features than 'ATerm', but -- still retains typing information. type DTerm = Term_ DS type instance X_Binder DS = Name DTerm type instance X_TVar DS = Void -- names are qualified type instance X_TPrim DS = Type type instance X_TLet DS = Void -- Let gets translated to lambda type instance X_TUnit DS = () type instance X_TBool DS = Type type instance X_TChar DS = () type instance X_TString DS = Void type instance X_TNat DS = Type type instance X_TRat DS = () type instance X_TAbs DS = Type -- For lambas this is the function type but -- for forall/exists it's the argument type type instance X_TApp DS = Type type instance X_TCase DS = Type type instance X_TChain DS = Void -- Chains are translated into conjunctions of -- binary comparisons type instance X_TTyOp DS = Type type instance X_TContainer DS = Void -- Literal containers are desugared into -- conversion functions applied to list literals type instance X_TContainerComp DS = Void -- Container comprehensions are translated -- into monadic chains type instance X_TAscr DS = Void -- No type ascriptions type instance X_TTup DS = Void -- No tuples, only pairs type instance X_TParens DS = Void -- No explicit parens -- Extra constructors type instance X_Term DS = X_DTerm data X_DTerm = DTPair_ Type DTerm DTerm | DTNil_ Type | DTTest_ [(String, Type, Name DTerm)] DTerm | DTVar_ Type (QName DTerm) deriving (Show, Generic) instance Subst Type X_DTerm instance Alpha X_DTerm pattern DTVar :: Type -> QName DTerm -> DTerm pattern DTVar ty qname = XTerm_ (DTVar_ ty qname) pattern DTPrim :: Type -> Prim -> DTerm pattern DTPrim ty name = TPrim_ ty name pattern DTUnit :: DTerm pattern DTUnit = TUnit_ () pattern DTBool :: Type -> Bool -> DTerm pattern DTBool ty bool = TBool_ ty bool pattern DTNat :: Type -> Integer -> DTerm pattern DTNat ty int = TNat_ ty int pattern DTRat :: Rational -> DTerm pattern DTRat rat = TRat_ () rat pattern DTChar :: Char -> DTerm pattern DTChar c = TChar_ () c pattern DTAbs :: Quantifier -> Type -> Bind (Name DTerm) DTerm -> DTerm pattern DTAbs q ty lam = TAbs_ q ty lam pattern DTApp :: Type -> DTerm -> DTerm -> DTerm pattern DTApp ty term1 term2 = TApp_ ty term1 term2 pattern DTPair :: Type -> DTerm -> DTerm -> DTerm pattern DTPair ty t1 t2 = XTerm_ (DTPair_ ty t1 t2) pattern DTCase :: Type -> [DBranch] -> DTerm pattern DTCase ty branch = TCase_ ty branch pattern DTTyOp :: Type -> TyOp -> Type -> DTerm pattern DTTyOp ty1 tyop ty2 = TTyOp_ ty1 tyop ty2 pattern DTNil :: Type -> DTerm pattern DTNil ty = XTerm_ (DTNil_ ty) -- | A test frame, recording a collection of variables with their types and -- their original user-facing names. Used for legible reporting of test -- failures inside the enclosed term. pattern DTTest :: [(String, Type, Name DTerm)] -> DTerm -> DTerm pattern DTTest ns t = XTerm_ (DTTest_ ns t) {-# COMPLETE DTVar, DTPrim, DTUnit, DTBool, DTChar, DTNat, DTRat, DTAbs, DTApp, DTPair, DTCase, DTTyOp, DTNil, DTTest #-} type instance X_TLink DS = Void type DBinding = Binding_ DS pattern DBinding :: Maybe (Embed PolyType) -> Name DTerm -> Embed DTerm -> DBinding pattern DBinding m b n = Binding_ m b n {-# COMPLETE DBinding #-} type DBranch = Bind (Telescope DGuard) DTerm type DGuard = Guard_ DS type instance X_GBool DS = Void -- Boolean guards get desugared to pattern-matching type instance X_GPat DS = () type instance X_GLet DS = Void -- Let gets desugared to 'when' with a variable pattern DGPat :: Embed DTerm -> DPattern -> DGuard pattern DGPat embedt pat = GPat_ () embedt pat {-# COMPLETE DGPat #-} type DPattern = Pattern_ DS type instance X_PVar DS = Embed Type type instance X_PWild DS = Embed Type type instance X_PAscr DS = Void type instance X_PUnit DS = () type instance X_PBool DS = Void type instance X_PChar DS = Void type instance X_PString DS = Void type instance X_PTup DS = Void type instance X_PInj DS = Void type instance X_PNat DS = Void type instance X_PCons DS = Void type instance X_PList DS = Void type instance X_PAdd DS = Void type instance X_PMul DS = Void type instance X_PSub DS = Void type instance X_PNeg DS = Void type instance X_PFrac DS = Void -- In the desugared language, constructor patterns (DPPair, DPInj) can -- only contain variables, not nested patterns. This means that the -- desugaring phase has to make explicit the order of matching by -- exploding nested patterns into sequential guards, which makes the -- interpreter simpler. type instance X_Pattern DS = Either (Embed Type, Name DTerm, Name DTerm) -- DPPair (Embed Type, Side, Name DTerm) -- DPInj pattern DPVar :: Type -> Name DTerm -> DPattern pattern DPVar ty name <- PVar_ (unembed -> ty) name where DPVar ty name = PVar_ (embed ty) name pattern DPWild :: Type -> DPattern pattern DPWild ty <- PWild_ (unembed -> ty) where DPWild ty = PWild_ (embed ty) pattern DPUnit :: DPattern pattern DPUnit = PUnit_ () pattern DPPair :: Type -> Name DTerm -> Name DTerm -> DPattern pattern DPPair ty x1 x2 <- XPattern_ (Left (unembed -> ty, x1, x2)) where DPPair ty x1 x2 = XPattern_ (Left (embed ty, x1, x2)) pattern DPInj :: Type -> Side -> Name DTerm -> DPattern pattern DPInj ty s x <- XPattern_ (Right (unembed -> ty, s, x)) where DPInj ty s x = XPattern_ (Right (embed ty, s, x)) {-# COMPLETE DPVar, DPWild, DPUnit, DPPair, DPInj #-} type instance X_QBind DS = Void type instance X_QGuard DS = Void ------------------------------------------------------------ -- getType ------------------------------------------------------------ instance HasType DTerm where getType (DTVar ty _) = ty getType (DTPrim ty _) = ty getType DTUnit = TyUnit getType (DTBool ty _) = ty getType (DTChar _) = TyC getType (DTNat ty _) = ty getType (DTRat _) = TyF getType (DTAbs Lam ty _) = ty getType DTAbs{} = TyProp getType (DTApp ty _ _) = ty getType (DTPair ty _ _) = ty getType (DTCase ty _) = ty getType (DTTyOp ty _ _) = ty getType (DTNil ty) = ty getType (DTTest _ _) = TyProp instance HasType DPattern where getType (DPVar ty _) = ty getType (DPWild ty) = ty getType DPUnit = TyUnit getType (DPPair ty _ _) = ty getType (DPInj ty _ _) = ty