% $Id: ILTrans.lhs,v 1.86 2004/02/13 19:23:58 wlux Exp $
%
% Copyright (c) 1999-2003, Wolfgang Lux
% See LICENSE for the full license.
%
% Modified by Martin Engelke (men@informatik.uni-kiel.de)
%
\nwfilename{ILTrans.lhs}
\section{Translating Curry into the Intermediate Language}
After desugaring and lifting have been performed, the source code is
translated into the intermediate language. Besides translating from
source terms and expressions into intermediate language terms and
expressions this phase in particular has to implement the pattern
matching algorithm for equations and case expressions.
Because of name conflicts between the source and intermediate language
data structures, we can use only a qualified import for the
\texttt{IL} module.
\begin{verbatim}
> module ILTrans(ilTrans,ilTransIntf) where
> import Data.Maybe
> import Data.List
> import Base
> import qualified IL
> import Utils
> import Env
> import Set
> import Map
\end{verbatim}
\paragraph{Modules}
At the top-level, the compiler has to translate data type, newtype,
function, and external declarations. When translating a data type or
newtype declaration, we ignore the types in the declaration and lookup
the types of the constructors in the type environment instead because
these types are already fully expanded, i.e., they do not include any
alias types.
\begin{verbatim}
> ilTrans :: Bool -> ValueEnv -> TCEnv -> EvalEnv -> Module -> IL.Module
> ilTrans flat tyEnv tcEnv evEnv (Module m _ ds) =
> IL.Module m (imports m ds') ds'
> where ds' = concatMap (translGlobalDecl flat m tyEnv tcEnv evEnv) ds
> translGlobalDecl :: Bool -> ModuleIdent -> ValueEnv -> TCEnv -> EvalEnv
> -> Decl -> [IL.Decl]
> translGlobalDecl _ m tyEnv tcEnv _ (DataDecl _ tc tvs cs) =
> [translData m tyEnv tcEnv tc tvs cs]
> translGlobalDecl _ m tyEnv tcEnv _ (NewtypeDecl _ tc tvs nc) =
> [translNewtype m tyEnv tcEnv tc tvs nc]
> translGlobalDecl flat m tyEnv tcEnv evEnv (FunctionDecl pos f eqs) =
> [translFunction pos flat m tyEnv tcEnv evEnv f eqs]
> translGlobalDecl _ m tyEnv tcEnv _ (ExternalDecl _ cc ie f _) =
> [translExternal m tyEnv tcEnv f cc (fromJust ie)]
> translGlobalDecl _ _ _ _ _ _ = []
> translData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] -> [ConstrDecl]
> -> IL.Decl
> translData m tyEnv tcEnv tc tvs cs =
> IL.DataDecl (qualifyWith m tc) (length tvs)
> (map (translConstrDecl m tyEnv tcEnv) cs)
> translNewtype :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident]
> -> NewConstrDecl -> IL.Decl
> translNewtype m tyEnv tcEnv tc tvs (NewConstrDecl _ _ c _) =
> IL.NewtypeDecl (qualifyWith m tc) (length tvs)
> (IL.ConstrDecl c' (translType' m tyEnv tcEnv ty))
> -- (IL.ConstrDecl c' (translType ty))
> where c' = qualifyWith m c
> TypeArrow ty _ = constrType tyEnv c'
> translConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> ConstrDecl
> -> IL.ConstrDecl [IL.Type]
> translConstrDecl m tyEnv tcEnv d =
> IL.ConstrDecl c' (map (translType' m tyEnv tcEnv)
> (arrowArgs (constrType tyEnv c')))
> -- IL.ConstrDecl c' (map translType (arrowArgs (constrType tyEnv c')))
> where c' = qualifyWith m (constr d)
> constr (ConstrDecl _ _ c _) = c
> constr (ConOpDecl _ _ _ op _) = op
> translExternal :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> CallConv
> -> String -> IL.Decl
> translExternal m tyEnv tcEnv f cc ie =
> IL.ExternalDecl f' (callConv cc) ie
> (translType' m tyEnv tcEnv (varType tyEnv f'))
> -- IL.ExternalDecl f' (callConv cc) ie (translType (varType tyEnv f'))
> where f' = qualifyWith m f
> callConv CallConvPrimitive = IL.Primitive
> callConv CallConvCCall = IL.CCall
\end{verbatim}
\paragraph{Interfaces}
In order to generate code, the compiler also needs to know the tags
and arities of all imported data constructors. For that reason we
compile the data type declarations of all interfaces into the
intermediate language, too. In this case we do not lookup the
types in the environment because the types in the interfaces are
already fully expanded. Note that we do not translate data types
which are imported into the interface from some other module.
\begin{verbatim}
> ilTransIntf :: ValueEnv -> TCEnv -> Interface -> [IL.Decl]
> ilTransIntf tyEnv tcEnv (Interface m ds) =
> foldr (translIntfDecl m tyEnv tcEnv) [] ds
> translIntfDecl :: ModuleIdent -> ValueEnv -> TCEnv -> IDecl -> [IL.Decl]
> -> [IL.Decl]
> translIntfDecl m tyEnv tcEnv (IDataDecl _ tc tvs cs) ds
> | not (isQualified tc) =
> translIntfData m tyEnv tcEnv (unqualify tc) tvs cs : ds
> translIntfDecl _ _ _ _ ds = ds
> translIntfData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident]
> -> [Maybe ConstrDecl] -> IL.Decl
> translIntfData m tyEnv tcEnv tc tvs cs =
> IL.DataDecl (qualifyWith m tc) (length tvs)
> (map (maybe hiddenConstr
> (translIntfConstrDecl m tyEnv tcEnv tvs)) cs)
> where hiddenConstr = IL.ConstrDecl qAnonId []
> qAnonId = qualify anonId
> translIntfConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> [Ident]
> -> ConstrDecl -> IL.ConstrDecl [IL.Type]
> translIntfConstrDecl m tyEnv tcEnv tvs (ConstrDecl _ _ c tys) =
> IL.ConstrDecl (qualifyWith m c) (map (translType' m tyEnv tcEnv)
> (toQualTypes m tvs tys))
> -- IL.ConstrDecl (qualifyWith m c) (map translType (toQualTypes m tvs tys))
> translIntfConstrDecl m tyEnv tcEnv tvs (ConOpDecl _ _ ty1 op ty2) =
> IL.ConstrDecl (qualifyWith m op)
> (map (translType' m tyEnv tcEnv)
> (toQualTypes m tvs [ty1,ty2]))
> -- IL.ConstrDecl (qualifyWith m op)
> -- (map translType (toQualTypes m tvs [ty1,ty2]))
\end{verbatim}
\paragraph{Types}
The type representation in the intermediate language is the same as
the internal representation except that it does not support
constrained type variables and skolem types. The former are fixed and
the later are replaced by fresh type constructors.
Due to possible occurrence of record types, it is necessary to transform
them back into their corresponding type constructors.
\begin{verbatim}
> translType' :: ModuleIdent -> ValueEnv -> TCEnv -> Type -> IL.Type
> translType' m tyEnv tcEnv ty =
> translType (elimRecordTypes m tyEnv tcEnv (maximum (0:(typeVars ty))) ty)
> translType :: Type -> IL.Type
> translType (TypeConstructor tc tys) =
> IL.TypeConstructor tc (map translType tys)
> translType (TypeVariable tv) = IL.TypeVariable tv
> translType (TypeConstrained tys _) = translType (head tys)
> translType (TypeArrow ty1 ty2) =
> IL.TypeArrow (translType ty1) (translType ty2)
> translType (TypeSkolem k) =
> IL.TypeConstructor (qualify (mkIdent ("_" ++ show k))) []
> elimRecordTypes :: ModuleIdent -> ValueEnv -> TCEnv -> Int -> Type -> Type
> elimRecordTypes m tyEnv tcEnv n (TypeConstructor t tys) =
> TypeConstructor t (map (elimRecordTypes m tyEnv tcEnv n) tys)
> elimRecordTypes m tyEnv tcEnv n (TypeVariable v) =
> TypeVariable v
> elimRecordTypes m tyEnv tcEnv n (TypeConstrained tys v) =
> TypeConstrained (map (elimRecordTypes m tyEnv tcEnv n) tys) v
> elimRecordTypes m tyEnv tcEnv n (TypeArrow t1 t2) =
> TypeArrow (elimRecordTypes m tyEnv tcEnv n t1)
> (elimRecordTypes m tyEnv tcEnv n t2)
> elimRecordTypes m tyEnv tcEnv n (TypeSkolem v) =
> TypeSkolem v
> elimRecordTypes m tyEnv tcEnv n (TypeRecord fs _)
> | null fs = internalError "elimRecordTypes: empty record type"
> | otherwise =
> case (lookupValue (fst (head fs)) tyEnv) of
> [Label _ r _] ->
> case (qualLookupTC r tcEnv) of
> [AliasType _ n' (TypeRecord fs' _)] ->
> let is = [0 .. n'-1]
> vs = foldl (matchTypeVars fs)
> zeroFM
> fs'
> tys = map (\i -> maybe (TypeVariable (i+n))
> (elimRecordTypes m tyEnv tcEnv n)
> (lookupFM i vs))
> is
> in TypeConstructor r tys
> _ -> internalError "elimRecordTypes: no record type"
> _ -> internalError "elimRecordTypes: no label"
> matchTypeVars :: [(Ident,Type)] -> FM Int Type -> (Ident,Type)
> -> FM Int Type
> matchTypeVars fs vs (l,ty) =
> maybe vs (match vs ty) (lookup l fs)
> where
> match vs (TypeVariable i) ty' = addToFM i ty' vs
> match vs (TypeConstructor _ tys) (TypeConstructor _ tys') =
> matchList vs tys tys'
> match vs (TypeConstrained tys _) (TypeConstrained tys' _) =
> matchList vs tys tys'
> match vs (TypeArrow ty1 ty2) (TypeArrow ty1' ty2') =
> matchList vs [ty1,ty2] [ty1',ty2']
> match vs (TypeSkolem _) (TypeSkolem _) = vs
> match vs (TypeRecord fs _) (TypeRecord fs' _) =
> foldl (matchTypeVars fs') vs fs
> match vs ty ty' =
> internalError ("matchTypeVars: " ++ show ty ++ "\n" ++ show ty')
>
> matchList vs tys tys' =
> foldl (\vs' (ty,ty') -> match vs' ty ty') vs (zip tys tys')
\end{verbatim}
\paragraph{Functions}
Each function in the program is translated into a function of the
intermediate language. The arguments of the function are renamed such
that all variables occurring in the same position (in different
equations) have the same name. This is necessary in order to
facilitate the translation of pattern matching into a \texttt{case}
expression. We use the following simple convention here: The top-level
arguments of the function are named from left to right \texttt{\_1},
\texttt{\_2}, and so on. The names of nested arguments are constructed
by appending \texttt{\_1}, \texttt{\_2}, etc. from left to right to
the name that were assigned to a variable occurring at the position of
the constructor term.
Some special care is needed for the selector functions introduced by
the compiler in place of pattern bindings. In order to generate the
code for updating all pattern variables, the equality of names between
the pattern variables in the first argument of the selector function
and their repeated occurrences in the remaining arguments must be
preserved. This means that the second and following arguments of a
selector function have to be renamed according to the name mapping
computed for its first argument.
If an evaluation annotation is available for a function, it determines
the evaluation mode of the case expression. Otherwise, the function
uses flexible matching.
\begin{verbatim}
> type RenameEnv = Env Ident Ident
> translFunction :: Position -> Bool -> ModuleIdent -> ValueEnv -> TCEnv
> -> EvalEnv -> Ident -> [Equation] -> IL.Decl
> translFunction pos flat m tyEnv tcEnv evEnv f eqs =
> -- | f == mkIdent "fun" = error (show (translType' m tyEnv tcEnv ty))
> -- | otherwise =
> IL.FunctionDecl f' vs (translType' m tyEnv tcEnv ty) expr
> -- = IL.FunctionDecl f' vs (translType ty)
> -- (match ev vs (map (translEquation tyEnv vs vs'') eqs))
> where f' = qualifyWith m f
> ty = varType tyEnv f'
> -- ty' = elimRecordType m tyEnv tcEnv (maximum (0:(typeVars ty))) ty
> ev' = lookupEval f evEnv
> ev = maybe (defaultMode ty) evalMode ev'
> vs = if not flat && isFpSelectorId f then translArgs eqs vs' else vs'
> (vs',vs'') = splitAt (equationArity (head eqs))
> (argNames (mkIdent ""))
> expr | ev' == Just EvalChoice
> = IL.Apply
> (IL.Function
> (qualifyWith preludeMIdent (mkIdent "commit"))
> 1)
> (match (ast pos) IL.Rigid vs
> (map (translEquation tyEnv vs vs'') eqs))
> | otherwise
> = match (ast pos) ev vs (map (translEquation tyEnv vs vs'') eqs)
> ---
> -- (vs',vs'') = splitAt (arrowArity ty) (argNames (mkIdent ""))
> evalMode :: EvalAnnotation -> IL.Eval
> evalMode EvalRigid = IL.Rigid
> evalMode EvalChoice = error "eval choice is not yet supported"
> defaultMode :: Type -> IL.Eval
> defaultMode _ = IL.Flex
>
> --defaultMode ty = if isIO (arrowBase ty) then IL.Rigid else IL.Flex
> -- where TypeConstructor qIOId _ = ioType undefined
> -- isIO (TypeConstructor tc [_]) = tc == qIOId
> -- isIO _ = False
> translArgs :: [Equation] -> [Ident] -> [Ident]
> translArgs [Equation _ (FunLhs _ (t:ts)) _] (v:_) =
> v : map (translArg (bindRenameEnv v t emptyEnv)) ts
> where translArg env (VariablePattern v) = fromJust (lookupEnv v env)
> translEquation :: ValueEnv -> [Ident] -> [Ident] -> Equation
> -> ([NestedTerm],IL.Expression)
> translEquation tyEnv vs vs' (Equation _ (FunLhs _ ts) rhs) =
> (zipWith translTerm vs ts,
> translRhs tyEnv vs' (foldr2 bindRenameEnv emptyEnv vs ts) rhs)
> translRhs :: ValueEnv -> [Ident] -> RenameEnv -> Rhs -> IL.Expression
> translRhs tyEnv vs env (SimpleRhs _ e _) = translExpr tyEnv vs env e
> equationArity :: Equation -> Int
> equationArity (Equation _ lhs _) = p_equArity lhs
> where
> p_equArity (FunLhs _ ts) = length ts
> p_equArity (OpLhs _ _ _) = 2
> p_equArity _ = error "ILTrans - illegal equation"
\end{verbatim}
\paragraph{Pattern Matching}
The pattern matching code searches for the left-most inductive
argument position in the left hand sides of all rules defining an
equation. An inductive position is a position where all rules have a
constructor rooted term. If such a position is found, a \texttt{case}
expression is generated for the argument at that position. The
matching code is then computed recursively for all of the alternatives
independently. If no inductive position is found, the algorithm looks
for the left-most demanded argument position, i.e., a position where
at least one of the rules has a constructor rooted term. If such a
position is found, an \texttt{or} expression is generated with those
cases that have a variable at the argument position in one branch and
all other rules in the other branch. If there is no demanded position,
the pattern matching is finished and the compiler translates the right
hand sides of the remaining rules, eventually combining them using
\texttt{or} expressions.
Actually, the algorithm below combines the search for inductive and
demanded positions. The function \texttt{match} scans the argument
lists for the left-most demanded position. If this turns out to be
also an inductive position, the function \texttt{matchInductive} is
called in order to generate a \texttt{case} expression. Otherwise, the
function \texttt{optMatch} is called that tries to find an inductive
position in the remaining arguments. If one is found,
\texttt{matchInductive} is called, otherwise the function
\texttt{optMatch} uses the demanded argument position found by
\texttt{match}.
\begin{verbatim}
> data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show
> pattern (NestedTerm t _) = t
> arguments (NestedTerm _ ts) = ts
> translLiteral :: Literal -> IL.Literal
> translLiteral (Char p c) = IL.Char p c
> translLiteral (Int id i) = IL.Int (ast (positionOfIdent id)) i
> translLiteral (Float p f) = IL.Float p f
> translLiteral _ = internalError "translLiteral"
> translTerm :: Ident -> ConstrTerm -> NestedTerm
> translTerm _ (LiteralPattern l) =
> NestedTerm (IL.LiteralPattern (translLiteral l)) []
> translTerm v (VariablePattern _) = NestedTerm (IL.VariablePattern v) []
> translTerm v (ConstructorPattern c ts) =
> NestedTerm (IL.ConstructorPattern c (take (length ts) vs))
> (zipWith translTerm vs ts)
> where vs = argNames v
> translTerm v (AsPattern _ t) = translTerm v t
> translTerm _ _ = internalError "translTerm"
> bindRenameEnv :: Ident -> ConstrTerm -> RenameEnv -> RenameEnv
> bindRenameEnv _ (LiteralPattern _) env = env
> bindRenameEnv v (VariablePattern v') env = bindEnv v' v env
> bindRenameEnv v (ConstructorPattern _ ts) env =
> foldr2 bindRenameEnv env (argNames v) ts
> bindRenameEnv v (AsPattern v' t) env = bindEnv v' v (bindRenameEnv v t env)
> bindRenameEnv _ _ env = internalError "bindRenameEnv"
> argNames :: Ident -> [Ident]
> argNames v = [mkIdent (prefix ++ show i) | i <- [1..]]
> where prefix = name v ++ "_"
> type Match = ([NestedTerm],IL.Expression)
> type Match' = ([NestedTerm] -> [NestedTerm],[NestedTerm],IL.Expression)
> isDefaultPattern :: IL.ConstrTerm -> Bool
> isDefaultPattern (IL.VariablePattern _) = True
> isDefaultPattern _ = False
> isDefaultMatch :: (IL.ConstrTerm,a) -> Bool
> isDefaultMatch = isDefaultPattern . fst
> match :: SrcRef -> IL.Eval -> [Ident] -> [Match] -> IL.Expression
> match _ ev [] alts = foldl1 IL.Or (map snd alts)
> match pos ev (v:vs) alts
> | null vars = e1
> | null nonVars = e2
> | otherwise = optMatch pos ev (IL.Or e1 e2) (v:) vs (map skipArg alts)
> where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)
> (nonArgs,args) = partition (null.fst) alts
> e1 = matchInductive pos ev id v vs nonVars
> e2 = match pos ev vs (map snd vars)
> tagAlt (t:ts,e) = (pattern t,(arguments t ++ ts,e))
> skipArg (t:ts,e) = ((t:),ts,e)
> optMatch :: SrcRef -> IL.Eval -> IL.Expression -> ([Ident] -> [Ident])
> -> [Ident] ->[Match'] -> IL.Expression
> optMatch _ ev e prefix [] alts = e
> optMatch pos ev e prefix (v:vs) alts
> | null vars = matchInductive pos ev prefix v vs nonVars
> | otherwise = optMatch pos ev e (prefix . (v:)) vs (map skipArg alts)
> where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)
> tagAlt (prefix,t:ts,e) = (pattern t,(prefix (arguments t ++ ts),e))
> skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)
> matchInductive :: SrcRef -> IL.Eval -> ([Ident] -> [Ident]) -> Ident
> -> [Ident] ->[(IL.ConstrTerm,Match)] -> IL.Expression
> matchInductive pos ev prefix v vs alts =
> IL.Case pos ev (IL.Variable v) (matchAlts ev prefix vs alts)
> matchAlts :: IL.Eval -> ([Ident] -> [Ident]) -> [Ident] ->
> [(IL.ConstrTerm,Match)] -> [IL.Alt]
> matchAlts ev prefix vs [] = []
> matchAlts ev prefix vs ((t,alt):alts) =
> IL.Alt t (match (srcRefOf t)
> ev (prefix (vars t ++ vs)) (alt : map snd same)) :
> matchAlts ev prefix vs others
> where (same,others) = partition ((t ==) . fst) alts
> vars (IL.ConstructorPattern _ vs) = vs
> vars _ = []
\end{verbatim}
Matching in a \texttt{case}-expression works a little bit differently.
In this case, the alternatives are matched from the first to the last
alternative and the first matching alternative is chosen. All
remaining alternatives are discarded.
\ToDo{The case matching algorithm should use type information in order
to detect total matches and immediately discard all alternatives which
cannot be reached.}
\begin{verbatim}
> caseMatch :: SrcRef -> ([Ident] -> [Ident]) -> [Ident] -> [Match']
> -> IL.Expression
> caseMatch _ prefix [] alts = thd3 (head alts)
> caseMatch r prefix (v:vs) alts
> | isDefaultMatch (head alts') =
> caseMatch r (prefix . (v:)) vs (map skipArg alts)
> | otherwise =
> IL.Case r IL.Rigid (IL.Variable v) (caseMatchAlts prefix vs alts')
> where alts' = map tagAlt alts
> tagAlt (prefix,t:ts,e) = (pattern t,(prefix,arguments t ++ ts,e))
> skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)
> caseMatchAlts ::
> ([Ident] -> [Ident]) -> [Ident] -> [(IL.ConstrTerm,Match')] -> [IL.Alt]
> caseMatchAlts prefix vs alts = map caseAlt (ts ++ ts')
> where (ts',ts) = partition isDefaultPattern (nub (map fst alts))
> caseAlt t =
> IL.Alt t (caseMatch (srcRefOf t) id (prefix (vars t ++ vs))
> (matchingCases t alts))
> matchingCases t =
> map (joinArgs (vars t)) . filter (matches t . fst)
> matches t t' = t == t' || isDefaultPattern t'
> joinArgs vs (IL.VariablePattern _,(prefix,ts,e)) =
> (id,prefix (map varPattern vs ++ ts),e)
> joinArgs _ (_,(prefix,ts,e)) = (id,prefix ts,e)
> varPattern v = NestedTerm (IL.VariablePattern v) []
> vars (IL.ConstructorPattern _ vs) = vs
> vars _ = []
\end{verbatim}
\paragraph{Expressions}
Note that the case matching algorithm assumes that the matched
expression is accessible through a variable. The translation of case
expressions therefore introduces a let binding for the scrutinized
expression and immediately throws it away after the matching -- except
if the matching algorithm has decided to use that variable in the
right hand sides of the case expression. This may happen, for
instance, if one of the alternatives contains an \texttt{@}-pattern.
\begin{verbatim}
> translExpr :: ValueEnv -> [Ident] -> RenameEnv -> Expression -> IL.Expression
> translExpr _ _ _ (Literal l) = IL.Literal (translLiteral l)
> translExpr tyEnv _ env (Variable v) =
> case lookupVar v env of
> Just v' -> IL.Variable v'
> Nothing -> IL.Function v (arrowArity (varType tyEnv v))
> where lookupVar v env
> | isQualified v = Nothing
> | otherwise = lookupEnv (unqualify v) env
> translExpr tyEnv _ _ (Constructor c) =
> IL.Constructor c (arrowArity (constrType tyEnv c))
> translExpr tyEnv vs env (Apply e1 e2) =
> IL.Apply (translExpr tyEnv vs env e1) (translExpr tyEnv vs env e2)
> translExpr tyEnv vs env (Let ds e) =
> case ds of
> [ExtraVariables _ vs] -> foldr IL.Exist e' vs
> [d] | all (`notElem` bv d) (qfv emptyMIdent d) ->
> IL.Let (translBinding env' d) e'
> _ -> IL.Letrec (map (translBinding env') ds) e'
> where e' = translExpr tyEnv vs env' e
> env' = foldr2 bindEnv env bvs bvs
> bvs = bv ds
> translBinding env (PatternDecl _ (VariablePattern v) rhs) =
> IL.Binding v (translRhs tyEnv vs env rhs)
> translBinding env p = error $ "unexpected binding: "++show p
> translExpr tyEnv ~(v:vs) env (Case r e alts) =
> case caseMatch r id [v] (map (translAlt v) alts) of
> IL.Case r mode (IL.Variable v') alts'
> | v == v' && v `notElem` fv alts' -> IL.Case r mode e' alts'
> e''
> | v `elem` fv e'' -> IL.Let (IL.Binding v e') e''
> | otherwise -> e''
> where e' = translExpr tyEnv vs env e
> translAlt v (Alt _ t rhs) =
> (id,
> [translTerm v t],
> translRhs tyEnv vs (bindRenameEnv v t env) rhs)
> translExpr _ _ _ _ = internalError "translExpr"
> instance Expr IL.Expression where
> fv (IL.Variable v) = [v]
> fv (IL.Apply e1 e2) = fv e1 ++ fv e2
> fv (IL.Case _ _ e alts) = fv e ++ fv alts
> fv (IL.Or e1 e2) = fv e1 ++ fv e2
> fv (IL.Exist v e) = filter (/= v) (fv e)
> fv (IL.Let (IL.Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)
> fv (IL.Letrec bds e) = filter (`notElem` vs) (fv es ++ fv e)
> where (vs,es) = unzip [(v,e) | IL.Binding v e <- bds]
> fv _ = []
> instance Expr IL.Alt where
> fv (IL.Alt (IL.ConstructorPattern _ vs) e) = filter (`notElem` vs) (fv e)
> fv (IL.Alt (IL.VariablePattern v) e) = filter (v /=) (fv e)
> fv (IL.Alt _ e) = fv e
\end{verbatim}
\paragraph{Auxiliary Definitions}
The functions \texttt{varType} and \texttt{constrType} return the type
of variables and constructors, respectively. The quantifiers are
stripped from the types.
\begin{verbatim}
> varType :: ValueEnv -> QualIdent -> Type
> varType tyEnv f =
> case qualLookupValue f tyEnv of
> [Value _ (ForAll _ ty)] -> ty
> _ -> internalError ("varType: " ++ show f)
> constrType :: ValueEnv -> QualIdent -> Type
> constrType tyEnv c =
> case qualLookupValue c tyEnv of
> [DataConstructor _ (ForAllExist _ _ ty)] -> ty
> [NewtypeConstructor _ (ForAllExist _ _ ty)] -> ty
> _ -> internalError ("constrType: " ++ show c)
\end{verbatim}
The list of import declarations in the intermediate language code is
determined by collecting all module qualifiers used in the current
module.
\begin{verbatim}
> imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]
> imports m = toListSet . deleteFromSet m . fromListSet . foldr modulesDecl []
> modulesDecl :: IL.Decl -> [ModuleIdent] -> [ModuleIdent]
> modulesDecl (IL.DataDecl _ _ cs) ms = foldr modulesConstrDecl ms cs
> where modulesConstrDecl (IL.ConstrDecl _ tys) ms = foldr modulesType ms tys
> modulesDecl (IL.NewtypeDecl _ _ (IL.ConstrDecl _ ty)) ms = modulesType ty ms
> modulesDecl (IL.FunctionDecl _ _ ty e) ms = modulesType ty (modulesExpr e ms)
> modulesDecl (IL.ExternalDecl _ _ _ ty) ms = modulesType ty ms
> modulesType :: IL.Type -> [ModuleIdent] -> [ModuleIdent]
> modulesType (IL.TypeConstructor tc tys) ms =
> modules tc (foldr modulesType ms tys)
> modulesType (IL.TypeVariable _) ms = ms
> modulesType (IL.TypeArrow ty1 ty2) ms = modulesType ty1 (modulesType ty2 ms)
> modulesExpr :: IL.Expression -> [ModuleIdent] -> [ModuleIdent]
> modulesExpr (IL.Function f _) ms = modules f ms
> modulesExpr (IL.Constructor c _) ms = modules c ms
> modulesExpr (IL.Apply e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)
> modulesExpr (IL.Case _ _ e as) ms = modulesExpr e (foldr modulesAlt ms as)
> where modulesAlt (IL.Alt t e) ms = modulesConstrTerm t (modulesExpr e ms)
> modulesConstrTerm (IL.ConstructorPattern c _) ms = modules c ms
> modulesConstrTerm _ ms = ms
> modulesExpr (IL.Or e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)
> modulesExpr (IL.Exist _ e) ms = modulesExpr e ms
> modulesExpr (IL.Let b e) ms = modulesBinding b (modulesExpr e ms)
> modulesExpr (IL.Letrec bs e) ms = foldr modulesBinding (modulesExpr e ms) bs
> modulesExpr _ ms = ms
> modulesBinding :: IL.Binding -> [ModuleIdent] -> [ModuleIdent]
> modulesBinding (IL.Binding _ e) = modulesExpr e
> modules :: QualIdent -> [ModuleIdent] -> [ModuleIdent]
> modules x ms = maybe ms (: ms) (fst (splitQualIdent x))
\end{verbatim}