Plan 9 from Bell Labs’s /usr/web/sources/contrib/fernan/nhc98/src/greencard/DIS.lhs

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


%
% 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 "<record>"
  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}



Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.