Remove1_3 is imported by: DbgTrans, Main, Type.
{- ---------------------------------------------------------------------------
Three functions for removing some syntactic sugar:
removeDecls: create selectors for record fields
mkSel: create a single selector for a named field
removeDo: remove do notation
translateExpRecord: remove record expressions
(patternmatching, construction and updating)
-}
module Remove1_3(removeDecls,mkSel,removeDo,translateExpRecord) where import Syntax import State import IntState import TokenId(TokenId,t_gtgt,t_gtgteq,t_zero) import TypeLib(getState,newIdent,getIdent,typeError) import SyntaxPos import TypeData(TypeMonad) import NT import IdKind import Extra(strPos,dropJust,isJust,isNothing,mixCommaAnd,noPos,dropRight ,isRight) import List import Id(Id)
{- ---------------------------------------------------------------------------
Create selectors for record fields.
Done before strongly connected components analysis.
-}
type SelectorMonad a = State () ([Id],IntState) a ([Id],IntState) -- () -> ([Id],IntState) -> (a,([Id],IntState))
{-
Replace DeclConstrs in the declarations by definitions for selectors.
Also collect identifiers of all field names.
-}
removeDecls :: Decls Id -> ((TokenId,IdKind) -> Id) -> IntState -> (Decls Id -- modified declarations ,[Id] -- identifiers of all data constructors ,IntState) removeDecls (DeclsParse decls) tidFun state = case mapS removeDecl decls () ([],state) of (decls,(zcons,state)) -> (DeclsParse (concat decls),zcons,state)
{-
Replace a single DeclConstrs by definitions for selectors.
-}
removeDecl :: Decl Id -> SelectorMonad [Decl Id] removeDecl (DeclConstrs pos zcon cs) = remember zcon >>>= \_ -> mapS mkSel cs removeDecl d = unitS [d]
{-
Create the definition for a given selector identfier.
-}
mkSel :: (Pos -- point of definition of selector, i.e in type definition ,Id -- field name id ,Id) -- selector name id -> SelectorMonad (Decl Id) mkSel (pos,field,selector) = r13Info field >>>= \ (InfoField unique tid icon_offs iData iSel) -> mapS (mkFun pos) icon_offs >>>= \ alts -> unitS (DeclFun pos selector alts)
{-
Make one equation of a selector for given data constructor and offset
-}
mkFun :: Pos -> (Id,Int) -- (data constructor, offset) -> SelectorMonad (Fun Id) mkFun pos (c,i) = r13Info c >>>= \ conInfo -> r13Unique >>>= \ v -> let wildcard = PatWildcard pos var = ExpVar pos v vars = take (arityI conInfo) (repeat wildcard) -- arityI safe for constructors :-) in unitS (Fun [ExpApplication pos (ExpCon pos c : onePos var i vars)] (Unguarded var) (DeclsParse []))
{-
Replace list element at given index by given new element.
-}
onePos :: a -> Int -> [a] -> [a] onePos v 1 (x:xs) = v:xs onePos v n (x:xs) = x: onePos v (n-1 ::Int) xs r13Info :: Id -> SelectorMonad Info r13Info i down thread@(zcon,state) = (dropJust (lookupIS state i),thread)
{- get a new unique id -}
r13Unique :: SelectorMonad Id r13Unique down thread@(zcon,state) = case uniqueIS state of (u,state) -> (u,(zcon,state)) remember :: Id -> SelectorMonad () remember zcon down thread@(zcons,state) = ((),(zcon:zcons,state))
{- --------------------------------------------------------------------------- Remove syntactic sugar of do notation. Done after strongly connected components analysis, more precisely: called by type checker -} {- Remove syntactic sugar of do notation. -}
removeDo :: [Stmt Id] -> TypeMonad (Exp Id) removeDo [StmtExp exp] = unitS exp removeDo (StmtExp exp:r) = let pos = getPos exp in getIdent (t_gtgt,Var) >>>= \ gtgt -> removeDo r >>>= \ exp2 -> unitS (ExpApplication pos [ExpVar pos gtgt, exp, exp2]) removeDo (StmtLet decls :r) = let pos = getPos decls in removeDo r >>>= \ exp2 -> unitS (ExpLet pos decls exp2) removeDo (StmtBind pat exp:r) = getIdent (t_gtgteq,Var) >>>= \ gtgteq -> getState >>>= \ state -> removeDo r >>>= \ exp2 -> let pos = getPos exp in if nofail state pat then unitS (ExpApplication pos [ExpVar pos gtgteq, exp, ExpLambda pos [pat] exp2]) else getIdent (t_zero,Var) >>>= \ zero -> -- In H98, this is `fail' newIdent >>>= \ x -> let eX = ExpVar pos x eFail = ExpApplication pos [ExpVar pos zero ,ExpLit pos (LitString Boxed "pattern-match failure in do expression")] in unitS (ExpApplication pos [ExpVar pos gtgteq ,exp ,ExpLambda pos [eX] (ExpCase pos eX [Alt pat (Unguarded exp2) (DeclsScc []) ,Alt (PatWildcard pos) (Unguarded eFail) (DeclsScc []) ])])
{-
Test if matching the given pattern cannot fail.
-}
nofail :: IntState -> Pat Id -> Bool nofail state (ExpCon pos con) = case lookupIS state con of Just (InfoConstr unique tid fix nt fields iType) -> case lookupIS state iType of Just (InfoData unique tid exp nt dk) -> case dk of (DataNewType unboxed constructors) -> True (Data unboxed constrs) -> length constrs == 1 nofail state (ExpVar _ _) = True nofail state (ExpApplication pos es) = all (nofail state) es nofail state (PatWildcard _) = True nofail state (PatAs _ _ pat) = nofail state pat nofail state (PatIrrefutable pos pat) = True nofail state _ = False
{- ---------------------------------------------------------------------------
Remove record expressions.
Done after strongly connected components analysis,
more precisely: called by type checker
-}
fieldInfo :: IntState -> Field Id -> (Id -- type constructor ,([(Id,Int)] -- data constructors with offsets for field ,Exp Id)) -- expressions from "field=exp" fieldInfo state (FieldExp pos field exp) = case lookupIS state field of Just (InfoField unique tid icon_offs idata iSel) -> (idata,(icon_offs,exp))
{- lookup value in association list; if not there, then return default value -}
fixArg :: Eq a => [(a,b)] -> (a,b) -> b fixArg given (i,def) = case lookup i given of Just e -> e Nothing -> def
{- construct alternative for record updating for one data constructor -}
fixAlt :: Pos -> [Exp Id] -- arguments for offsets -> (Id,[Int]) -- (data constructor, offsets) -> IntState -> (Alt Id,IntState) fixAlt pos exps (con,offsets) state = (Alt (ExpApplication pos (econ:vars)) (Unguarded (ExpApplication pos (econ : map (fixArg (zip offsets exps)) (zip nargs vars)))) (DeclsScc []) ,state') where nargs = [1 .. arityIS state con] (newNIds,state') = uniqueISs state nargs vars = map (ExpVar noPos . snd) newNIds econ = ExpCon pos con getOffsets :: [[(Id,Int)]] -> Id -> Either (Id,[Maybe Int]) (Id,[Int]) getOffsets icon_offs con = let offsets = map (\ icon_off -> lookup con icon_off) icon_offs in if all isJust offsets then Right (con,map dropJust offsets) else Left (con,offsets)
{-
Replace record expression exp{field1=exp1,...} by a non-record expression.
Used for record patterns as well.
(in fact, undefined constructor arguments are filled with wildcard patterns)
-}
translateExpRecord :: Exp Id -> [Field Id] -> IntState -> (Either String (Exp Id),IntState) translateExpRecord e@(ExpRecord exp' fields') fields state = translateExpRecord exp' (fields ++ fields') state translateExpRecord e@(ExpCon pos con) fields state = let coes = map (fieldInfo state) fields in if firstIsEqual coes then let (icon_offs,exps) = unzip (map snd coes) in case getOffsets icon_offs con of Right (con,offsets) -> (Right (ExpApplication pos (e:map (fixArg (zip offsets exps)) (zip [1 .. arityIS state con] (repeat (PatWildcard pos)) ) )) ,state) Left (con,offsets) -> (Left (errField1 state pos con offsets fields) ,state) else (Left (errField2 state fields),state) translateExpRecord exp [] state = (Left (errField4 (getPos exp)),state) translateExpRecord exp fields state = let coes@((t,_):_) = map (fieldInfo state) fields in if firstIsEqual coes -- all fields belong to same data type then let (icon_offs,exps) = unzip (map snd coes) pos = getPos exp in case (partition isRight . map (getOffsets icon_offs) . constrsI . dropJust . lookupIS state) t of ([],_) -> (Left (errField3 state fields),state) (rps,_) -> let consFixAlt rps (alts,state) = case fixAlt pos exps rps state of (alt,state') -> (alt:alts,state') (alts,state') = foldr consFixAlt ([],state) (map dropRight rps) in (Right (ExpCase (getPos exp) exp alts), state') else (Left (errField2 state fields),state)
{- Test if all first components are equal. -}
firstIsEqual :: Eq a => [(a,b)] -> Bool firstIsEqual [] = True firstIsEqual ((k,_):kvs) = all (k==) (map fst kvs) errField1 :: IntState -> Pos -> Id -> [Maybe a] -> [Field Id] -> String errField1 state pos con offsets fields = "The field(s)" ++ mixCommaAnd (map (\(_,FieldExp pos field exp) -> ' ':show (tidIS state field) ++ " at " ++ strPos pos) (filter (isNothing.fst) (zip offsets fields))) ++ " do(es) not belong to constructor " ++ show (tidIS state con) ++ " used at " ++ strPos pos ++ "." errField2 :: IntState -> [Field Id] -> String errField2 state fields = "The fields" ++ mixCommaAnd (map (\(FieldExp pos field exp) -> ' ': show (tidIS state field) ++ " at " ++ strPos pos) fields) ++ " do not belong to the same type." errField3 :: IntState -> [Field Id] -> String errField3 state fields = "The fields " ++ mixCommaAnd (map (\(FieldExp pos field exp) -> ' ':show (tidIS state field) ++ " at " ++ strPos pos) fields) ++ " do not belong to the same constructor." errField4 :: Pos -> [Char] errField4 pos = "The update of the expression at " ++ strPos pos ++ " uses an empty list of fields."
{- End Remove1_3 ------------------------------------------------------------}
(HTML for this module was generated on May 15, 2003. About the conversion tool.)