ref: b9f0554fb00ffee57f8ff08e932b015341ffac04
dir: /src/MicroHs/Expr.hs/
module MicroHs.Expr(
IdentModule,
EModule(..),
ExportItem(..),
ImportSpec(..),
ImportItem(..),
EDef(..), showEDefs,
Expr(..), eLam, eEqn, eEqns, showExpr, eqExpr,
Listish(..),
Lit(..), showLit,
CType(..),
EBind(..), showEBind, showEBinds,
Eqn(..),
EStmt(..),
EAlts(..),
EField(..), unEField,
EAlt,
ECaseArm,
FunDep,
EType, showEType, eqEType,
EConstraint,
EPat, patVars, isPConApp,
EKind, kType, kConstraint,
ESort, sKind,
IdKind(..), idKindIdent,
LHS,
Constr(..), ConstrField, SType,
ConTyInfo,
Con(..), conIdent, conArity, conFields,
tupleConstr, getTupleConstr,
mkTupleSel,
eApps,
lhsToType,
subst,
allVarsExpr, allVarsBind, allVarsEqns,
setSLocExpr,
errorMessage,
Assoc(..), Fixity,
getBindsVars,
HasLoc(..),
eForall,
eDummy,
impossible, impossibleShow,
getArrow, getArrows,
) where
import Prelude hiding ((<>))
import Control.Arrow(first)
import Data.List
import Data.Maybe
import MicroHs.Ident
import Text.PrettyPrint.HughesPJ hiding(first)
import GHC.Stack
type IdentModule = Ident
----------------------
data EModule = EModule IdentModule [ExportItem] [EDef]
--DEBUG deriving (Show)
data ExportItem
= ExpModule IdentModule
| ExpTypeCon Ident
| ExpType Ident
| ExpValue Ident
--DEBUG deriving (Show)
data EDef
= Data LHS [Constr] Deriving
| Newtype LHS Constr Deriving
| Type LHS EType
| Fcn Ident [Eqn]
| Sign [Ident] EType
| KindSign Ident EKind
| Import ImportSpec
| ForImp (Maybe String) Ident EType
| Infix Fixity [Ident]
| Class [EConstraint] LHS [FunDep] [EBind] -- XXX will probable need initial forall with FD
| Instance EConstraint [EBind] -- no deriving yet
| Default [EType]
--DEBUG deriving (Show)
data ImportSpec = ImportSpec Bool Ident (Maybe Ident) (Maybe (Bool, [ImportItem])) -- first Bool indicates 'qualified', second 'hiding'
--DEBUG deriving (Show)
data ImportItem
= ImpTypeCon Ident
| ImpType Ident
| ImpValue Ident
--DEBUG deriving (Show)
type Deriving = [EConstraint]
data Expr
= EVar Ident
| EApp Expr Expr
| EOper Expr [(Ident, Expr)]
| ELam [Eqn]
| ELit SLoc Lit
| ECase Expr [ECaseArm]
| ELet [EBind] Expr
| ETuple [Expr]
| EListish Listish
| EDo (Maybe Ident) [EStmt]
| ESectL Expr Ident
| ESectR Ident Expr
| EIf Expr Expr Expr
| ESign Expr EType
| ENegApp Expr
| EUpdate Expr [EField]
| ESelect [Ident]
-- only in patterns
| EAt Ident EPat
| EViewPat Expr EPat
| ELazy Bool EPat -- True indicates ~p, False indicates !p
-- only in types
| EForall [IdKind] EType
-- only while type checking
| EUVar Int
-- only after type checking
| ECon Con
--DEBUG deriving (Show)
data EField
= EField [Ident] Expr -- a.b = e
| EFieldPun [Ident] -- a.b
| EFieldWild -- ..
--DEBUG deriving (Show)
unEField :: EField -> ([Ident], Expr)
unEField (EField is e) = (is, e)
unEField _ = impossible
type FunDep = ([Ident], [Ident])
eLam :: [EPat] -> Expr -> Expr
eLam ps e = ELam $ eEqns ps e
eEqns :: [EPat] -> Expr -> [Eqn]
eEqns ps e = [eEqn ps e]
eEqn :: [EPat] -> Expr -> Eqn
eEqn ps e = Eqn ps (EAlts [([], e)] [])
type FieldName = Ident
data Con
= ConData ConTyInfo Ident [FieldName]
| ConNew Ident [FieldName]
--DEBUG deriving(Show)
data Listish
= LList [Expr]
| LCompr Expr [EStmt]
| LFrom Expr
| LFromTo Expr Expr
| LFromThen Expr Expr
| LFromThenTo Expr Expr Expr
--DEBUG deriving(Show)
conIdent :: HasCallStack =>
Con -> Ident
conIdent (ConData _ i _) = i
conIdent (ConNew i _) = i
conArity :: Con -> Int
conArity (ConData cs i _) = fromMaybe (error "conArity") $ lookup i cs
conArity (ConNew _ _) = 1
conFields :: Con -> [FieldName]
conFields (ConData _ _ fs) = fs
conFields (ConNew _ fs) = fs
instance Eq Con where
(==) (ConData _ i _) (ConData _ j _) = i == j
(==) (ConNew i _) (ConNew j _) = i == j
(==) _ _ = False
data Lit
= LInt Int
| LInteger Integer
| LDouble Double
| LRat Rational
| LChar Char
| LStr String
| LUStr String -- UTF-8 encoded string
| LPrim String
| LForImp String CType
| LTick String
--DEBUG deriving (Show)
deriving (Eq)
-- A type of a C FFI function
newtype CType = CType EType
instance Eq CType where
_ == _ = True -- Just ignore the CType
type ECaseArm = (EPat, EAlts)
data EStmt = SBind EPat Expr | SThen Expr | SLet [EBind]
--DEBUG deriving (Show)
data EBind = BFcn Ident [Eqn] | BPat EPat Expr | BSign Ident EType
--DEBUG deriving (Show)
-- A single equation for a function
data Eqn = Eqn [EPat] EAlts
--DEBUG deriving (Show)
data EAlts = EAlts [EAlt] [EBind]
--DEBUG deriving (Show)
type EAlt = ([EStmt], Expr)
type ConTyInfo = [(Ident, Int)] -- All constructors with their arities
type EPat = Expr
isPConApp :: EPat -> Bool
isPConApp (EVar i) = isConIdent i
isPConApp (EApp f _) = isPConApp f
isPConApp (EAt _ p) = isPConApp p
isPConApp _ = True
-- Variables bound in a pattern.
-- Could use difference lists, but it seems a little slower.
patVars :: HasCallStack => EPat -> [Ident]
patVars apat =
case apat of
EVar i -> add i []
EApp p1 p2 -> patVars p1 ++ patVars p2
EOper p1 ips -> patVars p1 ++ concatMap (\ (i, p2) -> i `add` patVars p2) ips
ELit _ _ -> []
ETuple ps -> concatMap patVars ps
EListish (LList ps) -> concatMap patVars ps
ESign p _ -> patVars p
EAt i p -> i `add` patVars p
EViewPat _ p -> patVars p
ELazy _ p -> patVars p
ECon _ -> []
EUpdate _ fs -> concatMap field fs
ENegApp _ -> []
_ -> error $ "patVars " ++ showExpr apat
where add i is | isConIdent i || isDummyIdent i = is
| otherwise = i : is
field (EField _ p) = patVars p
field (EFieldPun is) = [last is]
field EFieldWild = impossible
type LHS = (Ident, [IdKind])
data Constr = Constr
[IdKind] [EConstraint] -- existentials: forall vs . ctx =>
Ident -- constructor name
(Either [SType] [ConstrField]) -- types or named fields
--DEBUG deriving(Show)
type ConstrField = (Ident, SType) -- record label and type
type SType = (Bool, EType) -- the Bool indicates strict
-- Expr restricted to
-- * after desugaring: EApp and EVar
-- * before desugaring: EApp, EVar, ETuple, EList
type EType = Expr
type EConstraint = EType
data IdKind = IdKind Ident EKind
--DEBUG deriving (Show)
instance Show IdKind where
show (IdKind i k) = "(" ++ show i ++ "::" ++ show k ++ ")"
idKindIdent :: IdKind -> Ident
idKindIdent (IdKind i _) = i
type EKind = EType
type ESort = EType
sKind :: ESort
sKind = EVar (Ident noSLoc "Primitives.Kind")
kType :: EKind
kType = EVar (Ident noSLoc "Primitives.Type")
kConstraint :: EKind
kConstraint = EVar (Ident noSLoc "Primitives.Constraint")
tupleConstr :: SLoc -> Int -> Ident
tupleConstr loc n = mkIdentSLoc loc (replicate (n - 1) ',')
-- Check if it is a suple constructor
getTupleConstr :: Ident -> Maybe Int
getTupleConstr i =
case unIdent i of
',':xs -> Just (length xs + 2) -- "," is 2-tuple
_ -> Nothing
-- Create a tuple selector, component i (0 based) of n
mkTupleSel :: Int -> Int -> Expr
mkTupleSel i n = eLam [ETuple [ EVar $ if k == i then x else dummyIdent | k <- [0 .. n - 1] ]] (EVar x)
where x = mkIdent "$x"
eApps :: Expr -> [Expr] -> Expr
eApps = foldl EApp
lhsToType :: LHS -> EType
lhsToType (i, iks) = eApps (EVar i) $ map (EVar . idKindIdent) iks
---------------------------------
-- Get the location of a syntactic element
class HasLoc a where
getSLoc :: a -> SLoc
instance HasLoc Ident where
getSLoc (Ident l _) = l
-- Approximate location; only identifiers and literals carry a location
instance HasLoc Expr where
getSLoc (EVar i) = getSLoc i
getSLoc (EApp e _) = getSLoc e
getSLoc (EOper e _) = getSLoc e
getSLoc (ELam qs) = getSLoc qs
getSLoc (ELit l _) = l
getSLoc (ECase e _) = getSLoc e
getSLoc (ELet bs _) = getSLoc bs
getSLoc (ETuple es) = getSLoc es
getSLoc (EListish l) = getSLoc l
getSLoc (EDo (Just i) _) = getSLoc i
getSLoc (EDo _ ss) = getSLoc ss
getSLoc (ESectL e _) = getSLoc e
getSLoc (ESectR i _) = getSLoc i
getSLoc (EIf e _ _) = getSLoc e
getSLoc (ESign e _) = getSLoc e
getSLoc (ENegApp e) = getSLoc e
getSLoc (EUpdate e _) = getSLoc e
getSLoc (ESelect is) = getSLoc (head is)
getSLoc (EAt i _) = getSLoc i
getSLoc (EViewPat e _) = getSLoc e
getSLoc (ELazy _ e) = getSLoc e
getSLoc (EUVar _) = error "getSLoc EUVar"
getSLoc (ECon c) = getSLoc c
getSLoc (EForall [] e) = getSLoc e
getSLoc (EForall iks _) = getSLoc iks
instance forall a . HasLoc a => HasLoc [a] where
getSLoc [] = noSLoc -- XXX shouldn't happen
getSLoc (a:_) = getSLoc a
instance HasLoc IdKind where
getSLoc (IdKind i _) = getSLoc i
instance HasLoc Con where
getSLoc (ConData _ i _) = getSLoc i
getSLoc (ConNew i _) = getSLoc i
instance HasLoc Listish where
getSLoc (LList es) = getSLoc es
getSLoc (LCompr e _) = getSLoc e
getSLoc (LFrom e) = getSLoc e
getSLoc (LFromTo e _) = getSLoc e
getSLoc (LFromThen e _) = getSLoc e
getSLoc (LFromThenTo e _ _) = getSLoc e
instance HasLoc EStmt where
getSLoc (SBind p _) = getSLoc p
getSLoc (SThen e) = getSLoc e
getSLoc (SLet bs) = getSLoc bs
instance HasLoc EBind where
getSLoc (BFcn i _) = getSLoc i
getSLoc (BPat p _) = getSLoc p
getSLoc (BSign i _) = getSLoc i
instance HasLoc Eqn where
getSLoc (Eqn [] a) = getSLoc a
getSLoc (Eqn (p:_) _) = getSLoc p
instance HasLoc EAlts where
getSLoc (EAlts as _) = getSLoc as
instance HasLoc EAlt where
getSLoc ([], e) = getSLoc e
getSLoc (ss, _) = getSLoc ss
---------------------------------
data Assoc = AssocLeft | AssocRight | AssocNone
--DEBUG deriving (Show)
deriving (Eq)
type Fixity = (Assoc, Int)
---------------------------------
-- Enough to handle subsitution in types
subst :: [(Ident, Expr)] -> Expr -> Expr
subst [] = id
subst s =
let
sub ae =
case ae of
EVar i -> fromMaybe ae $ lookup i s
EApp f a -> EApp (sub f) (sub a)
ESign e t -> ESign (sub e) t
EUVar _ -> ae
EForall iks t -> EForall iks $ subst [ x | x@(i, _) <- s, not (elem i is) ] t
where is = map idKindIdent iks
ELit _ _ -> ae
_ -> error "subst unimplemented"
in sub
---------------------------------
-- XXX needs more?
eqEType :: EType -> EType -> Bool
eqEType = eqExpr
-- Very partial implementation of Expr equality.
-- It is only used to compare instances, so this suffices.
eqExpr :: HasCallStack =>
Expr -> Expr -> Bool
eqExpr (EVar i) (EVar i') = i == i'
eqExpr (ELit _ l) (ELit _ l') = l == l'
eqExpr (EApp f a) (EApp f' a') = eqExpr f f' && eqExpr a a'
eqExpr (EUVar r) (EUVar r') = r == r'
eqExpr _ _ = False -- XXX good enough for instances
--eqExpr e1 e2 = error $ "eqExpr: unimplemented " ++ showExpr e1 ++ " == " ++ showExpr e2
---------------------------------
type DList a = [a] -> [a]
composeMap :: forall a b . (a -> DList b) -> [a] -> DList b
composeMap _ [] = id
composeMap f (x:xs) = f x . composeMap f xs
allVarsBind :: EBind -> [Ident]
allVarsBind b = allVarsBind' b []
allVarsBind' :: EBind -> DList Ident
allVarsBind' abind =
case abind of
BFcn i eqns -> (i:) . composeMap allVarsEqn eqns
BPat p e -> allVarsPat p . allVarsExpr' e
BSign i _ -> (i:)
allVarsEqns :: [Eqn] -> [Ident]
allVarsEqns eqns = composeMap allVarsEqn eqns []
allVarsEqn :: Eqn -> DList Ident
allVarsEqn eqn =
case eqn of
Eqn ps alts -> composeMap allVarsPat ps . allVarsAlts alts
allVarsAlts :: EAlts -> DList Ident
allVarsAlts (EAlts alts bs) = composeMap allVarsAlt alts . composeMap allVarsBind' bs
allVarsAlt :: EAlt -> DList Ident
allVarsAlt (ss, e) = composeMap allVarsStmt ss . allVarsExpr' e
allVarsPat :: EPat -> DList Ident
allVarsPat = allVarsExpr'
allVarsExpr :: Expr -> [Ident]
allVarsExpr e = allVarsExpr' e []
allVarsExpr' :: Expr -> DList Ident
allVarsExpr' aexpr =
case aexpr of
EVar i -> (i:)
EApp e1 e2 -> allVarsExpr' e1 . allVarsExpr' e2
EOper e1 ies -> allVarsExpr' e1 . composeMap (\ (i,e2) -> (i :) . allVarsExpr' e2) ies
ELam qs -> composeMap allVarsEqn qs
ELit _ _ -> id
ECase e as -> allVarsExpr' e . composeMap allVarsCaseArm as
ELet bs e -> composeMap allVarsBind' bs . allVarsExpr' e
ETuple es -> composeMap allVarsExpr' es
EListish (LList es) -> composeMap allVarsExpr' es
EDo mi ss -> maybe id (:) mi . composeMap allVarsStmt ss
ESectL e i -> (i :) . allVarsExpr' e
ESectR i e -> (i :) . allVarsExpr' e
EIf e1 e2 e3 -> allVarsExpr' e1 . allVarsExpr' e2 . allVarsExpr' e3
EListish l -> allVarsListish l
ESign e _ -> allVarsExpr' e
ENegApp e -> allVarsExpr' e
EUpdate e ies -> allVarsExpr' e . composeMap field ies
ESelect _ -> id
EAt i e -> (i :) . allVarsExpr' e
EViewPat e p -> allVarsExpr' e . allVarsExpr' p
ELazy _ p -> allVarsExpr' p
EUVar _ -> id
ECon c -> (conIdent c :)
EForall iks e -> (map (\ (IdKind i _) -> i) iks ++) . allVarsExpr' e
where field (EField _ e) = allVarsExpr' e
field (EFieldPun is) = (last is :)
field EFieldWild = impossible
allVarsListish :: Listish -> DList Ident
allVarsListish (LList es) = composeMap allVarsExpr' es
allVarsListish (LCompr e ss) = allVarsExpr' e . composeMap allVarsStmt ss
allVarsListish (LFrom e) = allVarsExpr' e
allVarsListish (LFromTo e1 e2) = allVarsExpr' e1 . allVarsExpr' e2
allVarsListish (LFromThen e1 e2) = allVarsExpr' e1 . allVarsExpr' e2
allVarsListish (LFromThenTo e1 e2 e3) = allVarsExpr' e1 . allVarsExpr' e2 . allVarsExpr' e3
allVarsCaseArm :: ECaseArm -> DList Ident
allVarsCaseArm (p, alts) = allVarsPat p . allVarsAlts alts
allVarsStmt :: EStmt -> DList Ident
allVarsStmt astmt =
case astmt of
SBind p e -> allVarsPat p . allVarsExpr' e
SThen e -> allVarsExpr' e
SLet bs -> composeMap allVarsBind' bs
-----------------------------
setSLocExpr :: SLoc -> Expr -> Expr
setSLocExpr l (EVar i) = EVar (setSLocIdent l i)
setSLocExpr l (ECon c) = ECon (setSLocCon l c)
setSLocExpr l (ELit _ k) = ELit l k
setSLocExpr _ _ = error "setSLocExpr" -- what other cases do we need?
setSLocCon :: SLoc -> Con -> Con
setSLocCon l (ConData ti i fs) = ConData ti (setSLocIdent l i) fs
setSLocCon l (ConNew i fs) = ConNew (setSLocIdent l i) fs
errorMessage :: forall a .
HasCallStack =>
SLoc -> String -> a
errorMessage loc msg = error $ showSLoc loc ++ ": " ++ msg
----------------
instance Show EModule where
show (EModule nm _ ds) = "module " ++ showIdent nm ++ "(...) where\n" ++ showEDefs ds
instance Show Expr where
show = showExpr
instance Show Eqn where
show eqn = render $ ppEqns (text "_") (text "=") [eqn]
instance Show EDef where
show d = showEDefs [d]
showExpr :: Expr -> String
showExpr = render . ppExpr
showEDefs :: [EDef] -> String
showEDefs = render . ppEDefs
showEBind :: EBind -> String
showEBind = render . ppEBind
showEBinds :: [EBind] -> String
showEBinds = render . vcat . map ppEBind
showEType :: EType -> String
showEType = render . ppEType
ppImportItem :: ImportItem -> Doc
ppImportItem ae =
case ae of
ImpTypeCon i -> ppIdent i <> text "(..)"
ImpType i -> ppIdent i
ImpValue i -> ppIdent i
ppEDef :: EDef -> Doc
ppEDef def =
case def of
Data lhs [] ds -> text "data" <+> ppLHS lhs <+> ppDeriving ds
Data lhs cs ds -> text "data" <+> ppLHS lhs <+> text "=" <+> hsep (punctuate (text " |") (map ppConstr cs)) <+> ppDeriving ds
Newtype lhs c ds -> text "newtype" <+> ppLHS lhs <+> text "=" <+> ppConstr c <+> ppDeriving ds
Type lhs t -> text "type" <+> ppLHS lhs <+> text "=" <+> ppEType t
Fcn i eqns -> ppEqns (ppIdent i) (text "=") eqns
Sign is t -> hsep (punctuate (text ",") (map ppIdent is)) <+> text "::" <+> ppEType t
KindSign i t -> text "type" <+> ppIdent i <+> text "::" <+> ppEKind t
Import (ImportSpec q m mm mis) -> text "import" <+> (if q then text "qualified" else empty) <+> ppIdent m <> text (maybe "" ((" as " ++) . unIdent) mm) <>
case mis of
Nothing -> empty
Just (h, is) -> text (if h then " hiding" else "") <> parens (hsep $ punctuate (text ",") (map ppImportItem is))
ForImp ie i t -> text "foreign import ccall" <+> maybe empty (text . show) ie <+> ppIdent i <+> text "::" <+> ppEType t
Infix (a, p) is -> text ("infix" ++ f a) <+> text (show p) <+> hsep (punctuate (text ", ") (map ppIdent is))
where f AssocLeft = "l"; f AssocRight = "r"; f AssocNone = ""
Class sup lhs fds bs -> ppWhere (text "class" <+> ppCtx sup <+> ppLHS lhs <+> ppFunDeps fds) bs
Instance ct bs -> ppWhere (text "instance" <+> ppEType ct) bs
Default ts -> text "default" <+> parens (hsep (punctuate (text ", ") (map ppEType ts)))
ppDeriving :: Deriving -> Doc
ppDeriving [] = empty
ppDeriving ds = text "deriving" <+> parens (hsep $ punctuate (text ",") (map ppExpr ds))
ppCtx :: [EConstraint] -> Doc
ppCtx [] = empty
ppCtx ts = ppEType (ETuple ts) <+> text "=>"
ppFunDeps :: [FunDep] -> Doc
ppFunDeps [] = empty
ppFunDeps fds =
text "|" <+> hsep (punctuate (text ",") (map (\ (is, os) -> hsep (map ppIdent is) <+> text "-" <+> hsep (map ppIdent os)) fds))
ppEqns :: Doc -> Doc -> [Eqn] -> Doc
ppEqns name sepr = vcat . map (\ (Eqn ps alts) -> sep [name <+> hsep (map ppEPat ps), ppAlts sepr alts])
ppConstr :: Constr -> Doc
ppConstr (Constr iks ct c cs) = ppForall iks <+> ppCtx ct <+> ppIdent c <+> ppCs cs
where ppCs (Left ts) = hsep (map ppSType ts)
ppCs (Right fs) = braces (hsep $ map f fs)
where f (i, t) = ppIdent i <+> text "::" <+> ppSType t <> text ","
ppSType :: SType -> Doc
ppSType (False, t) = ppEType t
ppSType (True, t) = text "!" <> ppEType t
ppLHS :: LHS -> Doc
ppLHS (f, vs) = hsep (ppIdent f : map ppIdKind vs)
ppIdKind :: IdKind -> Doc
ppIdKind (IdKind i k) = parens $ ppIdent i <> text "::" <> ppEKind k
ppEDefs :: [EDef] -> Doc
ppEDefs ds = vcat (map pp ds)
where pp d@(Sign _ _) = ppEDef d
pp d@(Import _) = ppEDef d
pp d = ppEDef d $+$ text ""
ppAlts :: Doc -> EAlts -> Doc
ppAlts asep (EAlts alts bs) = ppWhere (ppAltsL asep alts) bs
ppWhere :: Doc -> [EBind] -> Doc
ppWhere d [] = d
ppWhere d bs = (d <+> text "where") $+$ nest 2 (vcat (map ppEBind bs))
ppAltsL :: Doc -> [EAlt] -> Doc
ppAltsL asep [([], e)] = text "" <+> asep <+> ppExpr e
ppAltsL asep alts = vcat (map (ppAlt asep) alts)
ppAlt :: Doc -> EAlt -> Doc
ppAlt asep (ss, e) = text " |" <+> hsep (punctuate (text ",") (map ppEStmt ss)) <+> asep <+> ppExpr e
ppExpr :: Expr -> Doc
ppExpr ae =
case ae of
EVar i | isOperChar cop -> parens (text op)
| otherwise -> text s
where op = unIdent (unQualIdent i)
s = if "inst$" `isPrefixOf` op then unIdent i else op
cop = head op
EApp _ _ -> ppApp [] ae
EOper e ies -> ppExpr (foldl (\ e1 (i, e2) -> EApp (EApp (EVar i) e1) e2) e ies)
ELam qs -> parens $ text "\\" <> ppEqns empty (text "->") qs
ELit _ i -> text (showLit i)
ECase e as -> text "case" <+> ppExpr e <+> text "of" $$ nest 2 (vcat (map ppCaseArm as))
ELet bs e -> text "let" $$ nest 2 (vcat (map ppEBind bs)) $$ text "in" <+> ppExpr e
ETuple es -> parens $ hsep $ punctuate (text ",") (map ppExpr es)
EDo mn ss -> maybe (text "do") (\ n -> ppIdent n <> text ".do") mn $$ nest 2 (vcat (map ppEStmt ss))
ESectL e i -> parens $ ppExpr e <+> ppIdent i
ESectR i e -> parens $ ppIdent i <+> ppExpr e
EIf e1 e2 e3 -> parens $ sep [text "if" <+> ppExpr e1, text "then" <+> ppExpr e2, text "else" <+> ppExpr e3]
EListish l -> ppListish l
ESign e t -> parens $ ppExpr e <+> text "::" <+> ppEType t
ENegApp e -> text "-" <+> ppExpr e
EUpdate ee ies -> ppExpr ee <> text "{" <+> hsep (punctuate (text ",") (map ppField ies)) <+> text "}"
ESelect is -> parens $ hcat $ map (\ i -> text "." <> ppIdent i) is
EAt i e -> ppIdent i <> text "@" <> ppExpr e
EViewPat e p -> parens $ ppExpr e <+> text "->" <+> ppExpr p
ELazy True p -> text "~" <> ppExpr p
ELazy False p -> text "!" <> ppExpr p
EUVar i -> text ("_a" ++ show i)
ECon c -> ppCon c
EForall iks e -> ppForall iks <+> ppEType e
-- where
ppApp :: [Expr] -> Expr -> Doc
ppApp as (EApp f a) = ppApp (a:as) f
ppApp as (EVar i) | isOperChar cop, [a, b] <- as = parens $ ppExpr a <+> text op <+> ppExpr b
| isOperChar cop, [a] <- as = parens $ ppExpr a <+> text op
| cop == ',' = ppExpr (ETuple as)
| op == "[]", length as == 1 = ppExpr (EListish (LList as))
where op = unIdent (unQualIdent i)
cop = head op
ppApp as f = parens $ hsep (map ppExpr (f:as))
ppField :: EField -> Doc
ppField (EField is e) = hcat (punctuate (text ".") (map ppIdent is)) <+> text "=" <+> ppExpr e
ppField (EFieldPun is) = hcat (punctuate (text ".") (map ppIdent is))
ppField EFieldWild = text ".."
ppForall :: [IdKind] -> Doc
--ppForall [] = empty
ppForall iks = text "forall" <+> hsep (map ppIdKind iks) <+> text "."
ppListish :: Listish -> Doc
ppListish (LList es) = ppList ppExpr es
ppListish (LCompr e ss) = brackets $ ppExpr e <+> text "|" <+> hsep (punctuate (text ",") (map ppEStmt ss))
ppListish (LFrom e1) = brackets $ ppExpr e1 <> text ".."
ppListish (LFromTo e1 e2) = brackets $ ppExpr e1 <> text ".." <> ppExpr e2
ppListish (LFromThen e1 e2) = brackets $ ppExpr e1 <> text "," <> ppExpr e2 <> text ".."
ppListish (LFromThenTo e1 e2 e3) = brackets $ ppExpr e1 <> text "," <> ppExpr e2 <> text ".." <> ppExpr e3
ppCon :: Con -> Doc
ppCon (ConData _ s _) = ppIdent s
ppCon (ConNew s _) = ppIdent s
-- Literals are tagged the way they appear in the combinator file:
-- # Int
-- % Double
-- ' Char (not in file)
-- " String
-- ^ FFI function
-- primitive
showLit :: Lit -> String
showLit l =
case l of
LInt i -> '#' : show i
LInteger i -> '#' : '#' : show i
LDouble d -> '&' : show d
LRat r -> '%' : show r
LChar c -> show c
LStr s -> show s
LUStr s -> show s
LPrim s -> s
LForImp s _-> '^' : last (words s) -- XXX needs improvement
LTick s -> '!' : s
ppEStmt :: EStmt -> Doc
ppEStmt as =
case as of
SBind p e -> ppEPat p <+> text "<-" <+> ppExpr e
SThen e -> ppExpr e
SLet bs -> text "let" $$ nest 2 (vcat (map ppEBind bs))
ppEBind :: EBind -> Doc
ppEBind ab =
case ab of
BFcn i eqns -> ppEDef (Fcn i eqns)
BPat p e -> ppEPat p <+> text "=" <+> ppExpr e
BSign i t -> ppIdent i <+> text "::" <+> ppEType t
ppCaseArm :: ECaseArm -> Doc
ppCaseArm arm =
case arm of
(p, alts) -> ppEPat p <> ppAlts (text "->") alts
ppEPat :: EPat -> Doc
ppEPat = ppExpr
ppEType :: EType -> Doc
ppEType = ppExpr
ppEKind :: EKind -> Doc
ppEKind = ppEType
ppList :: forall a . (a -> Doc) -> [a] -> Doc
ppList pp xs = brackets $ hsep $ punctuate (text ",") (map pp xs)
getBindVars :: EBind -> [Ident]
getBindVars abind =
case abind of
BFcn i _ -> [i]
BPat p _ -> patVars p
BSign _ _ -> []
getBindsVars :: [EBind] -> [Ident]
getBindsVars = concatMap getBindVars
eForall :: [IdKind] -> EType -> EType
eForall [] t = t
eForall vs t = EForall vs t
eDummy :: Expr
eDummy = EVar dummyIdent
impossible :: forall a .
HasCallStack =>
a
impossible = error "impossible"
impossibleShow :: forall a b .
HasCallStack =>
(Show a, HasLoc a) => a -> b
impossibleShow a = error $ "impossible: " ++ show (getSLoc a) ++ " " ++ show a
-----------
-- Probably belongs somewhere else
getArrow :: EType -> Maybe (EType, EType)
getArrow (EApp (EApp (EVar n) a) b) =
if isIdent "->" n || isIdent "Primitives.->" n then Just (a, b) else Nothing
getArrow _ = Nothing
getArrows :: EType -> ([EType], EType)
getArrows at =
case getArrow at of
Nothing -> ([], at)
Just (t, r) -> first (t:) (getArrows r)