module Reader.Abstraction
( abstract
) where
import Data.Types
( SignalDecType(..)
)
import Data.Enum
( EnumDefinition(..)
)
import Data.Binding
( BindExpr(..)
)
import Data.Expression
( Expr(..)
, Expr'(..)
, ExprPos
)
import Reader.Data
( NameTable
, PositionTable
, ArgumentTable
, Specification(..)
)
import Reader.Error
( Error
, errUnknown
, errConflict
, errPattern
)
import Data.Maybe
( mapMaybe
)
import Control.Monad.State
( StateT(..)
, evalStateT
, get
, put
, void
)
import qualified Reader.Parser.Data as PD
( Specification(..)
)
import qualified Data.IntMap.Strict as IM
( empty
, insert
, lookup
)
import qualified Data.StringMap as SM
( StringMap
, empty
, insert
, lookup
)
type Abstractor a b = a -> StateT ST (Either Error) b
data ST = ST
{ count :: Int
, tIndex :: SM.StringMap
, tName :: NameTable
, tPos :: PositionTable
, tArgs :: ArgumentTable
}
abstract
:: PD.Specification -> Either Error Specification
abstract spec =
evalStateT (abstractSpec spec)
ST { count = 1
, tIndex = SM.empty
, tName = IM.empty
, tPos = IM.empty
, tArgs = IM.empty
}
abstractSpec
:: Abstractor PD.Specification Specification
abstractSpec s = do
mapM_ (\x -> add (bIdent x,bPos x)) $ PD.parameters s
mapM_ (mapM_ (\(y,z,_) -> add (y,z)) . eValues) $ PD.enumerations s
mapM_ (\x -> add (bIdent x,bPos x)) $ PD.definitions s
ps <- mapM abstractBind $ PD.parameters s
vs <- mapM abstractBind $ PD.definitions s
let
(ig,ib,ie) = foldl classify ([],[],[]) $ PD.inputs s
(og,ob,oe) = foldl classify ([],[],[]) $ PD.outputs s
a <- get
ms <- mapM abstractEnum $ PD.enumerations s
ie' <- mapM abstractSignalType ie
oe' <- mapM abstractSignalType oe
a' <- get
put a' {
tIndex = tIndex a
}
ig' <- mapM add ig
og' <- mapM add og
ib' <- mapM abstractBus ib
ob' <- mapM abstractBus ob
ie'' <- mapM abstractTypedBus ie'
oe'' <- mapM abstractTypedBus oe'
let
is =
map SDSingle ig' ++
map (uncurry SDBus) ib' ++
map (uncurry SDEnum) ie''
os =
map SDSingle og' ++
map (uncurry SDBus) ob' ++
map (uncurry SDEnum) oe''
es <- mapM abstractExpr $ PD.initially s
ss <- mapM abstractExpr $ PD.preset s
rs <- mapM abstractExpr $ PD.requirements s
as <- mapM abstractExpr $ PD.assumptions s
bs <- mapM abstractExpr $ PD.invariants s
gs <- mapM abstractExpr $ PD.guarantees s
st <- get
return $ Specification
(PD.title s)
(PD.description s)
(PD.semantics s)
(PD.target s)
(PD.tags s)
ms ps vs is os es ss rs as bs gs
IM.empty
(tName st)
(tPos st)
(tArgs st)
IM.empty
IM.empty
where
classify (a,b,c) x = case x of
SDSingle y -> (y:a,b,c)
SDBus y z -> (a,(y,z):b,c)
SDEnum y z -> (a,b,(y,z):c)
abstractTypedBus (n,m) = do
a <- add n
return (a,m)
abstractSignalType
:: Abstractor ((String,ExprPos),(String,ExprPos))
((String,ExprPos),(Int,ExprPos))
abstractSignalType (n,(t,p)) = do
a <- get
i <- case SM.lookup t $ tIndex a of
Just j -> return j
Nothing -> errUnknown t p
return (n,(i,p))
abstractBus
:: Abstractor ((String,ExprPos),Expr String)
((Int,ExprPos),Expr Int)
abstractBus ((s,p),e) = do
(i,p') <- add (s,p)
e' <- abstractExpr e
return ((i,p'),e')
abstractEnum
:: Abstractor (EnumDefinition String) (EnumDefinition Int)
abstractEnum b = do
(n,p) <- add (eName b, ePos b)
vs <- mapM abstractEnumV $ eValues b
return EnumDefinition
{ eName = n
, eSize = eSize b
, eValues = vs
, ePos = p
, eMissing = eMissing b
, eDouble = Nothing
}
where
abstractEnumV (n,p,f) = do
a <- get
case SM.lookup n $ tIndex a of
Just j -> return (j,p,f)
Nothing -> errUnknown n p
abstractBind
:: Abstractor (BindExpr String) (BindExpr Int)
abstractBind b = do
a <- get
as <- mapM add $ bArgs b
es <- mapM abstractExpr $ bVal b
a' <- get
i <- case SM.lookup (bIdent b) $ tIndex a of
Just j -> return j
Nothing -> errUnknown (bIdent b) (bPos b)
put $ a' {
tIndex = tIndex a,
tArgs = IM.insert i (map fst as) $ tArgs a'
}
return BindExpr
{ bIdent = i
, bArgs = as
, bPos = bPos b
, bVal = es
}
add
:: Abstractor (String,ExprPos) (Int,ExprPos)
add (i,pos) = do
a <- get
case SM.lookup i $ tIndex a of
Nothing -> do
put ST
{ count = count a + 1
, tIndex = SM.insert i (count a) $ tIndex a
, tName = IM.insert (count a) i $ tName a
, tPos = IM.insert (count a) pos $ tPos a
, tArgs = IM.insert (count a) [] $ tArgs a
}
return (count a,pos)
Just j ->
let Just p = IM.lookup j $ tPos a
in errConflict i p pos
check
:: Abstractor (String,ExprPos) (Int,ExprPos)
check (i,pos) = do
a <- get
case SM.lookup i $ tIndex a of
Nothing -> errUnknown i pos
Just j -> return (j,pos)
abstractExpr
:: Abstractor (Expr String) (Expr Int)
abstractExpr e = case expr e of
BaseOtherwise -> return $ Expr BaseOtherwise $ srcPos e
BaseWild -> return $ Expr BaseWild $ srcPos e
BaseTrue -> return $ Expr BaseTrue $ srcPos e
BaseFalse -> return $ Expr BaseFalse $ srcPos e
BaseCon x -> return $ Expr (BaseCon x) $ srcPos e
BlnNot x -> lift' BlnNot x
NumSMin x -> lift' NumSMin x
NumSMax x -> lift' NumSMax x
NumSSize x -> lift' NumSSize x
NumSizeOf x -> lift' NumSizeOf x
LtlNext x -> lift' LtlNext x
LtlGlobally x -> lift' LtlGlobally x
LtlFinally x -> lift' LtlFinally x
NumPlus x y -> lift2' NumPlus x y
NumMinus x y -> lift2' NumMinus x y
NumMul x y -> lift2' NumMul x y
NumDiv x y -> lift2' NumDiv x y
NumMod x y -> lift2' NumMod x y
SetCup x y -> lift2' SetCup x y
SetCap x y -> lift2' SetCap x y
SetMinus x y -> lift2' SetMinus x y
BlnEQ x y -> lift2' BlnEQ x y
BlnNEQ x y -> lift2' BlnNEQ x y
BlnGE x y -> lift2' BlnGE x y
BlnGEQ x y -> lift2' BlnGEQ x y
BlnLE x y -> lift2' BlnLE x y
BlnLEQ x y -> lift2' BlnLEQ x y
BlnElem x y -> lift2' BlnElem x y
BlnOr x y -> lift2' BlnOr x y
BlnAnd x y -> lift2' BlnAnd x y
BlnImpl x y -> lift2' BlnImpl x y
BlnEquiv x y -> lift2' BlnEquiv x y
LtlRNext x y -> lift2' LtlRNext x y
LtlRGlobally x y -> lift2' LtlRGlobally x y
LtlRFinally x y -> lift2' LtlRFinally x y
LtlUntil x y -> lift2' LtlUntil x y
LtlWeak x y -> lift2' LtlWeak x y
LtlRelease x y -> lift2' LtlRelease x y
NumRPlus xs x -> cond NumRPlus xs x
NumRMul xs x -> cond NumRMul xs x
SetRCup xs x -> cond SetRCup xs x
SetRCap xs x -> cond SetRCap xs x
BlnROr xs x -> cond BlnROr xs x
BlnRAnd xs x -> cond BlnRAnd xs x
BaseId x -> do
(x',p) <- check (x,srcPos e)
return $ Expr (BaseId x') p
BaseBus x y -> do
(y',p) <- check (y,srcPos e)
x' <- abstractExpr x
return $ Expr (BaseBus x' y') p
BaseFml xs x -> do
(x',p) <- check (x,srcPos e)
xs' <- mapM abstractExpr xs
return $ Expr (BaseFml xs' x') p
SetExplicit xs -> do
xs' <- mapM abstractExpr xs
return $ Expr (SetExplicit xs') $ srcPos e
SetRange x y z -> do
x' <- abstractExpr x
y' <- abstractExpr y
z' <- abstractExpr z
return $ Expr (SetRange x' y' z') $ srcPos e
Colon v z -> case expr v of
Pattern x y -> do
a <- get
x' <- abstractExpr x
getPatternIds y
y' <- abstractExpr y
z' <- abstractExpr z
a' <- get
put $ a' { tIndex = tIndex a }
return $ Expr (Colon (Expr (Pattern x' y') (srcPos v)) z') (srcPos e)
_ -> lift2' Colon v z
Pattern x y -> lift2' Pattern x y
where
lift' c x = do
x' <- abstractExpr x
return $ Expr (c x') (srcPos e)
lift2' c x y = do
x' <- abstractExpr x
y' <- abstractExpr y
return $ Expr (c x' y') (srcPos e)
cond c xs x = do
a <- get
mapM_ add $ mapMaybe getId xs
xs' <- mapM abstractExpr xs
x' <- abstractExpr x
a' <- get
put $ a' { tIndex = tIndex a }
return $ Expr (c xs' x') (srcPos e)
getId x = case expr x of
BlnElem y _ -> isid y
BlnLE n _ -> range n
BlnLEQ n _ -> range n
_ -> Nothing
range n = case expr n of
BlnLE _ m -> isid m
BlnLEQ _ m -> isid m
_ -> Nothing
isid m = case expr m of
BaseId i -> Just (i,srcPos m)
_ -> Nothing
getPatternIds z = case expr z of
BaseWild -> return ()
BaseTrue -> return ()
BaseFalse -> return ()
BaseOtherwise -> return ()
BaseId i -> void $ add (i,srcPos z)
BlnNot x -> getPatternIds x
BlnOr x y -> mapM_ getPatternIds [x,y]
BlnAnd x y -> mapM_ getPatternIds [x,y]
BlnImpl x y -> mapM_ getPatternIds [x,y]
BlnEquiv x y -> mapM_ getPatternIds [x,y]
LtlNext x -> getPatternIds x
LtlRNext _ x -> getPatternIds x
LtlGlobally x -> getPatternIds x
LtlRGlobally _ x -> getPatternIds x
LtlFinally x -> getPatternIds x
LtlRFinally _ x -> getPatternIds x
LtlUntil x y -> mapM_ getPatternIds [x,y]
LtlWeak x y -> mapM_ getPatternIds [x,y]
LtlRelease x y -> mapM_ getPatternIds [x,y]
_ -> errPattern $ srcPos z