+++ /dev/null
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-\section[DsArrows]{Desugaring arrow commands}
-
-\begin{code}
-module DsArrows ( dsProcExpr ) where
-
-#include "HsVersions.h"
-
-import Match ( matchSimply )
-import DsUtils ( mkErrorAppDs,
- mkCoreTupTy, mkCoreTup, selectSimpleMatchVarL,
- mkTupleCase, mkBigCoreTup, mkTupleType,
- mkTupleExpr, mkTupleSelector,
- dsSyntaxTable, lookupEvidence )
-import DsMonad
-
-import HsSyn
-import TcHsSyn ( hsPatType )
-
--- NB: The desugarer, which straddles the source and Core worlds, sometimes
--- needs to see source types (newtypes etc), and sometimes not
--- So WATCH OUT; check each use of split*Ty functions.
--- Sigh. This is a pain.
-
-import {-# SOURCE #-} DsExpr ( dsExpr, dsLExpr, dsLocalBinds )
-
-import TcType ( Type, tcSplitAppTy, mkFunTy )
-import Type ( mkTyConApp, funArgTy )
-import CoreSyn
-import CoreFVs ( exprFreeVars )
-import CoreUtils ( mkIfThenElse, bindNonRec, exprType )
-
-import Id ( Id, idType )
-import Name ( Name )
-import PrelInfo ( pAT_ERROR_ID )
-import DataCon ( dataConWrapId )
-import TysWiredIn ( tupleCon )
-import BasicTypes ( Boxity(..) )
-import PrelNames ( eitherTyConName, leftDataConName, rightDataConName,
- arrAName, composeAName, firstAName,
- appAName, choiceAName, loopAName )
-import Util ( mapAccumL )
-import Outputable
-
-import HsUtils ( collectPatBinders, collectPatsBinders )
-import VarSet ( IdSet, mkVarSet, varSetElems,
- intersectVarSet, minusVarSet, extendVarSetList,
- unionVarSet, unionVarSets, elemVarSet )
-import SrcLoc ( Located(..), unLoc, noLoc )
-\end{code}
-
-\begin{code}
-data DsCmdEnv = DsCmdEnv {
- meth_binds :: [CoreBind],
- arr_id, compose_id, first_id, app_id, choice_id, loop_id :: CoreExpr
- }
-
-mkCmdEnv :: SyntaxTable Id -> DsM DsCmdEnv
-mkCmdEnv ids
- = dsSyntaxTable ids `thenDs` \ (meth_binds, ds_meths) ->
- return $ DsCmdEnv {
- meth_binds = meth_binds,
- arr_id = Var (lookupEvidence ds_meths arrAName),
- compose_id = Var (lookupEvidence ds_meths composeAName),
- first_id = Var (lookupEvidence ds_meths firstAName),
- app_id = Var (lookupEvidence ds_meths appAName),
- choice_id = Var (lookupEvidence ds_meths choiceAName),
- loop_id = Var (lookupEvidence ds_meths loopAName)
- }
-
-bindCmdEnv :: DsCmdEnv -> CoreExpr -> CoreExpr
-bindCmdEnv ids body = foldr Let body (meth_binds ids)
-
--- arr :: forall b c. (b -> c) -> a b c
-do_arr :: DsCmdEnv -> Type -> Type -> CoreExpr -> CoreExpr
-do_arr ids b_ty c_ty f = mkApps (arr_id ids) [Type b_ty, Type c_ty, f]
-
--- (>>>) :: forall b c d. a b c -> a c d -> a b d
-do_compose :: DsCmdEnv -> Type -> Type -> Type ->
- CoreExpr -> CoreExpr -> CoreExpr
-do_compose ids b_ty c_ty d_ty f g
- = mkApps (compose_id ids) [Type b_ty, Type c_ty, Type d_ty, f, g]
-
--- first :: forall b c d. a b c -> a (b,d) (c,d)
-do_first :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr
-do_first ids b_ty c_ty d_ty f
- = mkApps (first_id ids) [Type b_ty, Type c_ty, Type d_ty, f]
-
--- app :: forall b c. a (a b c, b) c
-do_app :: DsCmdEnv -> Type -> Type -> CoreExpr
-do_app ids b_ty c_ty = mkApps (app_id ids) [Type b_ty, Type c_ty]
-
--- (|||) :: forall b d c. a b d -> a c d -> a (Either b c) d
--- note the swapping of d and c
-do_choice :: DsCmdEnv -> Type -> Type -> Type ->
- CoreExpr -> CoreExpr -> CoreExpr
-do_choice ids b_ty c_ty d_ty f g
- = mkApps (choice_id ids) [Type b_ty, Type d_ty, Type c_ty, f, g]
-
--- loop :: forall b d c. a (b,d) (c,d) -> a b c
--- note the swapping of d and c
-do_loop :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr
-do_loop ids b_ty c_ty d_ty f
- = mkApps (loop_id ids) [Type b_ty, Type d_ty, Type c_ty, f]
-
--- map_arrow (f :: b -> c) (g :: a c d) = arr f >>> g :: a b d
-do_map_arrow :: DsCmdEnv -> Type -> Type -> Type ->
- CoreExpr -> CoreExpr -> CoreExpr
-do_map_arrow ids b_ty c_ty d_ty f c
- = do_compose ids b_ty c_ty d_ty (do_arr ids b_ty c_ty f) c
-
-mkFailExpr :: HsMatchContext Id -> Type -> DsM CoreExpr
-mkFailExpr ctxt ty
- = mkErrorAppDs pAT_ERROR_ID ty (matchContextErrString ctxt)
-
--- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> b
-mkSndExpr :: Type -> Type -> DsM CoreExpr
-mkSndExpr a_ty b_ty
- = newSysLocalDs a_ty `thenDs` \ a_var ->
- newSysLocalDs b_ty `thenDs` \ b_var ->
- newSysLocalDs (mkCorePairTy a_ty b_ty) `thenDs` \ pair_var ->
- returnDs (Lam pair_var
- (coreCasePair pair_var a_var b_var (Var b_var)))
-\end{code}
-
-Build case analysis of a tuple. This cannot be done in the DsM monad,
-because the list of variables is typically not yet defined.
-
-\begin{code}
--- coreCaseTuple [u1..] v [x1..xn] body
--- = case v of v { (x1, .., xn) -> body }
--- But the matching may be nested if the tuple is very big
-
-coreCaseTuple :: UniqSupply -> Id -> [Id] -> CoreExpr -> CoreExpr
-coreCaseTuple uniqs scrut_var vars body
- = mkTupleCase uniqs vars body scrut_var (Var scrut_var)
-
-coreCasePair :: Id -> Id -> Id -> CoreExpr -> CoreExpr
-coreCasePair scrut_var var1 var2 body
- = Case (Var scrut_var) scrut_var (exprType body)
- [(DataAlt (tupleCon Boxed 2), [var1, var2], body)]
-\end{code}
-
-\begin{code}
-mkCorePairTy :: Type -> Type -> Type
-mkCorePairTy t1 t2 = mkCoreTupTy [t1, t2]
-
-mkCorePairExpr :: CoreExpr -> CoreExpr -> CoreExpr
-mkCorePairExpr e1 e2 = mkCoreTup [e1, e2]
-\end{code}
-
-The input is divided into a local environment, which is a flat tuple
-(unless it's too big), and a stack, each element of which is paired
-with the stack in turn. In general, the input has the form
-
- (...((x1,...,xn),s1),...sk)
-
-where xi are the environment values, and si the ones on the stack,
-with s1 being the "top", the first one to be matched with a lambda.
-
-\begin{code}
-envStackType :: [Id] -> [Type] -> Type
-envStackType ids stack_tys = foldl mkCorePairTy (mkTupleType ids) stack_tys
-
-----------------------------------------------
--- buildEnvStack
---
--- (...((x1,...,xn),s1),...sk)
-
-buildEnvStack :: [Id] -> [Id] -> CoreExpr
-buildEnvStack env_ids stack_ids
- = foldl mkCorePairExpr (mkTupleExpr env_ids) (map Var stack_ids)
-
-----------------------------------------------
--- matchEnvStack
---
--- \ (...((x1,...,xn),s1),...sk) -> e
--- =>
--- \ zk ->
--- case zk of (zk-1,sk) ->
--- ...
--- case z1 of (z0,s1) ->
--- case z0 of (x1,...,xn) ->
--- e
-
-matchEnvStack :: [Id] -- x1..xn
- -> [Id] -- s1..sk
- -> CoreExpr -- e
- -> DsM CoreExpr
-matchEnvStack env_ids stack_ids body
- = newUniqueSupply `thenDs` \ uniqs ->
- newSysLocalDs (mkTupleType env_ids) `thenDs` \ tup_var ->
- matchVarStack tup_var stack_ids
- (coreCaseTuple uniqs tup_var env_ids body)
-
-
-----------------------------------------------
--- matchVarStack
---
--- \ (...(z0,s1),...sk) -> e
--- =>
--- \ zk ->
--- case zk of (zk-1,sk) ->
--- ...
--- case z1 of (z0,s1) ->
--- e
-
-matchVarStack :: Id -- z0
- -> [Id] -- s1..sk
- -> CoreExpr -- e
- -> DsM CoreExpr
-matchVarStack env_id [] body
- = returnDs (Lam env_id body)
-matchVarStack env_id (stack_id:stack_ids) body
- = newSysLocalDs (mkCorePairTy (idType env_id) (idType stack_id))
- `thenDs` \ pair_id ->
- matchVarStack pair_id stack_ids
- (coreCasePair pair_id env_id stack_id body)
-\end{code}
-
-\begin{code}
-mkHsTupleExpr :: [HsExpr Id] -> HsExpr Id
-mkHsTupleExpr [e] = e
-mkHsTupleExpr es = ExplicitTuple (map noLoc es) Boxed
-
-mkHsPairExpr :: HsExpr Id -> HsExpr Id -> HsExpr Id
-mkHsPairExpr e1 e2 = mkHsTupleExpr [e1, e2]
-
-mkHsEnvStackExpr :: [Id] -> [Id] -> HsExpr Id
-mkHsEnvStackExpr env_ids stack_ids
- = foldl mkHsPairExpr (mkHsTupleExpr (map HsVar env_ids)) (map HsVar stack_ids)
-\end{code}
-
-Translation of arrow abstraction
-
-\begin{code}
-
--- A | xs |- c :: [] t' ---> c'
--- --------------------------
--- A |- proc p -> c :: a t t' ---> arr (\ p -> (xs)) >>> c'
---
--- where (xs) is the tuple of variables bound by p
-
-dsProcExpr
- :: LPat Id
- -> LHsCmdTop Id
- -> DsM CoreExpr
-dsProcExpr pat (L _ (HsCmdTop cmd [] cmd_ty ids))
- = mkCmdEnv ids `thenDs` \ meth_ids ->
- let
- locals = mkVarSet (collectPatBinders pat)
- in
- dsfixCmd meth_ids locals [] cmd_ty cmd
- `thenDs` \ (core_cmd, free_vars, env_ids) ->
- let
- env_ty = mkTupleType env_ids
- in
- mkFailExpr ProcExpr env_ty `thenDs` \ fail_expr ->
- selectSimpleMatchVarL pat `thenDs` \ var ->
- matchSimply (Var var) ProcExpr pat (mkTupleExpr env_ids) fail_expr
- `thenDs` \ match_code ->
- let
- pat_ty = hsPatType pat
- proc_code = do_map_arrow meth_ids pat_ty env_ty cmd_ty
- (Lam var match_code)
- core_cmd
- in
- returnDs (bindCmdEnv meth_ids proc_code)
-\end{code}
-
-Translation of command judgements of the form
-
- A | xs |- c :: [ts] t
-
-\begin{code}
-dsLCmd ids local_vars env_ids stack res_ty cmd
- = dsCmd ids local_vars env_ids stack res_ty (unLoc cmd)
-
-dsCmd :: DsCmdEnv -- arrow combinators
- -> IdSet -- set of local vars available to this command
- -> [Id] -- list of vars in the input to this command
- -- This is typically fed back,
- -- so don't pull on it too early
- -> [Type] -- type of the stack
- -> Type -- return type of the command
- -> HsCmd Id -- command to desugar
- -> DsM (CoreExpr, -- desugared expression
- IdSet) -- set of local vars that occur free
-
--- A |- f :: a (t*ts) t'
--- A, xs |- arg :: t
--- -----------------------------
--- A | xs |- f -< arg :: [ts] t'
---
--- ---> arr (\ ((xs)*ts) -> (arg*ts)) >>> f
-
-dsCmd ids local_vars env_ids stack res_ty
- (HsArrApp arrow arg arrow_ty HsFirstOrderApp _)
- = let
- (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty
- (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty
- env_ty = mkTupleType env_ids
- in
- dsLExpr arrow `thenDs` \ core_arrow ->
- dsLExpr arg `thenDs` \ core_arg ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
- matchEnvStack env_ids stack_ids
- (foldl mkCorePairExpr core_arg (map Var stack_ids))
- `thenDs` \ core_make_arg ->
- returnDs (do_map_arrow ids
- (envStackType env_ids stack)
- arg_ty
- res_ty
- core_make_arg
- core_arrow,
- exprFreeVars core_arg `intersectVarSet` local_vars)
-
--- A, xs |- f :: a (t*ts) t'
--- A, xs |- arg :: t
--- ------------------------------
--- A | xs |- f -<< arg :: [ts] t'
---
--- ---> arr (\ ((xs)*ts) -> (f,(arg*ts))) >>> app
-
-dsCmd ids local_vars env_ids stack res_ty
- (HsArrApp arrow arg arrow_ty HsHigherOrderApp _)
- = let
- (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty
- (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty
- env_ty = mkTupleType env_ids
- in
- dsLExpr arrow `thenDs` \ core_arrow ->
- dsLExpr arg `thenDs` \ core_arg ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
- matchEnvStack env_ids stack_ids
- (mkCorePairExpr core_arrow
- (foldl mkCorePairExpr core_arg (map Var stack_ids)))
- `thenDs` \ core_make_pair ->
- returnDs (do_map_arrow ids
- (envStackType env_ids stack)
- (mkCorePairTy arrow_ty arg_ty)
- res_ty
- core_make_pair
- (do_app ids arg_ty res_ty),
- (exprFreeVars core_arrow `unionVarSet` exprFreeVars core_arg)
- `intersectVarSet` local_vars)
-
--- A | ys |- c :: [t:ts] t'
--- A, xs |- e :: t
--- ------------------------
--- A | xs |- c e :: [ts] t'
---
--- ---> arr (\ ((xs)*ts) -> let z = e in (((ys),z)*ts)) >>> c
-
-dsCmd ids local_vars env_ids stack res_ty (HsApp cmd arg)
- = dsLExpr arg `thenDs` \ core_arg ->
- let
- arg_ty = exprType core_arg
- stack' = arg_ty:stack
- in
- dsfixCmd ids local_vars stack' res_ty cmd
- `thenDs` \ (core_cmd, free_vars, env_ids') ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
- newSysLocalDs arg_ty `thenDs` \ arg_id ->
- -- push the argument expression onto the stack
- let
- core_body = bindNonRec arg_id core_arg
- (buildEnvStack env_ids' (arg_id:stack_ids))
- in
- -- match the environment and stack against the input
- matchEnvStack env_ids stack_ids core_body
- `thenDs` \ core_map ->
- returnDs (do_map_arrow ids
- (envStackType env_ids stack)
- (envStackType env_ids' stack')
- res_ty
- core_map
- core_cmd,
- (exprFreeVars core_arg `intersectVarSet` local_vars)
- `unionVarSet` free_vars)
-
--- A | ys |- c :: [ts] t'
--- -----------------------------------------------
--- A | xs |- \ p1 ... pk -> c :: [t1:...:tk:ts] t'
---
--- ---> arr (\ ((((xs), p1), ... pk)*ts) -> ((ys)*ts)) >>> c
-
-dsCmd ids local_vars env_ids stack res_ty
- (HsLam (MatchGroup [L _ (Match pats _ (GRHSs [L _ (GRHS [] body)] _ ))] _))
- = let
- pat_vars = mkVarSet (collectPatsBinders pats)
- local_vars' = local_vars `unionVarSet` pat_vars
- stack' = drop (length pats) stack
- in
- dsfixCmd ids local_vars' stack' res_ty body
- `thenDs` \ (core_body, free_vars, env_ids') ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
-
- -- the expression is built from the inside out, so the actions
- -- are presented in reverse order
-
- let
- (actual_ids, stack_ids') = splitAt (length pats) stack_ids
- -- build a new environment, plus what's left of the stack
- core_expr = buildEnvStack env_ids' stack_ids'
- in_ty = envStackType env_ids stack
- in_ty' = envStackType env_ids' stack'
- in
- mkFailExpr LambdaExpr in_ty' `thenDs` \ fail_expr ->
- -- match the patterns against the top of the old stack
- matchSimplys (map Var actual_ids) LambdaExpr pats core_expr fail_expr
- `thenDs` \ match_code ->
- -- match the old environment and stack against the input
- matchEnvStack env_ids stack_ids match_code
- `thenDs` \ select_code ->
- returnDs (do_map_arrow ids in_ty in_ty' res_ty select_code core_body,
- free_vars `minusVarSet` pat_vars)
-
-dsCmd ids local_vars env_ids stack res_ty (HsPar cmd)
- = dsLCmd ids local_vars env_ids stack res_ty cmd
-
--- A, xs |- e :: Bool
--- A | xs1 |- c1 :: [ts] t
--- A | xs2 |- c2 :: [ts] t
--- ----------------------------------------
--- A | xs |- if e then c1 else c2 :: [ts] t
---
--- ---> arr (\ ((xs)*ts) ->
--- if e then Left ((xs1)*ts) else Right ((xs2)*ts)) >>>
--- c1 ||| c2
-
-dsCmd ids local_vars env_ids stack res_ty (HsIf cond then_cmd else_cmd)
- = dsLExpr cond `thenDs` \ core_cond ->
- dsfixCmd ids local_vars stack res_ty then_cmd
- `thenDs` \ (core_then, fvs_then, then_ids) ->
- dsfixCmd ids local_vars stack res_ty else_cmd
- `thenDs` \ (core_else, fvs_else, else_ids) ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
- dsLookupTyCon eitherTyConName `thenDs` \ either_con ->
- dsLookupDataCon leftDataConName `thenDs` \ left_con ->
- dsLookupDataCon rightDataConName `thenDs` \ right_con ->
- let
- left_expr ty1 ty2 e = mkConApp left_con [Type ty1, Type ty2, e]
- right_expr ty1 ty2 e = mkConApp right_con [Type ty1, Type ty2, e]
-
- in_ty = envStackType env_ids stack
- then_ty = envStackType then_ids stack
- else_ty = envStackType else_ids stack
- sum_ty = mkTyConApp either_con [then_ty, else_ty]
- fvs_cond = exprFreeVars core_cond `intersectVarSet` local_vars
- in
- matchEnvStack env_ids stack_ids
- (mkIfThenElse core_cond
- (left_expr then_ty else_ty (buildEnvStack then_ids stack_ids))
- (right_expr then_ty else_ty (buildEnvStack else_ids stack_ids)))
- `thenDs` \ core_if ->
- returnDs(do_map_arrow ids in_ty sum_ty res_ty
- core_if
- (do_choice ids then_ty else_ty res_ty core_then core_else),
- fvs_cond `unionVarSet` fvs_then `unionVarSet` fvs_else)
-\end{code}
-
-Case commands are treated in much the same way as if commands
-(see above) except that there are more alternatives. For example
-
- case e of { p1 -> c1; p2 -> c2; p3 -> c3 }
-
-is translated to
-
- arr (\ ((xs)*ts) -> case e of
- p1 -> (Left (Left (xs1)*ts))
- p2 -> Left ((Right (xs2)*ts))
- p3 -> Right ((xs3)*ts)) >>>
- (c1 ||| c2) ||| c3
-
-The idea is to extract the commands from the case, build a balanced tree
-of choices, and replace the commands with expressions that build tagged
-tuples, obtaining a case expression that can be desugared normally.
-To build all this, we use quadruples decribing segments of the list of
-case bodies, containing the following fields:
-1. an IdSet containing the environment variables free in the case bodies
-2. a list of expressions of the form (Left|Right)* ((xs)*ts), to be put
- into the case replacing the commands
-3. a sum type that is the common type of these expressions, and also the
- input type of the arrow
-4. a CoreExpr for an arrow built by combining the translated command
- bodies with |||.
-
-\begin{code}
-dsCmd ids local_vars env_ids stack res_ty (HsCase exp (MatchGroup matches match_ty))
- = dsLExpr exp `thenDs` \ core_exp ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
-
- -- Extract and desugar the leaf commands in the case, building tuple
- -- expressions that will (after tagging) replace these leaves
-
- let
- leaves = concatMap leavesMatch matches
- make_branch (leaf, bound_vars)
- = dsfixCmd ids (local_vars `unionVarSet` bound_vars) stack res_ty leaf
- `thenDs` \ (core_leaf, fvs, leaf_ids) ->
- returnDs (fvs `minusVarSet` bound_vars,
- [noLoc $ mkHsEnvStackExpr leaf_ids stack_ids],
- envStackType leaf_ids stack,
- core_leaf)
- in
- mappM make_branch leaves `thenDs` \ branches ->
- dsLookupTyCon eitherTyConName `thenDs` \ either_con ->
- dsLookupDataCon leftDataConName `thenDs` \ left_con ->
- dsLookupDataCon rightDataConName `thenDs` \ right_con ->
- let
- left_id = nlHsVar (dataConWrapId left_con)
- right_id = nlHsVar (dataConWrapId right_con)
- left_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ TyApp left_id [ty1, ty2]) e
- right_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ TyApp right_id [ty1, ty2]) e
-
- -- Prefix each tuple with a distinct series of Left's and Right's,
- -- in a balanced way, keeping track of the types.
-
- merge_branches (fvs1, builds1, in_ty1, core_exp1)
- (fvs2, builds2, in_ty2, core_exp2)
- = (fvs1 `unionVarSet` fvs2,
- map (left_expr in_ty1 in_ty2) builds1 ++
- map (right_expr in_ty1 in_ty2) builds2,
- mkTyConApp either_con [in_ty1, in_ty2],
- do_choice ids in_ty1 in_ty2 res_ty core_exp1 core_exp2)
- (fvs_alts, leaves', sum_ty, core_choices)
- = foldb merge_branches branches
-
- -- Replace the commands in the case with these tagged tuples,
- -- yielding a HsExpr Id we can feed to dsExpr.
-
- (_, matches') = mapAccumL (replaceLeavesMatch res_ty) leaves' matches
- in_ty = envStackType env_ids stack
- fvs_exp = exprFreeVars core_exp `intersectVarSet` local_vars
-
- pat_ty = funArgTy match_ty
- match_ty' = mkFunTy pat_ty sum_ty
- -- Note that we replace the HsCase result type by sum_ty,
- -- which is the type of matches'
- in
- dsExpr (HsCase exp (MatchGroup matches' match_ty')) `thenDs` \ core_body ->
- matchEnvStack env_ids stack_ids core_body
- `thenDs` \ core_matches ->
- returnDs(do_map_arrow ids in_ty sum_ty res_ty core_matches core_choices,
- fvs_exp `unionVarSet` fvs_alts)
-
--- A | ys |- c :: [ts] t
--- ----------------------------------
--- A | xs |- let binds in c :: [ts] t
---
--- ---> arr (\ ((xs)*ts) -> let binds in ((ys)*ts)) >>> c
-
-dsCmd ids local_vars env_ids stack res_ty (HsLet binds body)
- = let
- defined_vars = mkVarSet (map unLoc (collectLocalBinders binds))
- local_vars' = local_vars `unionVarSet` defined_vars
- in
- dsfixCmd ids local_vars' stack res_ty body
- `thenDs` \ (core_body, free_vars, env_ids') ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
- -- build a new environment, plus the stack, using the let bindings
- dsLocalBinds binds (buildEnvStack env_ids' stack_ids)
- `thenDs` \ core_binds ->
- -- match the old environment and stack against the input
- matchEnvStack env_ids stack_ids core_binds
- `thenDs` \ core_map ->
- returnDs (do_map_arrow ids
- (envStackType env_ids stack)
- (envStackType env_ids' stack)
- res_ty
- core_map
- core_body,
- exprFreeVars core_binds `intersectVarSet` local_vars)
-
-dsCmd ids local_vars env_ids [] res_ty (HsDo _ctxt stmts body _)
- = dsCmdDo ids local_vars env_ids res_ty stmts body
-
--- A |- e :: forall e. a1 (e*ts1) t1 -> ... an (e*tsn) tn -> a (e*ts) t
--- A | xs |- ci :: [tsi] ti
--- -----------------------------------
--- A | xs |- (|e c1 ... cn|) :: [ts] t ---> e [t_xs] c1 ... cn
-
-dsCmd _ids local_vars env_ids _stack _res_ty (HsArrForm op _ args)
- = let
- env_ty = mkTupleType env_ids
- in
- dsLExpr op `thenDs` \ core_op ->
- mapAndUnzipDs (dsTrimCmdArg local_vars env_ids) args
- `thenDs` \ (core_args, fv_sets) ->
- returnDs (mkApps (App core_op (Type env_ty)) core_args,
- unionVarSets fv_sets)
-
--- A | ys |- c :: [ts] t (ys <= xs)
--- ---------------------
--- A | xs |- c :: [ts] t ---> arr_ts (\ (xs) -> (ys)) >>> c
-
-dsTrimCmdArg
- :: IdSet -- set of local vars available to this command
- -> [Id] -- list of vars in the input to this command
- -> LHsCmdTop Id -- command argument to desugar
- -> DsM (CoreExpr, -- desugared expression
- IdSet) -- set of local vars that occur free
-dsTrimCmdArg local_vars env_ids (L _ (HsCmdTop cmd stack cmd_ty ids))
- = mkCmdEnv ids `thenDs` \ meth_ids ->
- dsfixCmd meth_ids local_vars stack cmd_ty cmd
- `thenDs` \ (core_cmd, free_vars, env_ids') ->
- mappM newSysLocalDs stack `thenDs` \ stack_ids ->
- matchEnvStack env_ids stack_ids (buildEnvStack env_ids' stack_ids)
- `thenDs` \ trim_code ->
- let
- in_ty = envStackType env_ids stack
- in_ty' = envStackType env_ids' stack
- arg_code = if env_ids' == env_ids then core_cmd else
- do_map_arrow meth_ids in_ty in_ty' cmd_ty trim_code core_cmd
- in
- returnDs (bindCmdEnv meth_ids arg_code, free_vars)
-
--- Given A | xs |- c :: [ts] t, builds c with xs fed back.
--- Typically needs to be prefixed with arr (\p -> ((xs)*ts))
-
-dsfixCmd
- :: DsCmdEnv -- arrow combinators
- -> IdSet -- set of local vars available to this command
- -> [Type] -- type of the stack
- -> Type -- return type of the command
- -> LHsCmd Id -- command to desugar
- -> DsM (CoreExpr, -- desugared expression
- IdSet, -- set of local vars that occur free
- [Id]) -- set as a list, fed back
-dsfixCmd ids local_vars stack cmd_ty cmd
- = fixDs (\ ~(_,_,env_ids') ->
- dsLCmd ids local_vars env_ids' stack cmd_ty cmd
- `thenDs` \ (core_cmd, free_vars) ->
- returnDs (core_cmd, free_vars, varSetElems free_vars))
-
-\end{code}
-
-Translation of command judgements of the form
-
- A | xs |- do { ss } :: [] t
-
-\begin{code}
-
-dsCmdDo :: DsCmdEnv -- arrow combinators
- -> IdSet -- set of local vars available to this statement
- -> [Id] -- list of vars in the input to this statement
- -- This is typically fed back,
- -- so don't pull on it too early
- -> Type -- return type of the statement
- -> [LStmt Id] -- statements to desugar
- -> LHsExpr Id -- body
- -> DsM (CoreExpr, -- desugared expression
- IdSet) -- set of local vars that occur free
-
--- A | xs |- c :: [] t
--- --------------------------
--- A | xs |- do { c } :: [] t
-
-dsCmdDo ids local_vars env_ids res_ty [] body
- = dsLCmd ids local_vars env_ids [] res_ty body
-
-dsCmdDo ids local_vars env_ids res_ty (stmt:stmts) body
- = let
- bound_vars = mkVarSet (map unLoc (collectLStmtBinders stmt))
- local_vars' = local_vars `unionVarSet` bound_vars
- in
- fixDs (\ ~(_,_,env_ids') ->
- dsCmdDo ids local_vars' env_ids' res_ty stmts body
- `thenDs` \ (core_stmts, fv_stmts) ->
- returnDs (core_stmts, fv_stmts, varSetElems fv_stmts))
- `thenDs` \ (core_stmts, fv_stmts, env_ids') ->
- dsCmdLStmt ids local_vars env_ids env_ids' stmt
- `thenDs` \ (core_stmt, fv_stmt) ->
- returnDs (do_compose ids
- (mkTupleType env_ids)
- (mkTupleType env_ids')
- res_ty
- core_stmt
- core_stmts,
- fv_stmt)
-
-\end{code}
-A statement maps one local environment to another, and is represented
-as an arrow from one tuple type to another. A statement sequence is
-translated to a composition of such arrows.
-\begin{code}
-dsCmdLStmt ids local_vars env_ids out_ids cmd
- = dsCmdStmt ids local_vars env_ids out_ids (unLoc cmd)
-
-dsCmdStmt
- :: DsCmdEnv -- arrow combinators
- -> IdSet -- set of local vars available to this statement
- -> [Id] -- list of vars in the input to this statement
- -- This is typically fed back,
- -- so don't pull on it too early
- -> [Id] -- list of vars in the output of this statement
- -> Stmt Id -- statement to desugar
- -> DsM (CoreExpr, -- desugared expression
- IdSet) -- set of local vars that occur free
-
--- A | xs1 |- c :: [] t
--- A | xs' |- do { ss } :: [] t'
--- ------------------------------
--- A | xs |- do { c; ss } :: [] t'
---
--- ---> arr (\ (xs) -> ((xs1),(xs'))) >>> first c >>>
--- arr snd >>> ss
-
-dsCmdStmt ids local_vars env_ids out_ids (ExprStmt cmd _ c_ty)
- = dsfixCmd ids local_vars [] c_ty cmd
- `thenDs` \ (core_cmd, fv_cmd, env_ids1) ->
- matchEnvStack env_ids []
- (mkCorePairExpr (mkTupleExpr env_ids1) (mkTupleExpr out_ids))
- `thenDs` \ core_mux ->
- let
- in_ty = mkTupleType env_ids
- in_ty1 = mkTupleType env_ids1
- out_ty = mkTupleType out_ids
- before_c_ty = mkCorePairTy in_ty1 out_ty
- after_c_ty = mkCorePairTy c_ty out_ty
- in
- mkSndExpr c_ty out_ty `thenDs` \ snd_fn ->
- returnDs (do_map_arrow ids in_ty before_c_ty out_ty core_mux $
- do_compose ids before_c_ty after_c_ty out_ty
- (do_first ids in_ty1 c_ty out_ty core_cmd) $
- do_arr ids after_c_ty out_ty snd_fn,
- extendVarSetList fv_cmd out_ids)
- where
-
--- A | xs1 |- c :: [] t
--- A | xs' |- do { ss } :: [] t' xs2 = xs' - defs(p)
--- -----------------------------------
--- A | xs |- do { p <- c; ss } :: [] t'
---
--- ---> arr (\ (xs) -> ((xs1),(xs2))) >>> first c >>>
--- arr (\ (p, (xs2)) -> (xs')) >>> ss
---
--- It would be simpler and more consistent to do this using second,
--- but that's likely to be defined in terms of first.
-
-dsCmdStmt ids local_vars env_ids out_ids (BindStmt pat cmd _ _)
- = dsfixCmd ids local_vars [] (hsPatType pat) cmd
- `thenDs` \ (core_cmd, fv_cmd, env_ids1) ->
- let
- pat_ty = hsPatType pat
- pat_vars = mkVarSet (collectPatBinders pat)
- env_ids2 = varSetElems (mkVarSet out_ids `minusVarSet` pat_vars)
- env_ty2 = mkTupleType env_ids2
- in
-
- -- multiplexing function
- -- \ (xs) -> ((xs1),(xs2))
-
- matchEnvStack env_ids []
- (mkCorePairExpr (mkTupleExpr env_ids1) (mkTupleExpr env_ids2))
- `thenDs` \ core_mux ->
-
- -- projection function
- -- \ (p, (xs2)) -> (zs)
-
- newSysLocalDs env_ty2 `thenDs` \ env_id ->
- newUniqueSupply `thenDs` \ uniqs ->
- let
- after_c_ty = mkCorePairTy pat_ty env_ty2
- out_ty = mkTupleType out_ids
- body_expr = coreCaseTuple uniqs env_id env_ids2 (mkTupleExpr out_ids)
- in
- mkFailExpr (StmtCtxt DoExpr) out_ty `thenDs` \ fail_expr ->
- selectSimpleMatchVarL pat `thenDs` \ pat_id ->
- matchSimply (Var pat_id) (StmtCtxt DoExpr) pat body_expr fail_expr
- `thenDs` \ match_code ->
- newSysLocalDs after_c_ty `thenDs` \ pair_id ->
- let
- proj_expr = Lam pair_id (coreCasePair pair_id pat_id env_id match_code)
- in
-
- -- put it all together
- let
- in_ty = mkTupleType env_ids
- in_ty1 = mkTupleType env_ids1
- in_ty2 = mkTupleType env_ids2
- before_c_ty = mkCorePairTy in_ty1 in_ty2
- in
- returnDs (do_map_arrow ids in_ty before_c_ty out_ty core_mux $
- do_compose ids before_c_ty after_c_ty out_ty
- (do_first ids in_ty1 pat_ty in_ty2 core_cmd) $
- do_arr ids after_c_ty out_ty proj_expr,
- fv_cmd `unionVarSet` (mkVarSet out_ids `minusVarSet` pat_vars))
-
--- A | xs' |- do { ss } :: [] t
--- --------------------------------------
--- A | xs |- do { let binds; ss } :: [] t
---
--- ---> arr (\ (xs) -> let binds in (xs')) >>> ss
-
-dsCmdStmt ids local_vars env_ids out_ids (LetStmt binds)
- -- build a new environment using the let bindings
- = dsLocalBinds binds (mkTupleExpr out_ids) `thenDs` \ core_binds ->
- -- match the old environment against the input
- matchEnvStack env_ids [] core_binds `thenDs` \ core_map ->
- returnDs (do_arr ids
- (mkTupleType env_ids)
- (mkTupleType out_ids)
- core_map,
- exprFreeVars core_binds `intersectVarSet` local_vars)
-
--- A | ys |- do { ss; returnA -< ((xs1), (ys2)) } :: [] ...
--- A | xs' |- do { ss' } :: [] t
--- ------------------------------------
--- A | xs |- do { rec ss; ss' } :: [] t
---
--- xs1 = xs' /\ defs(ss)
--- xs2 = xs' - defs(ss)
--- ys1 = ys - defs(ss)
--- ys2 = ys /\ defs(ss)
---
--- ---> arr (\(xs) -> ((ys1),(xs2))) >>>
--- first (loop (arr (\((ys1),~(ys2)) -> (ys)) >>> ss)) >>>
--- arr (\((xs1),(xs2)) -> (xs')) >>> ss'
-
-dsCmdStmt ids local_vars env_ids out_ids (RecStmt stmts later_ids rec_ids rhss binds)
- = let -- ToDo: ****** binds not desugared; ROSS PLEASE FIX ********
- env2_id_set = mkVarSet out_ids `minusVarSet` mkVarSet later_ids
- env2_ids = varSetElems env2_id_set
- env2_ty = mkTupleType env2_ids
- in
-
- -- post_loop_fn = \((later_ids),(env2_ids)) -> (out_ids)
-
- newUniqueSupply `thenDs` \ uniqs ->
- newSysLocalDs env2_ty `thenDs` \ env2_id ->
- let
- later_ty = mkTupleType later_ids
- post_pair_ty = mkCorePairTy later_ty env2_ty
- post_loop_body = coreCaseTuple uniqs env2_id env2_ids (mkTupleExpr out_ids)
- in
- matchEnvStack later_ids [env2_id] post_loop_body
- `thenDs` \ post_loop_fn ->
-
- --- loop (...)
-
- dsRecCmd ids local_vars stmts later_ids rec_ids rhss
- `thenDs` \ (core_loop, env1_id_set, env1_ids) ->
-
- -- pre_loop_fn = \(env_ids) -> ((env1_ids),(env2_ids))
-
- let
- env1_ty = mkTupleType env1_ids
- pre_pair_ty = mkCorePairTy env1_ty env2_ty
- pre_loop_body = mkCorePairExpr (mkTupleExpr env1_ids)
- (mkTupleExpr env2_ids)
-
- in
- matchEnvStack env_ids [] pre_loop_body
- `thenDs` \ pre_loop_fn ->
-
- -- arr pre_loop_fn >>> first (loop (...)) >>> arr post_loop_fn
-
- let
- env_ty = mkTupleType env_ids
- out_ty = mkTupleType out_ids
- core_body = do_map_arrow ids env_ty pre_pair_ty out_ty
- pre_loop_fn
- (do_compose ids pre_pair_ty post_pair_ty out_ty
- (do_first ids env1_ty later_ty env2_ty
- core_loop)
- (do_arr ids post_pair_ty out_ty
- post_loop_fn))
- in
- returnDs (core_body, env1_id_set `unionVarSet` env2_id_set)
-
--- loop (arr (\ ((env1_ids), ~(rec_ids)) -> (env_ids)) >>>
--- ss >>>
--- arr (\ (out_ids) -> ((later_ids),(rhss))) >>>
-
-dsRecCmd ids local_vars stmts later_ids rec_ids rhss
- = let
- rec_id_set = mkVarSet rec_ids
- out_ids = varSetElems (mkVarSet later_ids `unionVarSet` rec_id_set)
- out_ty = mkTupleType out_ids
- local_vars' = local_vars `unionVarSet` rec_id_set
- in
-
- -- mk_pair_fn = \ (out_ids) -> ((later_ids),(rhss))
-
- mappM dsExpr rhss `thenDs` \ core_rhss ->
- let
- later_tuple = mkTupleExpr later_ids
- later_ty = mkTupleType later_ids
- rec_tuple = mkBigCoreTup core_rhss
- rec_ty = mkTupleType rec_ids
- out_pair = mkCorePairExpr later_tuple rec_tuple
- out_pair_ty = mkCorePairTy later_ty rec_ty
- in
- matchEnvStack out_ids [] out_pair
- `thenDs` \ mk_pair_fn ->
-
- -- ss
-
- dsfixCmdStmts ids local_vars' out_ids stmts
- `thenDs` \ (core_stmts, fv_stmts, env_ids) ->
-
- -- squash_pair_fn = \ ((env1_ids), ~(rec_ids)) -> (env_ids)
-
- newSysLocalDs rec_ty `thenDs` \ rec_id ->
- let
- env1_id_set = fv_stmts `minusVarSet` rec_id_set
- env1_ids = varSetElems env1_id_set
- env1_ty = mkTupleType env1_ids
- in_pair_ty = mkCorePairTy env1_ty rec_ty
- core_body = mkBigCoreTup (map selectVar env_ids)
- where
- selectVar v
- | v `elemVarSet` rec_id_set
- = mkTupleSelector rec_ids v rec_id (Var rec_id)
- | otherwise = Var v
- in
- matchEnvStack env1_ids [rec_id] core_body
- `thenDs` \ squash_pair_fn ->
-
- -- loop (arr squash_pair_fn >>> ss >>> arr mk_pair_fn)
-
- let
- env_ty = mkTupleType env_ids
- core_loop = do_loop ids env1_ty later_ty rec_ty
- (do_map_arrow ids in_pair_ty env_ty out_pair_ty
- squash_pair_fn
- (do_compose ids env_ty out_ty out_pair_ty
- core_stmts
- (do_arr ids out_ty out_pair_ty mk_pair_fn)))
- in
- returnDs (core_loop, env1_id_set, env1_ids)
-
-\end{code}
-A sequence of statements (as in a rec) is desugared to an arrow between
-two environments
-\begin{code}
-
-dsfixCmdStmts
- :: DsCmdEnv -- arrow combinators
- -> IdSet -- set of local vars available to this statement
- -> [Id] -- output vars of these statements
- -> [LStmt Id] -- statements to desugar
- -> DsM (CoreExpr, -- desugared expression
- IdSet, -- set of local vars that occur free
- [Id]) -- input vars
-
-dsfixCmdStmts ids local_vars out_ids stmts
- = fixDs (\ ~(_,_,env_ids) ->
- dsCmdStmts ids local_vars env_ids out_ids stmts
- `thenDs` \ (core_stmts, fv_stmts) ->
- returnDs (core_stmts, fv_stmts, varSetElems fv_stmts))
-
-dsCmdStmts
- :: DsCmdEnv -- arrow combinators
- -> IdSet -- set of local vars available to this statement
- -> [Id] -- list of vars in the input to these statements
- -> [Id] -- output vars of these statements
- -> [LStmt Id] -- statements to desugar
- -> DsM (CoreExpr, -- desugared expression
- IdSet) -- set of local vars that occur free
-
-dsCmdStmts ids local_vars env_ids out_ids [stmt]
- = dsCmdLStmt ids local_vars env_ids out_ids stmt
-
-dsCmdStmts ids local_vars env_ids out_ids (stmt:stmts)
- = let
- bound_vars = mkVarSet (map unLoc (collectLStmtBinders stmt))
- local_vars' = local_vars `unionVarSet` bound_vars
- in
- dsfixCmdStmts ids local_vars' out_ids stmts
- `thenDs` \ (core_stmts, fv_stmts, env_ids') ->
- dsCmdLStmt ids local_vars env_ids env_ids' stmt
- `thenDs` \ (core_stmt, fv_stmt) ->
- returnDs (do_compose ids
- (mkTupleType env_ids)
- (mkTupleType env_ids')
- (mkTupleType out_ids)
- core_stmt
- core_stmts,
- fv_stmt)
-
-\end{code}
-
-Match a list of expressions against a list of patterns, left-to-right.
-
-\begin{code}
-matchSimplys :: [CoreExpr] -- Scrutinees
- -> HsMatchContext Name -- Match kind
- -> [LPat Id] -- Patterns they should match
- -> CoreExpr -- Return this if they all match
- -> CoreExpr -- Return this if they don't
- -> DsM CoreExpr
-matchSimplys [] _ctxt [] result_expr _fail_expr = returnDs result_expr
-matchSimplys (exp:exps) ctxt (pat:pats) result_expr fail_expr
- = matchSimplys exps ctxt pats result_expr fail_expr
- `thenDs` \ match_code ->
- matchSimply exp ctxt pat match_code fail_expr
-\end{code}
-
-List of leaf expressions, with set of variables bound in each
-
-\begin{code}
-leavesMatch :: LMatch Id -> [(LHsExpr Id, IdSet)]
-leavesMatch (L _ (Match pats _ (GRHSs grhss binds)))
- = let
- defined_vars = mkVarSet (collectPatsBinders pats)
- `unionVarSet`
- mkVarSet (map unLoc (collectLocalBinders binds))
- in
- [(expr,
- mkVarSet (map unLoc (collectLStmtsBinders stmts))
- `unionVarSet` defined_vars)
- | L _ (GRHS stmts expr) <- grhss]
-\end{code}
-
-Replace the leaf commands in a match
-
-\begin{code}
-replaceLeavesMatch
- :: Type -- new result type
- -> [LHsExpr Id] -- replacement leaf expressions of that type
- -> LMatch Id -- the matches of a case command
- -> ([LHsExpr Id],-- remaining leaf expressions
- LMatch Id) -- updated match
-replaceLeavesMatch res_ty leaves (L loc (Match pat mt (GRHSs grhss binds)))
- = let
- (leaves', grhss') = mapAccumL replaceLeavesGRHS leaves grhss
- in
- (leaves', L loc (Match pat mt (GRHSs grhss' binds)))
-
-replaceLeavesGRHS
- :: [LHsExpr Id] -- replacement leaf expressions of that type
- -> LGRHS Id -- rhss of a case command
- -> ([LHsExpr Id],-- remaining leaf expressions
- LGRHS Id) -- updated GRHS
-replaceLeavesGRHS (leaf:leaves) (L loc (GRHS stmts rhs))
- = (leaves, L loc (GRHS stmts leaf))
-\end{code}
-
-Balanced fold of a non-empty list.
-
-\begin{code}
-foldb :: (a -> a -> a) -> [a] -> a
-foldb _ [] = error "foldb of empty list"
-foldb _ [x] = x
-foldb f xs = foldb f (fold_pairs xs)
- where
- fold_pairs [] = []
- fold_pairs [x] = [x]
- fold_pairs (x1:x2:xs) = f x1 x2:fold_pairs xs
-\end{code}