ministg-0.3: src/Ministg/Arity.hs
{-# OPTIONS_GHC -XTypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : Ministg.Arity
-- Copyright : (c) 2009 Bernie Pope
-- License : BSD-style
-- Maintainer : bjpop@csse.unimelb.edu.au
-- Stability : experimental
-- Portability : ghc
--
-- Arity analysis of ministg programs: compute how many arguments each
-- top-level and let-bound function has, and annotate the application sites
-- of those functions.
-----------------------------------------------------------------------------
module Ministg.Arity (runArity, Arity) where
import qualified Data.Map as Map
import Data.Map (Map)
import Control.Monad.Reader
import Control.Applicative
import Ministg.AST
import Data.List (foldl')
-- | A mapping from variable names (names of functions) to their respective
-- arities.
type ArityMap = Map Var Int
-- | A monad for pushing arity information down the AST, taking care of
-- variable scope.
type A a = Reader ArityMap a
-- | Arity analysis of a program fragment.
runArity :: Arity a => a -> a
runArity x = runReader (arity x) Map.empty
-- | Overloaded arity function.
class Arity a where
arity :: a -> A a
instance Arity Alt where
arity (PatAlt con args body) =
PatAlt con args <$> local (clearVars args) (arity body)
arity (DefaultAlt var body) =
DefaultAlt var <$> local (clearVars [var]) (arity body)
instance Arity Object where
arity (Fun args body) = Fun args <$> local (clearVars args) (arity body)
arity (Thunk exp cs) = Thunk <$> arity exp <*> pure cs
arity other = return other
instance Arity Program where
arity (Program decls) = Program <$> (local (Map.union as) $ mapM arity decls)
where
as :: ArityMap
as = Map.fromList [ (var, countArgs obj) | Decl var obj <- decls, isFun obj]
-- | Count the number of arguments (really parameters) of a function object).
countArgs :: Object -> Int
countArgs (Fun args _) = length args
countArgs other = error $ "countArgs called on non function: " ++ show other
instance Arity Decl where
arity (Decl var object) = Decl var <$> arity object
instance Arity Exp where
arity (FunApp _oldArity var args) =
FunApp <$> asks (Map.lookup var) <*> pure var <*> pure args
arity (Let var object exp)
| isFun object =
Let var <$> arity object <*> local (Map.insert var $ countArgs object) (arity exp)
| otherwise = Let var <$> arity object <*> local (clearVars [var]) (arity exp)
arity (Case exp alts) = Case <$> arity exp <*> mapM arity alts
arity (Stack annotation exp) = Stack annotation <$> arity exp
arity exp@(Atom {}) = return exp
arity exp@(PrimApp {}) = return exp
-- | Remove a list of variables from an ArityMap.
clearVars :: [Var] -> ArityMap -> ArityMap
clearVars vars map = foldl' (flip Map.delete) map vars