% % Copyright (C) 1997 Thomas Nordin and Alastair Reid % \begin{code} module DIS ( DIS(..) , apply , ppDIS, ppDIS' , expandDIS, DISEnv , freeVarsOfDIS , simplify ) where import Casm( BaseTy(..), ppBaseTy ) import Name( Name ) import Pretty import PrettyUtils( ppTuple, commaList, textline ) #if !defined(__HASKELL98__) #define isAlphaNum isAlphanum #endif import Char( isAlphaNum, isLower ) \end{code} I'd like to get rid of this definition \begin{code} -- The DIS table maps a user defined DIS to its definition. type DISTable = [(Name, ([Name], DIS))] \end{code} %************************************************************************ %* * \subsection{DIS data structure} %* * %************************************************************************ \begin{code} data DIS = Apply DIS [DIS] -- args never empty | BaseDIS BaseTy | Constructor Name | Declare String DIS -- declared DIS can only be a Var or an Exp | Exp String | Record Name [Name] | Tuple | UserDIS Bool Name Name -- bool is whether user functions are pure | Var Name deriving ( Show ) \end{code} Always use this constructor to maintain the invariant that the args part of an apply is non-empty. \begin{code} apply :: DIS -> [DIS] -> DIS apply f [] = f apply f as = Apply f as \end{code} %************************************************************************ %* * \subsection{Pretty Printing of DISs} %* * %************************************************************************ \begin{code} ppDIS :: DIS -> Doc ppDIS = ppDIS' False -- @ppDIS'@ Can either print the type casts or not. ppDIS' :: Bool -> DIS -> Doc ppDIS' showCasts dis = pp dis where pp (Apply Tuple ds) = ppTuple (pps ds) pp (Apply (Record name fs) ds) = text name <+> braces (commaList fields) where fields = zipWith (\n d -> textline [n, "="] <+> d) fs (pps ds) pp (Apply d ds) = parens (pp d <+> hsep (pps ds)) pp (BaseDIS n) = text "%%" <> text (show n) pp (Constructor nm) = text nm pp (Declare s d) = text "declare" <+> quotes (text s) <+> pp d <+> text "in" pp (Exp s) = quotes (text s) pp (Record nm fs) = text "" pp Tuple = text "()" -- unit pp (UserDIS True n1 n2) = text ('<':n1++'/':n2++'>':[]) pp (UserDIS False n1 n2) = text ('<':'<':n1++'/':n2++'>':'>':[]) pp (Var nm) = text nm pps = map pp \end{code} %************************************************************************ %* * \subsection{Free Variables} %* * %************************************************************************ \begin{code} freeVarsOfDIS :: DIS -> [Name] freeVarsOfDIS = free where free (Apply d ds) = free d ++ concatMap free ds free (Var nm) = [nm] free (Declare s d) = free d free _ = [] \end{code} %************************************************************************ %* * \subsection{Expanding DISs} %* * %************************************************************************ Expanding a DIS is rather like evaluating an expression: we walk over the DIS with an environment replacing disnames and arguments with values from the environment. The result is a DIS in normal \begin{code} type DISEnv = [(Name, ([Name], DIS))] type ArgEnv = [(Name, DIS)] expandDIS :: DISEnv -> DIS -> DIS expandDIS denv d = expandDIS' denv [] d expandDIS' :: DISEnv -> ArgEnv -> DIS -> DIS expandDIS' denv aenv d = xp d where -- dis application xp (Apply f@(Var nm) ds) = case (lookup nm denv) of Just (args, d) -> if length args == length ds then expandDIS' denv (zip args (xps ds)) d else error ("Argument list mismatch while calling " ++ nm ++ " in DIS " ++ show d ) Nothing -> Apply f (xps ds) xp (Apply d ds) = Apply (xp d) (xps ds) xp v@(Var nm) = case (lookup nm aenv) of Just d -> d Nothing -> v xp (Declare ctype v@(Var nm)) = Declare (subst ctype) (case (lookup nm aenv) of Just d -> d Nothing -> v) xp (Declare ctype (Exp s)) = Declare (subst ctype) (Exp (subst s)) xp (Exp s) = Exp (subst s) xp (UserDIS p f t) = UserDIS p (subst f) (subst t) xp (BaseDIS (Foreign f)) = BaseDIS (Foreign (subst f)) -- everything else is already in normal form xp d = d xps = map xp -- substitute for anything of the form %[a-z][a-zA-Z0-9]* subst :: String -> String subst ('%':c:cs) | isLower c = case lookup nm aenv of Just (Exp c) -> c ++ subst rest Just (Var v) -> '%':v ++ subst rest Just d' -> error ("Can't substitute " ++ show d' ++ " for " ++ nm ++ " in DIS " ++ show d) Nothing -> error ("Unknown variable " ++ nm ++ " in DIS " ++ show d) where (cs0, rest) = span isAlphaNum cs nm = c:cs0 subst ('%':'%':cs) = '%':'%': subst cs -- escape code subst (c:cs) = c : subst cs subst "" = "" \end{code} %************************************************************************ %* * \subsection{Simplify DISs} %* * %************************************************************************ Simplify a DIS by: * pushing outer declarations down to leaves, * overriding inner ones, * removing declarations of literals (which have no effect), * and where userDISs are applied to many args, converting args to a tuple \begin{code} simplify :: DIS -> DIS simplify dis = simpl [] dis where simpl :: [(Name,DIS)] -> DIS -> DIS simpl env (Apply decl@(Declare cty (Var v)) [d]) = case lookup v env of Just _ -> simpl env d Nothing -> simpl ((v,decl):env) d simpl env (Apply (Declare cty (Exp v)) [d]) = simpl env d simpl env (Apply u@(UserDIS p f t) ds) | length ds > 1 = Apply u [Apply Tuple (map (simpl env) ds)] simpl env (Apply d ds) = Apply (simpl env d) (map (simpl env) ds) simpl env d@(Var "iO") = d simpl env (Var v) = case lookup v env of Just d -> d Nothing -> error ("No C type decl for variable "++v++" in DIS:\n" ++show dis) simpl env d@(Exp s) = inner env d s simpl env d = d inner env d [] = d inner env d ('%':c:cs) | isLower c = case lookup nm env of Just decl -> Apply decl [inner env d rest] Nothing -> error ("No C type decl for variable "++nm++" in literal:\n" ++show d) where (cs0, rest) = span isAlphaNum cs nm = c:cs0 inner env d (c:cs) = inner env d cs \end{code} %************************************************************************ %* * \subsection{Example DISs} %* * %************************************************************************ \begin{code} dis1 = Apply (BaseDIS Int) [Declare "int" (Var "x")] dis2 = Apply (BaseDIS Float) [Declare "float" (Var "y")] dis3 = Apply Tuple [dis1,dis2] disenv1 = [ ( "int", (["x"], dis1) ) , ( "float", (["y"], dis2) ) ] dis4 = Apply (Var "int") [Var "arg1"] dis5 = expandDIS disenv1 dis4 \end{code}