module Writer.Utils
( printFormula
, checkLower
, merge
, adjust
) where
import Data.Maybe
( mapMaybe
)
import Data.Char
( toLower
)
import Config
( Configuration(..)
)
import Data.Types
( SignalDecType(..)
)
import Data.LTL
( Atomic(..)
, Formula(..)
, fNot
)
import Data.SymbolTable
( IdRec(..)
)
import Data.Specification
( Specification(..)
)
import Writer.Error
( Error
, errToLower
)
import Writer.Data
( WriteMode(..)
, OperatorConfig(..)
, UnaryOperator(..)
, BinaryOperator(..)
, Assoc(..)
, Unsupported(..)
)
import Data.Array.IArray
( (!)
)
printFormula
:: OperatorConfig -> WriteMode -> Formula -> String
printFormula opc mode formula = reverse $ case mode of
Pretty -> pr [] formula
Fully -> parens pr [] formula
where
parens c a x = ')' : c ('(':a) x
pr' a y r x = case mode of
Fully -> parens pr a x
Pretty -> case compare (precedence' y) (precedence' x) of
LT -> parens pr a x
GT -> pr a x
EQ -> case (assoc' y, r) of
(AssocRight, False) -> parens pr a x
(AssocRight, True) -> pr a x
(_, False) -> pr a x
(_, True) -> parens pr a x
pr a f = case f of
TTrue -> revappend a ttrue
FFalse -> revappend a ffalse
Atomic (Input x) -> revappend a x
Atomic (Output x) -> revappend a x
Not x -> pr' (unOp opnot a) f False x
And [] -> pr a TTrue
And [x] -> pr a x
And [x,y] -> pr' (binOp opand $ pr' a f False x) f True y
And (x:y:xr) -> case assoc' f of
AssocRight -> pr' (binOp opand $ pr' a f False x) f True $ And (y:xr)
_ -> pr a $ And $ And [x,y] : xr
Or [] -> pr a FFalse
Or [x] -> pr a x
Or [x,y] -> pr' (binOp opor $ pr' a f False x) f True y
Or (x:y:xr) -> case assoc' f of
AssocRight -> pr' (binOp opor $ pr' a f False x) f True $ Or (y:xr)
_ -> pr a $ Or $ Or [x,y] : xr
Implies x y -> pr' (binOp opimplies $ pr' a f False x) f True y
Equiv x y -> pr' (binOp opequiv $ pr' a f False x) f True y
Next x -> pr' (unOp opnext a) f True x
Globally x -> pr' (unOp opglobally a) f True x
Finally x -> pr' (unOp opfinally a) f True x
Until x y -> pr' (binOp opuntil $ pr' a f False x) f True y
Release x y -> pr' (binOp oprelease $ pr' a f False x) f True y
Weak x y -> pr' (binOp opweak $ pr' a f False x) f True y
precedence' f = case f of
TTrue -> 0
FFalse -> 0
Atomic {} -> 0
Not {} -> dp + uopPrecedence opnot
And {} -> dp + bopPrecedence opand
Or {} -> dp + bopPrecedence opor
Implies {} -> dp + bopPrecedence opimplies
Equiv {} -> dp + bopPrecedence opequiv
Next {} -> dp + uopPrecedence opnext
Globally {} -> dp + uopPrecedence opglobally
Finally {} -> dp + uopPrecedence opfinally
Until {} -> dp + bopPrecedence opuntil
Release {} -> dp + bopPrecedence oprelease
Weak {} -> dp + bopPrecedence opweak
assoc' f = case f of
TTrue -> AssocLeft
FFalse -> AssocLeft
Atomic {} -> AssocLeft
Not {} -> AssocLeft
And {} -> bopAssoc opand
Or {} -> bopAssoc opor
Implies {} -> bopAssoc opimplies
Equiv {} -> bopAssoc opequiv
Next {} -> AssocLeft
Globally {} -> AssocLeft
Finally {} -> AssocLeft
Until {} -> bopAssoc opuntil
Release {} -> bopAssoc oprelease
Weak {} -> bopAssoc opweak
binOp op a = ' ' : revappend (' ' : a) (bopName op)
unOp op a = ' ' : revappend a (uopName op)
uopPrecedence' x =
if unsupported x
then Nothing
else Just $ uopPrecedence x
bopPrecedence' x =
if unsupported x
then Nothing
else Just $ bopPrecedence x
dp =
let
xs = mapMaybe (\f -> f opc)
[ uopPrecedence' . opNot
, bopPrecedence' . opAnd
, bopPrecedence' . opOr
, bopPrecedence' . opImplies
, bopPrecedence' . opEquiv
, uopPrecedence' . opNext
, uopPrecedence' . opFinally
, uopPrecedence' . opGlobally
, bopPrecedence' . opUntil
, bopPrecedence' . opRelease
, bopPrecedence' . opWeak
]
m = foldl min 1 xs
in if m > 0
then 0
else 1 m
ttrue = tTrue opc
ffalse = fFalse opc
opnot = opNot opc
opand = opAnd opc
opor = opOr opc
opimplies = opImplies opc
opequiv = opEquiv opc
opnext = opNext opc
opfinally = opFinally opc
opglobally = opGlobally opc
opuntil = opUntil opc
oprelease = opRelease opc
opweak = opWeak opc
revappend a xs = case xs of
[] -> a
(x:xr) -> revappend (x:a) xr
merge
:: [Formula] -> [Formula] -> [Formula] ->
[Formula] -> [Formula] -> [Formula] -> Either Error Formula
merge es ss rs as is gs =
let
fmle = case (rs,as) of
([],[]) -> TTrue
([],[x]) -> x
([],_) -> And as
([x],[]) -> Globally x
([x],[y]) -> And [Globally x,y]
([x],_) -> And (Globally x : as)
(_,[]) -> Globally $ And rs
(_,[x]) -> And [Globally $ And rs, x]
(_,_) -> And ((Globally $ And rs) : as)
fmls = case (is,gs) of
([],[]) -> TTrue
([],[x]) -> x
([],_) -> And gs
([x],[]) -> Globally x
([x],[y]) -> And [Globally x,y]
([x],_) -> And (Globally x : gs)
(_,[]) -> Globally $ And is
(_,[x]) -> And [Globally $ And is, x]
(_,_) -> And ((Globally $ And is) : gs)
fmli = case (fmle, fmls) of
(FFalse,_) -> TTrue
(TTrue,x) -> x
(x,FFalse) -> fNot x
(_,TTrue) -> TTrue
_ -> Implies fmle fmls
fmlc = case (ss,fmli) of
([],_) -> fmli
(_,FFalse) -> FFalse
([x],TTrue) -> x
(xs, TTrue) -> And xs
_ -> And (ss ++ [fmli])
fmlf = case (es,fmlc) of
([],_) -> fmlc
([x],FFalse) -> fNot x
(xs,FFalse) -> Or $ map fNot xs
(_,TTrue) -> TTrue
([x],_) -> Implies x fmlc
_ -> Implies (And es) fmlc
in
return fmlf
checkLower
:: String -> Specification -> Either Error ()
checkLower fmt s =
let
ids = map ident (inputs s) ++
map ident (outputs s)
names = map (idName . (symboltable s !)) ids
lnames = map (map toLower) names
znames = zip3 ids names lnames
in
checkDouble znames
where
ident x = case x of
SDSingle (y,_) -> y
SDBus (y,_) _ -> y
SDEnum (y,_) _ -> y
checkDouble xs = case xs of
[] -> return ()
[_] -> return ()
((i,a,b):(x,c,d):xr) ->
if b == d
then errToLower fmt a c $ idPos $ symboltable s ! i
else checkDouble ((x,c,d) : xr)
adjust
:: Configuration -> OperatorConfig -> Configuration
adjust c oc =
c {
noRelease = noRelease c || unsupported (opRelease oc),
noWeak = noWeak c || unsupported (opWeak oc),
noGlobally = noGlobally c || unsupported (opGlobally oc),
noFinally = noFinally c || unsupported (opFinally oc)
}