{- CAO Compiler
Copyright (C) 2014 Cryptography and Information Security Group, HASLab - INESC TEC and Universidade do Minho
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . -}
{-
Module : $Header$
Description : Tidy CAO variable names.
Copyright : (C) 2014 Cryptography and Information Security Group, HASLab - INESC TEC and Universidade do Minho
License : GPL
Maintainer : Paulo Silva
Stability : experimental
Portability : non-portable
-}
module Language.CAO.Syntax.Tidy
( tidyCaoAST
, showCaoAST
, showCaoASTDebug
) where
import Control.Monad.State
import Data.Map ( Map )
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Traversable as T
import Language.CAO.Common.Literal
import Language.CAO.Common.Outputable
import Language.CAO.Common.Polynomial
import Language.CAO.Common.SrcLoc
import Language.CAO.Common.Utils
import Language.CAO.Common.Var
import Language.CAO.Index
import Language.CAO.Syntax
import Language.CAO.Syntax.Utils
import Language.CAO.Type
type TidyM = State TidySt
data TidySt
= TidySt { symbolCount :: Map String Int
, seen :: Map Var Var
, globalSymbols :: Map String Int
}
emptyState :: TidySt
emptyState
= TidySt { symbolCount = Map.empty
, seen = Map.empty
, globalSymbols = Map.empty
}
resetLocals :: TidyM ()
resetLocals = modify $ \ s -> s { symbolCount = globalSymbols s }
showCaoAST :: Prog Var -> String
showCaoAST = showPpr . tidyCaoAST
showCaoASTDebug :: Prog Var -> String
showCaoASTDebug = showPprDebug . tidyCaoAST
tidyCaoAST :: Prog Var -> Prog Var
tidyCaoAST p@(Prog defs ip) = uncurry Prog (evalState tidyWorker initState)
where
tidyWorker = do
defs' <- mapM tidyLDef defs
ip' <- mapMaybeM tidyFunDef ip
return (defs', ip')
initState = emptyState { globalSymbols = Map.fromList glbs }
glbs = zip (map getSymbol $ Set.toList $ globals p) (repeat 1)
tidyLDef :: LDef Var -> TidyM (LDef Var)
tidyLDef = tidyLoc tidyDef
tidyDef :: Def Var -> TidyM (Def Var)
tidyDef (VarDef vd) = resetLocals >> liftM VarDef (tidyVarDecl vd)
tidyDef (FunDef vd) = resetLocals >> liftM FunDef (tidyFunDef vd)
tidyDef (TyDef vd) = resetLocals >> liftM TyDef (tidyTyDef vd)
tidyDef (ConstDef cd) = resetLocals >> liftM ConstDef (tidyConstDecl cd)
tidyVarDecl :: VarDecl Var -> TidyM (VarDecl Var)
tidyVarDecl (VarD v td me)
= liftM3 VarD (tidyLVar v) (tidyTyDecl td) (T.mapM tidyTLExpr me)
tidyVarDecl (MultiD v td)
= liftM2 MultiD (mapM tidyLVar v) (tidyTyDecl td)
tidyVarDecl (ContD v td es)
= liftM3 ContD (tidyLVar v) (tidyTyDecl td) (mapM tidyTLExpr es)
tidyConstDecl :: ConstDecl Var -> TidyM (ConstDecl Var)
tidyConstDecl (ConstD v td c)
= liftM3 ConstD (tidyLVar v) (tidyTyDecl td) (return c)
tidyConstDecl (MultiConstD v td c)
= liftM3 MultiConstD (mapM tidyLVar v) (tidyTyDecl td) (return c)
tidyFunDef :: Fun Var -> TidyM (Fun Var)
tidyFunDef (Fun v args tds lstmts)
= liftM4 Fun ( tidyLVar v )
(mapM tidyArg args )
(mapM tidyTyDecl tds )
(mapM tidyLStmt lstmts)
tidyTyDef :: TyDef Var -> TidyM (TyDef Var)
tidyTyDef (TySynDef v td) = liftM2 TySynDef (tidyLVar v) (tidyTyDecl td)
tidyTyDef (StructDecl v fs) = liftM2 StructDecl (tidyLVar v) (mapM tidyFld fs)
tidyLTyDecl :: LTyDecl Var -> TidyM (LTyDecl Var)
tidyLTyDecl = tidyLoc tidyTyDecl
tidyTyDecl :: TyDecl Var -> TidyM (TyDecl Var)
tidyTyDecl (BitsD s e) = liftM (BitsD s) $ tidyLExpr e
tidyTyDecl (ModD md) = liftM ModD $ tidyMod md
tidyTyDecl (VectorD e td) = liftM2 VectorD (tidyLExpr e)
(tidyTyDecl td)
tidyTyDecl (MatrixD r c td) = liftM3 MatrixD (tidyLExpr r)
(tidyLExpr c)
(tidyTyDecl td)
tidyTyDecl (TySynD v) = liftM TySynD (tidyLVar v)
tidyTyDecl d = return d
tidyArg :: Arg Var -> TidyM (Arg Var)
tidyArg (Arg v td)
= liftM2 Arg (tidyLVar v) (tidyTyDecl td)
tidyArg (ArgConst v td i)
= liftM3 ArgConst (tidyLVar v) (tidyTyDecl td) (T.mapM tidyLExpr i)
tidyFld :: (Located Var, TyDecl Var) -> TidyM (Located Var, TyDecl Var)
tidyFld (v, td) = liftM2 (,) (tidyLVar v) (tidyTyDecl td)
tidyLStmt :: LStmt Var -> TidyM (LStmt Var)
tidyLStmt = tidyLoc tidyStmt
tidyStmt :: Stmt Var -> TidyM (Stmt Var)
tidyStmt (VDecl vd)
= liftM VDecl (tidyVarDecl vd)
tidyStmt (CDecl cd)
= liftM CDecl (tidyConstDecl cd)
tidyStmt (Assign lvs es)
= liftM2 Assign (mapM tidyLVal lvs) (mapM tidyTLExpr es)
tidyStmt (FCallS v es)
= liftM2 FCallS (tidyVar v) (mapM tidyTLExpr es)
tidyStmt (Ret es)
= liftM Ret (mapM tidyTLExpr es)
tidyStmt (Ite e ss mss)
= liftM3 Ite (tidyTLExpr e)
(mapM tidyLStmt ss)
(T.mapM (mapM tidyLStmt) mss)
tidyStmt (Seq iter ss)
= liftM2 Seq (tidySeqIter iter) (mapM tidyLStmt ss)
tidyStmt (While e ss)
= liftM2 While (tidyTLExpr e) (mapM tidyLStmt ss)
tidyStmt (Nop a)
= return (Nop a)
tidyLVal :: LVal Var -> TidyM (LVal Var)
tidyLVal (LVVar v) = liftM LVVar (tidyLVar v)
tidyLVal (LVStruct lv fi) = liftM2 LVStruct (tidyLVal lv) (tidyVar fi)
tidyLVal (LVCont ty lv pat) = liftM2 (LVCont ty) (tidyLVal lv) (tidyAPat pat)
tidySeqIter :: SeqIter Var -> TidyM (SeqIter Var)
tidySeqIter (SeqIter v s e mb is)
= liftM4 (\v' s' e' mb' -> SeqIter v' s' e' mb' is)
(tidyVar v) (tidyLExpr s) (tidyLExpr e) (T.mapM tidyLExpr mb)
tidyAPat :: APat Var -> TidyM (APat Var)
tidyAPat (VectP rp) = liftM VectP (tidyRowAPat rp)
tidyAPat (MatP rp cp) = liftM2 MatP (tidyRowAPat rp) (tidyRowAPat cp)
tidyRowAPat :: RowAPat Var -> TidyM (RowAPat Var)
tidyRowAPat (CElem e) = liftM CElem (tidyTLExpr e)
tidyRowAPat (CRange i j) = liftM2 CRange (tidyTLExpr i) (tidyTLExpr j)
tidyMod :: Mod Var -> TidyM (Mod Var)
tidyMod (ModNum e) = liftM ModNum (tidyLExpr e)
tidyMod (ModPol td ind p) = liftM3 ModPol (tidyTyDecl td)
(tidyVar ind)
(tidyPol p)
tidyLit :: Literal Var -> TidyM (Literal Var)
tidyLit (PLit pol) = liftM PLit (tidyPol pol)
tidyLit l = return l
tidyPol :: Pol Var -> TidyM (Pol Var)
tidyPol (Pol ms) = liftM Pol (mapM tidyMon ms)
tidyMon :: Mon Var -> TidyM (Mon Var)
tidyMon (Mon c b) = liftM2 Mon (tidyMCoef c) (tidyMBase b)
tidyMCoef :: MCoef Var -> TidyM (MCoef Var)
tidyMCoef (CoefP p) = liftM CoefP (tidyPol p)
tidyMCoef c = return c
tidyMBase :: MBase Var -> TidyM (MBase Var)
tidyMBase (MExpI n e) = liftM (flip MExpI e) (tidyVar n)
tidyMBase b = return b
tidyLExpr :: LExpr Var -> TidyM (LExpr Var)
tidyLExpr = tidyLoc tidyExpr
tidyTLExpr :: TLExpr Var -> TidyM (TLExpr Var)
tidyTLExpr = tidyLoc (\ (TyE t e) -> liftM (TyE t) (tidyExpr e))
tidyExpr :: Expr Var -> TidyM (Expr Var)
tidyExpr (Var v) = liftM Var (tidyVar v)
tidyExpr (Lit lit) = liftM Lit (tidyLit lit)
tidyExpr (FunCall v es) = liftM2 FunCall (tidyLVar v) (mapM tidyTLExpr es)
tidyExpr (StructProj e fi) = liftM2 StructProj (tidyTLExpr e) (tidyVar fi)
tidyExpr (UnaryOp op e) = liftM (UnaryOp op) (tidyTLExpr e)
tidyExpr (BinaryOp op e1 e2) = liftM2 (BinaryOp op) (tidyTLExpr e1)
(tidyTLExpr e2)
tidyExpr (Access e pat) = liftM2 Access (tidyTLExpr e) (tidyAPat pat)
tidyExpr (Cast b td e) = liftM2 (Cast b) (mapM tidyLTyDecl td)
(tidyTLExpr e)
tidyLVar :: Located Var -> TidyM (Located Var)
tidyLVar = tidyLoc tidyVar
tidyVar :: Var -> TidyM Var
tidyVar v
| isLocal v = do
vars <- gets seen
case Map.lookup v vars of
Nothing -> do
v' <- newSymbol v
t' <- tidyType $ varType v'
let v'' = setType t' v'
modify (\s -> s { seen = Map.insert v v'' (seen s) })
return v''
Just v' -> return v'
| isGlobalInit v = return v
| nsTyVar v = return v
| isCCast v = return v
| isCFunction v = return v
| otherwise = do
t' <- tidyType $ varType v
return $ setSymbol (addPrefix $ getSymbol v) (setType t' v)
newSymbol :: Var -> TidyM Var
newSymbol v = do
sc <- gets symbolCount
let vs = getSymbol v
case Map.lookup vs sc of
Nothing -> do
modify (\s -> s { symbolCount = Map.insert vs 1 (symbolCount s) })
return $ setSymbol (addPrefix vs) v
Just i -> do
modify (\s -> s { symbolCount = Map.adjust (+1) vs (symbolCount s) })
return $ setSymbol (addPrefix $ vs ++ '_' : show i) v
tidyType :: Type Var -> TidyM (Type Var)
tidyType (Bits s sz) =
liftM (Bits s) $ tidyIExpr sz
tidyType (Vector n t) =
liftM2 Vector (tidyIExpr n) (tidyType t)
tidyType (Matrix n m t) =
liftM3 Matrix (tidyIExpr n) (tidyIExpr m) (tidyType t)
tidyType (Mod Nothing Nothing (Pol [Mon (CoefI i) EZero])) = do
i' <- tidyIExpr i
return $ Mod Nothing Nothing (Pol [Mon (CoefI i') EZero])
tidyType (Mod (Just im@(Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])))
(Just i)
(Pol pol)) = do
im' <- tidyType im
pol' <- mapM aux pol
return $ Mod (Just im') (Just i) (Pol pol')
where
aux (Mon (CoefI co) e) = do
co' <- tidyIExpr co
return $ Mon (CoefI co') e
aux _ = error ": not expected case"
tidyType (TySyn v t) = do
t' <- tidyType t
let tct = TySyn newvar t'
newvar = setType tct v
return tct
tidyType (Struct s flds) = do
fldtys' <- mapM tidyFld' flds
let tct = Struct newvar flds'
newvar = setType tct s
flds' = map(\(v, ty) -> (setType (SField newvar ty) v, ty)) fldtys'
return tct
where
tidyFld' (a, sf) = tidyType sf >>= \ sf' -> return (a, sf')
tidyType e = return e
tidyIExpr :: IExpr Var -> TidyM (IExpr Var)
tidyIExpr (IInd v) = liftM IInd $ tidyVar v
tidyIExpr (ISum l) = liftM ISum $ mapM tidyIExpr l
tidyIExpr (IArith op e1 e2) = liftM2 (IArith op) (tidyIExpr e1) (tidyIExpr e2)
tidyIExpr (ISym e) = liftM ISym $ tidyIExpr e
tidyIExpr n@(IInt _) = return n
{-# INLINE addPrefix #-}
addPrefix :: String -> String
addPrefix = ("c_" ++)
{-# INLINE tidyLoc #-}
tidyLoc :: (a -> TidyM a) -> Located a -> TidyM (Located a)
tidyLoc f (L l a) = liftM (L l) (f a)