{-# LANGUAGE CPP #-}
module Generators.GenTypedFlatCurry (genTypedFlatCurry) where
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>), (<*>))
#endif
import Control.Monad ((<=<))
import Control.Monad.Extra (concatMapM)
import qualified Control.Monad.State as S ( State, evalState, get, gets
, modify, put )
import Data.Function (on)
import Data.List (nub, sortBy)
import Data.Maybe (fromMaybe)
import qualified Data.Map as Map (Map, empty, insert, lookup)
import qualified Data.Set as Set (Set, empty, insert, member)
import Curry.Base.Ident
import Curry.Base.SpanInfo
import Curry.FlatCurry.Typed.Goodies (typeName)
import Curry.FlatCurry.Typed.Type
import qualified Curry.Syntax as CS
import Base.CurryTypes (toType)
import Base.Messages (internalError)
import Base.NestEnv ( NestEnv, emptyEnv, bindNestEnv, lookupNestEnv
, nestEnv, unnestEnv )
import Base.TypeExpansion
import Base.Types
import CompilerEnv
import Env.OpPrec (mkPrec)
import Env.TypeConstructor (TCEnv)
import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
import qualified IL
import Transformations (transType)
genTypedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module
-> TProg
genTypedFlatCurry env mdl il = patchPrelude $ run env mdl (trModule il)
patchPrelude :: TProg -> TProg
patchPrelude p@(TProg n _ ts fs os)
| n == prelude = TProg n [] ts' fs os
| otherwise = p
where ts' = sortBy (compare `on` typeName) pts
pts = primTypes ++ ts
primTypes :: [TypeDecl]
primTypes =
[ Type arrow Public [0, 1] []
, Type unit Public [] [(Cons unit 0 Public [])]
, Type nil Public [0] [ Cons nil 0 Public []
, Cons cons 2 Public [TVar 0, TCons nil [TVar 0]]
]
] ++ map mkTupleType [2 .. maxTupleArity]
where arrow = mkPreludeQName "(->)"
unit = mkPreludeQName "()"
nil = mkPreludeQName "[]"
cons = mkPreludeQName ":"
mkTupleType :: Int -> TypeDecl
mkTupleType arity = Type tuple Public [0 .. arity - 1]
[Cons tuple arity Public (map TVar [0 .. arity - 1])]
where tuple = mkPreludeQName $ '(' : replicate (arity - 1) ',' ++ ")"
mkPreludeQName :: String -> QName
mkPreludeQName n = (prelude, n)
prelude :: String
prelude = "Prelude"
maxTupleArity :: Int
maxTupleArity = 15
type FlatState a = S.State FlatEnv a
data FlatEnv = FlatEnv
{ modIdent :: ModuleIdent
, tyExports :: Set.Set Ident
, valExports :: Set.Set Ident
, tcEnv :: TCEnv
, tyEnv :: ValueEnv
, fixities :: [CS.IDecl]
, typeSynonyms :: [CS.Decl Type]
, imports :: [ModuleIdent]
, nextVar :: Int
, varMap :: NestEnv VarIndex
}
run :: CompilerEnv -> CS.Module Type -> FlatState a -> a
run env (CS.Module _ _ mid es is ds) act = S.evalState act env0
where
es' = case es of Just (CS.Exporting _ e) -> e
_ -> []
env0 = FlatEnv
{ modIdent = mid
, tyExports = foldr (buildTypeExports mid) Set.empty es'
, valExports = foldr (buildValueExports mid) Set.empty es'
, imports = nub [ m | CS.ImportDecl _ m _ _ _ <- is ]
, tyEnv = valueEnv env
, tcEnv = tyConsEnv env
, fixities = [ CS.IInfixDecl (spanInfo2Pos p) fix (mkPrec mPrec) (qualifyWith mid o)
| CS.InfixDecl p fix mPrec os <- ds, o <- os
]
, typeSynonyms = [ d | d@CS.TypeDecl{} <- ds ]
, nextVar = 0
, varMap = emptyEnv
}
buildTypeExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident
buildTypeExports mid (CS.ExportTypeWith _ tc _)
| isLocalIdent mid tc = Set.insert (unqualify tc)
buildTypeExports _ _ = id
buildValueExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident
buildValueExports mid (CS.Export _ q)
| isLocalIdent mid q = Set.insert (unqualify q)
buildValueExports mid (CS.ExportTypeWith _ tc cs)
| isLocalIdent mid tc = flip (foldr Set.insert) cs
buildValueExports _ _ = id
getModuleIdent :: FlatState ModuleIdent
getModuleIdent = S.gets modIdent
getArity :: QualIdent -> FlatState Int
getArity qid = S.gets tyEnv >>= \ env -> return $ case qualLookupValue qid env of
[DataConstructor _ a _ _] -> a
[NewtypeConstructor _ _ _] -> 1
[Value _ _ a _] -> a
[Label _ _ _] -> 1
_ -> internalError
("GenTypedFlatCurry.getArity: " ++ qualName qid)
getFixities :: FlatState [CS.IDecl]
getFixities = S.gets fixities
getTypeSynonyms :: FlatState [CS.Decl Type]
getTypeSynonyms = S.gets typeSynonyms
getImports :: [ModuleIdent] -> FlatState [String]
getImports imps = (nub . map moduleName . (imps ++)) <$> S.gets imports
withFreshEnv :: FlatState a -> FlatState a
withFreshEnv act = S.modify (\ s -> s { nextVar = 0, varMap = emptyEnv }) >> act
inNestedEnv :: FlatState a -> FlatState a
inNestedEnv act = do
S.modify $ \ s -> s { varMap = nestEnv $ varMap s }
res <- act
S.modify $ \ s -> s { varMap = unnestEnv $ varMap s }
return res
newVar :: IL.Type -> Ident -> FlatState (VarIndex, TypeExpr)
newVar ty i = do
idx <- (+1) <$> S.gets nextVar
S.modify $ \ s -> s { nextVar = idx, varMap = bindNestEnv i idx (varMap s) }
ty' <- trType ty
return (idx, ty')
getVarIndex :: Ident -> FlatState VarIndex
getVarIndex i = S.gets varMap >>= \ varEnv -> case lookupNestEnv i varEnv of
[v] -> return v
_ -> internalError $ "GenFlatCurry.getVarIndex: " ++ escName i
trIOpDecl :: CS.IDecl -> FlatState [OpDecl]
trIOpDecl (CS.IInfixDecl _ fix prec op)
= (\op' -> [Op op' (cvFixity fix) prec]) <$> trQualIdent op
trIOpDecl _ = return []
trModule :: IL.Module -> FlatState TProg
trModule (IL.Module mid is ds) = do
is' <- getImports is
sns <- getTypeSynonyms >>= concatMapM trTypeSynonym
tds <- concatMapM trTypeDecl ds
fds <- concatMapM (return . map runNormalization <=< trTFuncDecl) ds
ops <- getFixities >>= concatMapM trIOpDecl
return $ TProg (moduleName mid) is' (sns ++ tds) fds ops
trTypeSynonym :: CS.Decl a -> FlatState [TypeDecl]
trTypeSynonym (CS.TypeDecl _ t tvs ty) = do
m <- getModuleIdent
qid <- flip qualifyWith t <$> getModuleIdent
t' <- trQualIdent qid
vis <- getTypeVisibility qid
tEnv <- S.gets tcEnv
ty' <- trType (transType $ expandType m tEnv $ toType tvs ty)
return [TypeSyn t' vis [0 .. length tvs - 1] ty']
trTypeSynonym _ = return []
trTypeDecl :: IL.Decl -> FlatState [TypeDecl]
trTypeDecl (IL.DataDecl qid a []) = do
q' <- trQualIdent qid
vis <- getTypeVisibility qid
c <- trQualIdent $ qualify (mkIdent $ "_Constr#" ++ idName (unqualify qid))
let tvs = [0 .. a - 1]
return [Type q' vis tvs [Cons c 1 Private [TCons q' $ map TVar tvs]]]
trTypeDecl (IL.DataDecl qid a cs) = do
q' <- trQualIdent qid
vis <- getTypeVisibility qid
cs' <- mapM trConstrDecl cs
return [Type q' vis [0 .. a - 1] cs']
trTypeDecl (IL.ExternalDataDecl qid a) = do
q' <- trQualIdent qid
vis <- getTypeVisibility qid
return [Type q' vis [0 .. a - 1] []]
trTypeDecl _ = return []
trConstrDecl :: IL.ConstrDecl -> FlatState ConsDecl
trConstrDecl (IL.ConstrDecl qid tys) = flip Cons (length tys)
<$> trQualIdent qid
<*> getVisibility qid
<*> mapM trType tys
trType :: IL.Type -> FlatState TypeExpr
trType (IL.TypeConstructor t tys) = TCons <$> trQualIdent t <*> mapM trType tys
trType (IL.TypeVariable idx) = return $ TVar $ abs idx
trType (IL.TypeArrow ty1 ty2) = FuncType <$> trType ty1 <*> trType ty2
trType (IL.TypeForall idxs ty) = ForallType (map abs idxs) <$> trType ty
cvFixity :: CS.Infix -> Fixity
cvFixity CS.InfixL = InfixlOp
cvFixity CS.InfixR = InfixrOp
cvFixity CS.Infix = InfixOp
trTFuncDecl :: IL.Decl -> FlatState [TFuncDecl]
trTFuncDecl (IL.FunctionDecl f vs _ e) = do
f' <- trQualIdent f
a <- getArity f
vis <- getVisibility f
ty' <- trType ty
r' <- trTRule vs e
return [TFunc f' a vis ty' r']
where ty = foldr IL.TypeArrow (IL.typeOf e) $ map fst vs
trTFuncDecl (IL.ExternalDecl f ty) = do
f' <- trQualIdent f
a <- getArity f
vis <- getVisibility f
ty' <- trType ty
r' <- trTExternal ty f
return [TFunc f' a vis ty' r']
trTFuncDecl _ = return []
trTRule :: [(IL.Type, Ident)] -> IL.Expression
-> FlatState TRule
trTRule vs e = withFreshEnv $ TRule <$> mapM (uncurry newVar) vs
<*> trTExpr e
trTExternal :: IL.Type -> QualIdent -> FlatState TRule
trTExternal ty f = flip TExternal (qualName f) <$> trType ty
trTExpr :: IL.Expression -> FlatState TExpr
trTExpr (IL.Literal ty l) = TLit <$> trType ty <*> trLiteral l
trTExpr (IL.Variable ty v) = TVarE <$> trType ty <*> getVarIndex v
trTExpr (IL.Function ty f _) = genCall Fun ty f []
trTExpr (IL.Constructor ty c _) = genCall Con ty c []
trTExpr (IL.Apply e1 e2) = trApply e1 e2
trTExpr (IL.Case t e bs) = TCase (cvEval t) <$> trTExpr e
<*> mapM (inNestedEnv . trAlt) bs
trTExpr (IL.Or e1 e2) = TOr <$> trTExpr e1 <*> trTExpr e2
trTExpr (IL.Exist v ty e) = inNestedEnv $ do
v' <- newVar ty v
e' <- trTExpr e
return $ case e' of TFree vs e'' -> TFree (v' : vs) e''
_ -> TFree (v' : []) e'
trTExpr (IL.Let (IL.Binding v b) e) = inNestedEnv $ do
v' <- newVar (IL.typeOf b) v
b' <- trTExpr b
e' <- trTExpr e
return $ case e' of TLet bs e'' -> TLet ((v', b'):bs) e''
_ -> TLet ((v', b'):[]) e'
trTExpr (IL.Letrec bs e) = inNestedEnv $ do
let (vs, es) = unzip [ ((IL.typeOf b, v), b) | IL.Binding v b <- bs]
TLet <$> (zip <$> mapM (uncurry newVar) vs <*> mapM trTExpr es)
<*> trTExpr e
trTExpr (IL.Typed e _) = TTyped <$> trTExpr e <*> ty'
where ty' = trType $ IL.typeOf e
trLiteral :: IL.Literal -> FlatState Literal
trLiteral (IL.Char c) = return $ Charc c
trLiteral (IL.Int i) = return $ Intc i
trLiteral (IL.Float f) = return $ Floatc f
trApply :: IL.Expression -> IL.Expression -> FlatState TExpr
trApply e1 e2 = genFlatApplic e1 [e2]
where
genFlatApplic e es = case e of
IL.Apply ea eb -> genFlatApplic ea (eb:es)
IL.Function ty f _ -> genCall Fun ty f es
IL.Constructor ty c _ -> genCall Con ty c es
_ -> do
expr <- trTExpr e
genApply expr es
trAlt :: IL.Alt -> FlatState TBranchExpr
trAlt (IL.Alt p e) = TBranch <$> trPat p <*> trTExpr e
trPat :: IL.ConstrTerm -> FlatState TPattern
trPat (IL.LiteralPattern ty l) = TLPattern <$> trType ty <*> trLiteral l
trPat (IL.ConstructorPattern ty c vs) =
TPattern <$> trType ty <*> trQualIdent c <*> mapM (uncurry newVar) vs
trPat (IL.VariablePattern _ _) = internalError "GenTypedFlatCurry.trPat"
cvEval :: IL.Eval -> CaseType
cvEval IL.Rigid = Rigid
cvEval IL.Flex = Flex
data Call = Fun | Con
genCall :: Call -> IL.Type -> QualIdent -> [IL.Expression]
-> FlatState TExpr
genCall call ty f es = do
f' <- trQualIdent f
arity <- getArity f
case compare supplied arity of
LT -> genTComb ty f' es (part call (arity - supplied))
EQ -> genTComb ty f' es (full call)
GT -> do
let (es1, es2) = splitAt arity es
funccall <- genTComb ty f' es1 (full call)
genApply funccall es2
where
supplied = length es
full Fun = FuncCall
full Con = ConsCall
part Fun = FuncPartCall
part Con = ConsPartCall
genTComb :: IL.Type -> QName -> [IL.Expression] -> CombType -> FlatState TExpr
genTComb ty qid es ct = do
ty' <- trType ty
let ty'' = defunc ty' (length es)
TComb ty'' ct qid <$> mapM trTExpr es
where
defunc t 0 = t
defunc (FuncType _ t2) n = defunc t2 (n - 1)
defunc _ _ = internalError "GenTypedFlatCurry.genTComb.defunc"
genApply :: TExpr -> [IL.Expression] -> FlatState TExpr
genApply e es = do
ap <- trQualIdent qApplyId
es' <- mapM trTExpr es
return $ foldl (\e1 e2 -> let FuncType _ ty2 = typeOf e1
in TComb ty2 FuncCall ap [e1, e2])
e es'
runNormalization :: Normalize a => a -> a
runNormalization x = S.evalState (normalize x) (0, Map.empty)
type NormState a = S.State (Int, Map.Map Int Int) a
class Normalize a where
normalize :: a -> NormState a
instance Normalize Int where
normalize i = do
(n, m) <- S.get
case Map.lookup i m of
Nothing -> do
S.put (n + 1, Map.insert i n m)
return n
Just n' -> return n'
instance Normalize TypeExpr where
normalize (TVar i) = TVar <$> normalize i
normalize (TCons q tys) = TCons q <$> mapM normalize tys
normalize (FuncType ty1 ty2) = FuncType <$> normalize ty1 <*> normalize ty2
normalize (ForallType is ty) =
ForallType <$> mapM normalize is <*> normalize ty
instance Normalize b => Normalize (a, b) where
normalize (x, y) = (,) x <$> normalize y
instance Normalize TFuncDecl where
normalize (TFunc f a v ty r) = TFunc f a v <$> normalize ty <*> normalize r
instance Normalize TRule where
normalize (TRule vs e) = TRule <$> mapM normalize vs
<*> normalize e
normalize (TExternal ty s) = flip TExternal s <$> normalize ty
instance Normalize TExpr where
normalize (TVarE ty v) = flip TVarE v <$> normalize ty
normalize (TLit ty l) = flip TLit l <$> normalize ty
normalize (TComb ty ct f es) = flip TComb ct <$> normalize ty
<*> pure f
<*> mapM normalize es
normalize (TLet ds e) = TLet <$> mapM normalizeBinding ds
<*> normalize e
where normalizeBinding (v, b) = (,) <$> normalize v <*> normalize b
normalize (TOr a b) = TOr <$> normalize a
<*> normalize b
normalize (TCase ct e bs) = TCase ct <$> normalize e
<*> mapM normalize bs
normalize (TFree vs e) = TFree <$> mapM normalize vs
<*> normalize e
normalize (TTyped e ty') = TTyped <$> normalize e
<*> normalize ty'
instance Normalize TBranchExpr where
normalize (TBranch p e) = TBranch <$> normalize p <*> normalize e
instance Normalize TPattern where
normalize (TPattern ty c vs) = TPattern <$> normalize ty
<*> pure c
<*> mapM normalize vs
normalize (TLPattern ty l) = flip TLPattern l <$> normalize ty
trQualIdent :: QualIdent -> FlatState QName
trQualIdent qid = do
mid <- getModuleIdent
return $ (moduleName $ fromMaybe mid mid', idName i)
where
mid' | i `elem` [listId, consId, nilId, unitId] || isTupleId i
= Just preludeMIdent
| otherwise
= qidModule qid
i = qidIdent qid
getTypeVisibility :: QualIdent -> FlatState Visibility
getTypeVisibility i = S.gets $ \s ->
if Set.member (unqualify i) (tyExports s) then Public else Private
getVisibility :: QualIdent -> FlatState Visibility
getVisibility i = S.gets $ \s ->
if Set.member (unqualify i) (valExports s) then Public else Private