language-eiffel-0.1.2: Language/Eiffel/Util.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE OverloadedStrings #-}
module Language.Eiffel.Util where
import Control.Applicative hiding (getConst)
import Control.Monad
import Control.Lens hiding (from, lens)
import Data.Maybe
import qualified Data.HashMap.Strict as Map
import qualified Data.Text as Text
import Data.Text (Text)
import Language.Eiffel.Syntax
-- Class level utilities
-- | A 'Feature' can provide its name, arguments, contract, etc.
class Feature a expr | a -> expr where
-- | The name of the feature.
featureName :: a -> Text
-- | Argument declarations.
featureArgs :: a -> [Decl]
-- | Result type.
featureResult :: a -> Typ
-- | Precondition.
featurePre :: a -> [Clause expr]
-- | Postconditions.
featurePost :: a -> [Clause expr]
-- | Whether the feature is frozen (can't be redefined).
featureIsFrozen :: a -> Bool
-- | Transform the feature given a renaming clause.
featureRename :: a -> RenameClause -> a
-- | An existential type to aggregate
-- all features (routines, attributes, constants) together.
data FeatureEx expr =
-- | Wrap the 'Feature' in the existential type.
forall a. Feature a expr => FeatureEx a
instance Feature (FeatureEx expr) expr where
featureName (FeatureEx f) = featureName f
featureArgs (FeatureEx f) = featureArgs f
featureResult (FeatureEx f) = featureResult f
featurePre (FeatureEx f) = featurePre f
featurePost (FeatureEx f) = featurePost f
featureIsFrozen (FeatureEx f) = featureIsFrozen f
featureRename (FeatureEx f) = FeatureEx . featureRename f
-- | Wrap up SomeFeature
wrapSomeFeature :: (forall f . Feature f expr => f -> b)
-> SomeFeature body expr
-> b
wrapSomeFeature f (SomeRoutine r) = f r
wrapSomeFeature f (SomeAttr a) = f a
wrapSomeFeature f (SomeConst c) = f c
instance Feature (SomeFeature body expr) expr where
featureName = wrapSomeFeature featureName
featureArgs = wrapSomeFeature featureArgs
featureResult = wrapSomeFeature featureResult
featurePre = wrapSomeFeature featurePre
featurePost = wrapSomeFeature featurePost
featureIsFrozen = wrapSomeFeature featureIsFrozen
featureRename (SomeRoutine rout) r = SomeRoutine (featureRename rout r)
featureRename (SomeAttr attr) r = SomeAttr (featureRename attr r)
featureRename (SomeConst c) r = SomeConst (featureRename c r)
instance Feature (AbsRoutine body expr) expr where
featureName = routineName
featureArgs = routineArgs
featureResult = routineResult
featurePre = contractClauses . routineReq
featurePost = contractClauses . routineEns
featureIsFrozen = routineFroz
featureRename rout r@(Rename orig new alias)
| routineName rout == orig = rout { routineName = new
, routineAlias = alias
, routineArgs = newArgs
}
| otherwise = rout {routineArgs = newArgs}
where newArgs = map (renameDecl r) (routineArgs rout)
instance Feature (Attribute expr) expr where
featureName = declName . attrDecl
featureArgs = const []
featureResult = declType . attrDecl
featurePre = contractClauses . attrReq
featurePost = contractClauses . attrEns
featureIsFrozen = attrFroz
featureRename attr r =
attr {attrDecl = renameDecl r (attrDecl attr)}
instance Feature (Constant expr) expr where
featureName = declName . constDecl
featureArgs = const []
featureResult = declType . constDecl
featurePre _ = []
featurePost _ = []
featureIsFrozen = constFroz
featureRename constant r =
constant {constDecl = renameDecl r (constDecl constant)}
-- | A way to extract each type of feature from a class.
class Feature a expr => ClassFeature a body expr | a -> expr, a -> body where
-- | A list of all this class' features of the given type.
allFeatures :: AbsClas body expr -> [a]
-- | Find this kind of feature in a class
findFeature :: AbsClas body expr -> Text -> Maybe a
instance ClassFeature (Constant expr) body expr where
findFeature = findFeature' toConstMb
allFeatures = allConstants
instance ClassFeature (AbsRoutine body expr) body expr where
findFeature = findFeature' toRoutineMb
allFeatures = allRoutines
instance ClassFeature (Attribute expr) body expr where
findFeature = findFeature' toAttrMb
allFeatures = allAttributes
instance ClassFeature (FeatureEx expr) body expr where
allFeatures clas = map FeatureEx (allAttributes clas) ++
map FeatureEx (allRoutines clas) ++
map FeatureEx (allConstants clas)
findFeature = findFeature' (Just . FeatureEx)
findFeature' :: (SomeFeature body expr -> Maybe a)
-> AbsClas body expr
-> Text
-> Maybe a
findFeature' from cls name = join $ from <$> findSomeFeature cls name
-- | Convert a constant into an attribute.
constToAttr :: Constant exp -> Attribute Expr
constToAttr (Constant froz d _) =
Attribute froz d Nothing [] (Contract False []) (Contract False [])
-- * Extracting data from a class.
-- | Fetch attributes from all feature clauses.
allAttributes = allHelper fmAttrs
-- | Fetch routines from all feature clauses.
allRoutines = allHelper fmRoutines
-- | Fetch contants from all feature clauses.
allConstants = allHelper fmConsts
-- Help for above 'all' functions
allHelper lens =
map (view exportFeat) . Map.elems . view lens . featureMap
-- | Fetch creation routines from all feature clauses.
allCreates = concatMap createNames . creates
-- | Fetch attribute declarations from all feature clauses.
allAttributeDecls = map attrDecl . allAttributes
-- | Fetch constant declarations from all feature clauses.
allConstantDecls = map constDecl . allConstants
-- | All inheritance clauses.
allInherited = concatMap inheritClauses . inherit
-- | All inherited classes, as types.
allInheritedTypes = map inheritClass . allInherited
-- | Determine if a name is in the creation clause of a class.
isCreateName n c = n `elem` allCreates c
-- * 'SomeFeature' predicates, extractors.
toRoutineMb (SomeRoutine r) = Just r
toRoutineMb _ = Nothing
toAttrMb (SomeAttr r) = Just r
toAttrMb _ = Nothing
toConstMb (SomeConst r) = Just r
toConstMb _ = Nothing
-- isRoutine (SomeRoutine _) = True
-- isRoutine _ = False
-- isAttr (SomeAttr _) = True
-- isAttr _ = False
-- isConst (SomeConst _) = True
-- isConst _ = False
-- getRoutine (SomeRoutine r) = r
-- getAttr (SomeAttr a) = a
-- getConst (SomeConst c) = c
-- onlyRoutine f (SomeRoutine a) = SomeRoutine (f a)
-- onlyRoutine _f other = other
-- onlyAttr f (SomeAttr a) = SomeAttr (f a)
-- onlyAttr _f other = other
-- onlyConst f (SomeConst a) = SomeConst (f a)
-- onlyConst _f other = other
-- onlyRoutineM f (SomeRoutine a) = SomeRoutine <$> f a
-- onlyRoutineM f other = pure other
-- onlyAttrM :: Applicative m
-- => (Attribute exp -> m (Attribute exp))
-- -> SomeFeature body exp
-- -> m (SomeFeature body exp)
-- onlyAttrM f (SomeAttr a) = SomeAttr <$> f a
-- onlyAttrM f other = pure other
-- onlyConstM f (SomeConst a) = SomeConst (f a)
-- onlyConstM f other = other
-- * Class modification
-- ** Setting members of a class.
-- | Set the feature clause of a class.
updFeatureMap :: AbsClas body exp -> FeatureMap body exp -> AbsClas body exp
updFeatureMap c featMap = c {featureMap = featMap}
-- | Update a routine body.
updFeatBody :: RoutineBody a -> PosAbsStmt b -> RoutineBody b
updFeatBody impl body = impl {routineBody = body}
-- ** Mapping features of a class
-- | These functions will update a class or feature clause with a transformation
-- function.
-- | Map a transformation function over the routines in a class, replacing the
-- old routines with the transformed versions within a feature clause.
-- mapRoutines f = Map.map (over exportFeat (onlyRoutine f))
-- | Monadic version of 'mapRoutines'.
mapRoutinesM :: (Applicative m, Monad m) =>
(AbsRoutine body exp -> m (AbsRoutine body exp)) ->
FeatureMap body exp ->
m (FeatureMap body exp)
mapRoutinesM f = mapMOf (fmRoutines.traverse.exportFeat) f
-- | Map a transformation function over the attributes in a class,
-- replacing the old attributes with the transformed versions within a feature clause.
mapAttributes :: (Attribute exp -> Attribute exp)
-> FeatureMap body exp
-> FeatureMap body exp
mapAttributes f = over (fmAttrs.traverse.exportFeat) f
-- | Monadic version of 'mapAttributes'.
mapAttributesM :: (Monad m, Applicative m) =>
(Attribute exp -> m (Attribute exp)) ->
FeatureMap body exp ->
m (FeatureMap body exp)
mapAttributesM f = mapMOf (fmAttrs.traverse.exportFeat) f
-- | Map a transformation function over the constants in a class, replacing the
-- old constants with the transformed versions within a feature clause.
-- mapConstants f = Map.map (over exportFeat (onlyConst f))
-- | Map a transformation function over the contracts in a class, replacing the
-- old contracts with the transformed versions within a feature clause.
mapContract clauseF cs =
cs { contractClauses = map clauseF (contractClauses cs)}
-- | Map a transformation function over all expressions in a class.
-- A transformation for features, constants, and attributes must be given
-- as if the type of expressions changes (ie, with a typecheck) then
-- all expressions types must change together.
mapExprs :: (AbsRoutine body exp -> AbsRoutine body' exp')
-> (Constant exp -> Constant exp')
-> (Clause exp -> Clause exp')
-> FeatureMap body exp
-> FeatureMap body' exp'
mapExprs routF constF clauseF fm =
FeatureMap (mapUpd routF fmRoutines)
(mapUpd updAttr fmAttrs)
(mapUpd constF fmConsts)
where
updAttr a = a { attrEns = mapContract clauseF (attrEns a)
, attrReq = mapContract clauseF (attrReq a)
}
mapUpd f lens = Map.map (over exportFeat f) (view lens fm)
-- | Map a transformation function over the attributes in a class, replacing the
-- old attributes with the transformed versions within a class.
classMapAttributes f c =
c {featureMap = mapAttributes f (featureMap c)}
-- | Monadic version of 'classMapAttributes'.
classMapAttributesM :: (Applicative m, Monad m) =>
(Attribute exp -> m (Attribute exp)) ->
AbsClas body exp ->
m (AbsClas body exp)
classMapAttributesM f c = do
fm <- mapAttributesM f (featureMap c)
return (c {featureMap = fm})
-- | Map a transformation function over the routines in a class, replacing the
-- old routines with the transformed versions within a class.
classMapRoutines :: (AbsRoutine body exp -> AbsRoutine body exp)
-> AbsClas body exp -> AbsClas body exp
classMapRoutines f c =
c {featureMap = over (fmRoutines.traverse.exportFeat) f (featureMap c)}
-- | Monadic version of 'classMapRoutines'.
classMapRoutinesM :: (Applicative m, Monad m) =>
(AbsRoutine body exp -> m (AbsRoutine body exp)) ->
AbsClas body exp ->
m (AbsClas body exp)
classMapRoutinesM f c = do
fm <- mapRoutinesM f (featureMap c)
return (c {featureMap = fm})
-- | Map a transformation function over the constants in a class, replacing the
-- old constants with the transformed versions within a class.
classMapConstants f c =
c {featureMap = over (fmConsts.traverse.exportFeat) f (featureMap c)}
-- | Map a transformation function over all expressions in a class.
-- A transformation for features, constants, and attributes must be given
-- as if the type of expressions changes (ie, with a typecheck) then
-- all expressions types must change together. This is performed on every
-- feature clause in a class.
classMapExprs :: (AbsRoutine body exp -> AbsRoutine body' exp')
-> (Clause exp -> Clause exp')
-> (Constant exp -> Constant exp')
-> AbsClas body exp -> AbsClas body' exp'
classMapExprs featrF clauseF constF c =
c { featureMap = mapExprs featrF constF clauseF (featureMap c)
, invnts = map clauseF (invnts c)
}
-- * Interface construction
-- | Strip the body from a routine.
makeRoutineIs :: SomeFeature body Expr -> SomeFeature EmptyBody Expr
makeRoutineIs (SomeRoutine r) = SomeRoutine (makeRoutineI r)
makeRoutineIs (SomeAttr a) = SomeAttr a
makeRoutineIs (SomeConst c) = SomeConst c
-- | Strip the contracts from an attribute.
makeAttributeI :: Attribute exp -> Attribute Expr
makeAttributeI (Attribute froz decl assgn notes _ _) =
Attribute froz decl assgn notes (Contract False []) (Contract False [])
-- | Strip the bodies from all features.
clasInterface :: AbsClas body Expr -> ClasInterface
clasInterface c =
c { featureMap = over (fmRoutines.traverse.exportFeat)
(makeRoutineI)
(featureMap c)
}
-- | Strip the bodies and rescue clause from a routine.
makeRoutineI :: AbsRoutine body Expr -> RoutineI
makeRoutineI f = f { routineImpl = EmptyBody
, routineRescue = Nothing}
-- * Map construction
-- | Turn a list of classes into a map indexed by the class names.
clasMap :: [AbsClas body exp] -> Map ClassName (AbsClas body exp)
clasMap = Map.fromList . map (\ c -> (className c, c))
-- | Extract a map of attribute names to types given a class.
attrMap :: AbsClas body exp -> Map Text Typ
attrMap = declsToMap . map attrDecl . allAttributes
-- * Search
-- | Find a routine in a class.
findRoutine :: Clas -> Text -> Maybe Routine
findRoutine = findFeature
-- | Find an operator (symbol sequence) in a class.
findOperator :: AbsClas body Expr -> Text -> Int ->
Maybe (AbsRoutine body Expr)
findOperator c opName numArgs =
let fs = allRoutines c
ffs = filter (\ rout -> routineAlias rout == Just opName &&
length (routineArgs rout) == numArgs) fs
in listToMaybe ffs
-- -- | Find a 'ClassFeature'.
-- findFeature :: ClassFeature a body expr =>
-- AbsClas body expr -> Text -> Maybe a
-- findFeature clasInt name =
-- let fs = filter (\f -> Text.map toLower (featureName f) == Text.map toLower name)
-- (allFeatures clasInt)
-- in listToMaybe fs
-- | Find the sum-type for all features.
findSomeFeature :: AbsClas body expr -> Text -> Maybe (SomeFeature body expr)
findSomeFeature cls name =
lkup fmRoutines SomeRoutine <|>
lkup fmAttrs SomeAttr <|>
lkup fmConsts SomeConst
where
lkup lens cast = cast <$>
view exportFeat <$>
Map.lookup nameLow (view lens featMap)
featMap = featureMap cls
nameLow = Text.toLower name
-- | Find an existential 'FeatureEx'.
findFeatureEx :: AbsClas body expr -> Text -> Maybe (FeatureEx expr)
findFeatureEx = findFeature
-- | Find a routine by name.
findRoutineInt :: ClasInterface -> Text -> Maybe RoutineI
findRoutineInt = findFeature
-- | Find an attribute in a class by name.
findAttrInt :: AbsClas body expr -> Text -> Maybe (Attribute expr)
findAttrInt = findFeature
-- | Find a constant by name in a class.
findConstantInt :: AbsClas body Expr -> Text -> Maybe (Constant Expr)
findConstantInt = findFeature
-- | Given a class and a routine, given a unique name.
fullName :: AbsClas body exp -> RoutineI -> Text
fullName c f = fullNameStr (className c) (routineName f)
-- | Given to string construct a unique combination.
fullNameStr :: Text -> Text -> Text
fullNameStr cName fName = Text.concat ["__", cName, "_", fName]
-- | Given a class, create a list of generic classes for the formal generic
-- parameters of the class.
genericStubs :: AbsClas body exp -> [AbsClas body' exp']
genericStubs = map makeGenericStub . generics
-- | Given a generic, construct a class for the generic.
makeGenericStub :: Generic -> AbsClas body exp
makeGenericStub (Generic g constrs _) =
AbsClas { deferredClass = False
, frozenClass = False
, expandedClass = False
, classNote = []
, className = g
, currProc = Dot
, procGeneric = []
, obsoleteClass = False
, procExpr = []
, generics = []
, inherit = [Inheritance False $ map simpleInherit constrs]
, creates = []
, converts = []
, featureMap = FeatureMap Map.empty Map.empty Map.empty
, invnts = []
}
where
simpleInherit t = InheritClause t [] [] [] [] []
-- * Inheritance utilities
-- | Rename a declaration.
renameDecl :: RenameClause -> Decl -> Decl
renameDecl r@(Rename orig new _) (Decl n t)
| n == orig = Decl new t'
| otherwise = Decl n t'
where
t' = renameType r t
-- | Rename a type, in the case of a like-type.
renameType r (ClassType n ts) = ClassType n (map (renameType r) ts)
renameType (Rename orig new _) (Like i)
| i == orig = Like new
| otherwise = Like i
renameType r t = error $ "renameType: rename " ++ show r ++
" in type: " ++ show t
-- | Rename everything in a class.
renameAll :: [RenameClause] -> AbsClas body exp -> AbsClas body exp
renameAll renames cls = renamed
where
renamed = foldr renameClass cls renames
renameKey (Rename old new _aliasMb) k
| k == Text.toLower old = new
| otherwise = k
renameKeys r c = c { featureMap = fmMapKeys (renameKey r) (featureMap c)}
renameClass r = renameKeys r .
classMapConstants (flip featureRename r) .
classMapAttributes (flip featureRename r) .
classMapRoutines (flip featureRename r)
-- | Undefine a single feature in a class.
undefineName :: Text -> AbsClas body exp -> AbsClas body exp
undefineName name cls =
cls { featureMap = fmKeyFilter (/= name) (featureMap cls)}
-- | Undefine every specified name for a class.
undefineAll :: InheritClause -> AbsClas body exp -> AbsClas body exp
undefineAll inh cls = foldr undefineName cls (undefine inh)
-- | Specifies whether a class can be merged with another.
mergeableClass :: AbsClas body exp -> Bool
mergeableClass _clas = True -- null (generics clas) -- && null (inherit clas)
-- | Merge two classes, combining invariants and feature clauses.
mergeClass :: AbsClas body exp -> AbsClas body exp -> AbsClas body exp
mergeClass class1 class2
| mergeableClass class1 && mergeableClass class2 =
class1 { invnts = invnts class1 ++ invnts class2
, featureMap = featureMap class1 `fmUnion` featureMap class2
}
| otherwise = error $ "mergeClasses: classes not mergeable " ++
show (className class1, className class2)
-- | Merge a list of classes.
mergeClasses :: [AbsClas body exp] -> AbsClas body exp
mergeClasses = foldr1 mergeClass
-- * Feature Map functions
fmMapKeys :: (Text -> Text) -> FeatureMap body exp -> FeatureMap body exp
fmMapKeys f = fmKeyMap fmRoutines . fmKeyMap fmAttrs . fmKeyMap fmConsts
where
fmKeyMap setter = over setter mapKeys
mapKeys :: Map Text v -> Map Text v
mapKeys = Map.fromList . map (\(k,v) -> (f k, v)) . Map.toList
fmKeyFilter :: (Text -> Bool)
-> FeatureMap body exp
-> FeatureMap body exp
fmKeyFilter p = fmFilt fmRoutines . fmFilt fmAttrs . fmFilt fmConsts
where
fmFilt setter = over setter filt
filt = Map.filterWithKey (\ k _v -> p k)
fmUnion
:: FeatureMap body exp
-> FeatureMap body exp
-> FeatureMap body exp
fmUnion fm1 fm2 =
FeatureMap
(Map.union (view fmRoutines fm1) (view fmRoutines fm2))
(Map.union (view fmAttrs fm1) (view fmAttrs fm2))
(Map.union (view fmConsts fm1) (view fmConsts fm2))
fmEmpty = FeatureMap Map.empty Map.empty Map.empty
fmUnions = foldr fmUnion fmEmpty
-- * Routine level utilities
-- | Construct a map from a routine's arguments.
argMap :: RoutineWithBody a -> Map Text Typ
argMap = declsToMap . routineArgs
-- | Construct a map from a routine's declarations.
localMap :: RoutineWithBody a -> Map Text Typ
localMap = declsToMap . routineDecls
-- | Give the declarations of a routine's locals.
routineDecls :: AbsRoutine (RoutineBody exp1) exp -> [Decl]
routineDecls r =
case routineImpl r of
RoutineDefer -> []
RoutineExternal _ _ -> []
body -> routineLocal body
-- Operator utilities
-- | Operator aliases for user-level operators, ie, not including
-- =, /=, ~, and /~
opAlias :: BinOp -> Text
opAlias Add = "+"
opAlias Sub = "-"
opAlias Mul = "*"
opAlias Div = "/"
opAlias Quot = "//"
opAlias Rem = "\\"
opAlias Pow = "^"
opAlias And = "and"
opAlias AndThen = "and then"
opAlias Or = "or"
opAlias OrElse = "or else"
opAlias Xor = "xor"
opAlias Implies = "implies"
opAlias (SymbolOp o) = o
opAlias (RelOp o _) = rel o
where
rel Lte = "<="
rel Lt = "<"
rel Gt = ">"
rel Gte = ">="
rel relOp = error $ "opAlias: non user-level operator " ++ show relOp
-- | Test if the binary operator is an equality operator.
equalityOp :: BinOp -> Bool
equalityOp (RelOp Eq _) = True
equalityOp (RelOp Neq _) = True
equalityOp (RelOp TildeEq _) = True
equalityOp (RelOp TildeNeq _) = True
equalityOp _ = False
-- | Unary operator aliases for everything except `old'.
unOpAlias Not = "not"
unOpAlias Neg = "-"
unOpAlias Old = "unOpAlias: `old' is not a user-operator."
-- * Type utilities
-- | Convert a class into its type.
classToType :: AbsClas body exp -> Typ
classToType clas = ClassType (className clas) (map genType (generics clas))
where genType g = ClassType (genericName g) []
-- | Whether a type is basic (where basic meaning its an integer, natural, real or boolean).
isBasic :: Typ -> Bool
isBasic t = any ($ t) [isBooleanType, isIntegerType, isNaturalType, isRealType, isCharType]
-- | A list of the number of integer bits (8, 16, ...)
intBits :: [Integer]
intBits = [8, 16, 32, 64]
-- | The bounds on the range of values a integer or natural type can take.
typeBounds :: Typ -> (Integer, Integer)
typeBounds (ClassType n []) = fromJust $ lookup n wholeMap
where
intMap = zip integerTypeNames
(map (\bits -> let half = bits `quot` 2
in (- 2^half, 2^half - 1)) intBits)
natMap = zip naturalTypeNames
(map (\bits -> (0, 2^bits - 1)) intBits)
wholeMap = intMap ++ natMap
typeBounds t = error $ "typeBounds: won't work on " ++ show t
-- | Boolean type test.
isBooleanType :: Typ -> Bool
isBooleanType = (== "BOOLEAN") . classNameType
-- | Integer type test.
isIntegerType :: Typ -> Bool
isIntegerType = isInTypeNames integerTypeNames
-- | Natural number type test.
isNaturalType :: Typ -> Bool
isNaturalType = isInTypeNames naturalTypeNames
-- | Real number type test.
isRealType :: Typ -> Bool
isRealType = isInTypeNames realTypeNames
-- | Character type test.
isCharType :: Typ -> Bool
isCharType = isInTypeNames charTypeNames
isInTypeNames names (ClassType name _) = name `elem` names
isInTypeNames _ _ = False
-- | List of integer type names (ie, INTEGER_32).
integerTypeNames :: [Text]
integerTypeNames = map ((Text.append "INTEGER_") . Text.pack . show) intBits
-- | List of integer type names (ie, NATURAL_32).
naturalTypeNames :: [Text]
naturalTypeNames = map ((Text.append "NATURAL_") . Text.pack . show) intBits
-- | List of integer type names (ie, REAL_64).
realTypeNames :: [Text]
realTypeNames = ["REAL_32", "REAL_64"]
-- | List of integer type names (ie, CHARACTER_8).
charTypeNames :: [Text]
charTypeNames = ["CHARACTER_8", "CHARACTER_32"]
-- | Given a type give the name of the class as a string.
classNameType :: Typ -> Text
classNameType (ClassType cn _) = cn
classNameType (Sep _ _ cn) = cn
classNameType t = error $ "Non-class type " ++ show t
-- | The default integer type.
intType :: Typ
intType = namedType "INTEGER_32"
-- | The default boolean type.
boolType :: Typ
boolType = namedType "BOOLEAN"
-- | The default real number type.
realType :: Typ
realType = namedType "REAL_64"
-- | The default character type.
charType :: Typ
charType = namedType "CHARACTER_8"
-- | The default string type.
stringType :: Typ
stringType = namedType "STRING_8"
-- | The top type, ANY.
anyType :: Typ
anyType = namedType "ANY"
-- | Construct a simple type from a classname.
namedType :: ClassName -> Typ
namedType name = ClassType name []
-- * Declaration
-- | Insert a declaration into a string-type map.
insertDecl :: Decl -> Map Text Typ -> Map Text Typ
insertDecl (Decl s t) = Map.insert s t
-- | Turn a list of declarations into a string-type map.
declsToMap :: [Decl] -> Map Text Typ
declsToMap = foldr insertDecl Map.empty
-- * SCOOP utilities
-- | Given a processor declaration, extract the processor.
newVar :: ProcDecl -> Proc
newVar (SubTop p) = p
newVar (CreateLessThan p _) = p