module Language.Sally.Types (
Name
, textFromName
, nameFromT
, nameFromS
, catNamesWith
, bangNames
, scoreNames
, nextName
, stateName
, inputName
, varFromName
, SallyBaseType(..)
, SallyConst(..)
, SallyState(..)
, SallyPred(..)
, SallyVar(..)
, SallyArith(..)
, SallyExpr(..)
, ToSallyExpr(..)
, SallyStateFormula(..)
, SallyLet
, SallyTransition(..)
, SallySystem(..)
, TrResult(..)
) where
import Data.Foldable (toList)
import Data.List (intersperse)
import Data.Ratio (numerator, denominator)
import Data.Sequence (Seq)
import Data.String
import Data.Text (Text)
import qualified Data.Text as T
import Text.PrettyPrint.ANSI.Leijen
import Language.Sally.SExpPP
newtype Name = Name { textFromName :: Text }
deriving (Show, Eq, Ord)
instance Pretty Name where
pretty = text . T.unpack . textFromName
instance ToSExp Name where
toSExp = SXBare . text . T.unpack . textFromName
nameFromS :: String -> Name
nameFromS = Name . T.pack
nameFromT :: Text -> Name
nameFromT = Name
instance IsString Name where
fromString = nameFromS
catNamesWith :: Text -> Name -> Name -> Name
catNamesWith sp a b = Name (textFromName a `T.append` sp `T.append` textFromName b)
bangNames :: Name -> Name -> Name
bangNames = catNamesWith "!"
scoreNames :: Name -> Name -> Name
scoreNames = catNamesWith "_"
nextName :: Name -> Name
nextName = catNamesWith "" "next."
stateName :: Name -> Name
stateName = catNamesWith "" "state."
inputName :: Name -> Name
inputName = catNamesWith "" "input."
data SallyConst = SConstBool Bool
| SConstInt Integer
| SConstReal Rational
deriving (Show, Eq)
instance ToSExp SallyConst where
toSExp (SConstBool b) = SXBare $ if b then text "true" else text "false"
toSExp (SConstInt x) =
let bare = SXBare $ integer x
in if x >= 0 then bare
else SXList [bare]
toSExp (SConstReal x) =
let nx = numerator x
dx = denominator x
in if dx == 1 then toSExp (SConstInt nx)
else SXList [ SXBare "/", toSExp (SConstInt nx)
, toSExp (SConstInt dx) ]
data SallyBaseType = SBool
| SInt
| SReal
deriving (Show, Eq)
instance ToSExp SallyBaseType where
toSExp SBool = bareText "Bool"
toSExp SInt = bareText "Int"
toSExp SReal = bareText "Real"
newtype SallyVar = SallyVar { textFromVar :: Text }
deriving (Show, Eq)
instance ToSExp SallyVar where
toSExp = SXBare . text . T.unpack . textFromVar
varFromName :: Name -> SallyVar
varFromName = SallyVar . textFromName
data SallyExpr = SELit SallyConst
| SEVar SallyVar
| SEPre SallyPred
| SEArith SallyArith
| SEMux SallyExpr SallyExpr SallyExpr
deriving (Show, Eq)
class ToSallyExpr a where
toSallyExpr :: a -> SallyExpr
instance ToSExp SallyExpr where
toSExp (SELit x) = SXBare (sxPretty x)
toSExp (SEVar x) = SXBare (sxPretty x)
toSExp (SEPre x) = toSExp x
toSExp (SEArith x) = toSExp x
toSExp (SEMux x y z) = SXList [bareText "ite", toSExp x, toSExp y, toSExp z]
data SallyPred = SPConst Bool
| SPExpr SallyExpr
| SPAnd (Seq SallyPred)
| SPOr (Seq SallyPred)
| SPImpl SallyPred SallyPred
| SPNot SallyPred
| SPEq SallyExpr SallyExpr
| SPLEq SallyExpr SallyExpr
| SPGEq SallyExpr SallyExpr
| SPLt SallyExpr SallyExpr
| SPGt SallyExpr SallyExpr
deriving (Show, Eq)
instance ToSExp SallyPred where
toSExp (SPConst x) = SXBare (text (if x then "true" else "false"))
toSExp (SPExpr x) = SXBare (sxPretty x)
toSExp (SPAnd xs) = SXList (bareText "and" : toList (fmap toSExp xs))
toSExp (SPOr xs) = SXList (bareText "or" : toList (fmap toSExp xs))
toSExp (SPImpl p q) = SXList [bareText "=>", toSExp p, toSExp q]
toSExp (SPNot p) = SXList [bareText "not", toSExp p]
toSExp (SPEq x y) = SXList [bareText "=", toSExp x, toSExp y]
toSExp (SPLEq x y) = SXList [bareText "<=", toSExp x, toSExp y]
toSExp (SPGEq x y) = SXList [bareText ">=", toSExp x, toSExp y]
toSExp (SPLt x y) = SXList [bareText "<", toSExp x, toSExp y]
toSExp (SPGt x y) = SXList [bareText "<", toSExp x, toSExp y]
data SallyArith = SAAdd SallyExpr SallyExpr
| SAMult SallyExpr SallyExpr
| SADiv SallyExpr SallyExpr
| SAExpr SallyExpr
deriving (Show, Eq)
instance ToSExp SallyArith where
toSExp (SAAdd x y) = SXList [bareText "+", toSExp x, toSExp y]
toSExp (SAMult x y) = SXList [bareText "*", toSExp x, toSExp y]
toSExp (SADiv x y) = SXList [bareText "/", toSExp x, toSExp y]
toSExp (SAExpr e) = toSExp e
data SallyState = SallyState
{ sName :: Name
, sVars :: [(Name, SallyBaseType)]
, sInVars :: [(Name, SallyBaseType)]
}
deriving (Show, Eq)
instance ToSExp SallyState where
toSExp SallyState {sName=sn, sVars=sv, sInVars=siv} =
SXList $ [ bareText "define-state-type"
, toSExp sn
, SXList $ map (\(n,t) -> SXList [toSExp n, toSExp t]) sv
] ++
(if null siv then []
else [SXList $ map (\(n,t) -> SXList [toSExp n, toSExp t]) siv])
data SallyStateFormula = SallyStateFormula
{ sfName :: Name
, sfDomain :: Name
, sfPred :: SallyPred
}
deriving (Show, Eq)
instance ToSExp SallyStateFormula where
toSExp SallyStateFormula {sfName=sn, sfDomain=sd, sfPred=sp} =
SXList [ bareText "define-states"
, toSExp sn
, toSExp sd
, toSExp sp
]
type SallyLet = (SallyVar, SallyExpr)
data SallyTransition = SallyTransition
{ traName :: Name
, traDom :: Name
, traLet :: [SallyLet]
, traPred :: SallyPred
}
deriving (Show, Eq)
instance ToSExp SallyTransition where
toSExp SallyTransition {traName=tn, traDom=td, traLet=tl, traPred=tp} =
SXList $ [ bareText "define-transition"
, toSExp tn
, toSExp td
] ++
(if null listOfBinds then [toSExp tp]
else [SXList [bareText "let", SXList listOfBinds, toSExp tp]])
where
listOfBinds = map (\(v,e) -> SXList [toSExp v, toSExp e]) tl
data SallySystem = SallySystem
{ sysNm :: Name
, sysSN :: Name
, sysISN :: Name
, sysTN :: Name
}
deriving (Show, Eq)
instance ToSExp SallySystem where
toSExp ss = SXList [ bareText "define-transition-system"
, toSExp (sysNm ss)
, toSExp (sysSN ss)
, toSExp (sysISN ss)
, toSExp (sysTN ss)
]
data TrResult = TrResult
{ tresState :: SallyState
, tresFormulas :: [SallyStateFormula]
, tresConsts :: [SallyConst]
, tresInit :: SallyStateFormula
, tresTrans :: [SallyTransition]
, tresSystem :: SallySystem
}
deriving (Show, Eq)
instance Pretty TrResult where
pretty tr = vcat [ consts_comment
, consts
, state_comment
, sxPretty (tresState tr)
] <$$>
vcat (formulas_comment : intersperse
sallyCom
(map sxPretty (tresFormulas tr))) <$$>
vcat [ init_comment
, sxPretty (tresInit tr)
] <$$>
vcat (trans_comment : intersperse
sallyCom
(map sxPretty (tresTrans tr))) <$$>
vcat (system_comment : [sxPretty (tresSystem tr)])
where
consts = if null (tresConsts tr) then text ";; NONE"
else vcat (map sxPretty (tresConsts tr))
consts_comment = sallyCom <+> text "Constants"
state_comment = linebreak <> sallyCom <+> text "State type"
init_comment = linebreak <> sallyCom <+> text "Initial State"
formulas_comment = linebreak <> sallyCom <+> text "State Formulas"
trans_comment = linebreak <> sallyCom <+> text "Transitions"
system_comment = linebreak <> sallyCom <+> text "System Definition"