mulang-4.4.0: src/Language/Mulang/Inspector/Generic.hs
module Language.Mulang.Inspector.Generic (
assigns,
calls,
declares,
declaresComputation,
declaresComputationWithArity,
declaresComputationWithArity',
declaresEntryPoint,
declaresFunction,
declaresRecursively,
declaresVariable,
delegates,
delegates',
parses,
raises,
rescues,
uses,
usesAnonymousVariable,
usesExceptionHandling,
usesExceptions,
usesFor,
usesIf,
usesYield) where
import Language.Mulang.Ast
import Language.Mulang.Generator (declaredIdentifiers, expressions, declarations, referencedIdentifiers)
import Language.Mulang.Identifier
import Language.Mulang.Inspector.Bound (containsBoundDeclaration, BoundInspection)
import Language.Mulang.Inspector.Contextualized (decontextualize, ContextualizedBoundInspection)
import Language.Mulang.Inspector.Primitive
import Language.Mulang.Inspector.Query (inspect, select)
import Data.Maybe (listToMaybe)
import Data.List.Extra (has)
-- | Inspection that tells whether an expression is equal to a given piece of code after being parsed
parses :: (String -> Expression) -> String -> Inspection
parses parser code = (== (parser code))
assigns :: BoundInspection
assigns predicate = containsExpression f
where f (Assignment name _) = predicate name
f (Variable name _) = predicate name
f (Attribute name _) = predicate name
f _ = False
-- | Inspection that tells whether an expression uses the the given target identifier
-- in its definition
uses :: BoundInspection
uses p = containsExpression f
where f = any p . referencedIdentifiers
calls :: BoundInspection
calls p = containsExpression f
where f (Call (Reference id) _ ) = p id
f _ = False
delegates :: BoundInspection
delegates = decontextualize . delegates'
delegates' :: ContextualizedBoundInspection
delegates' p context expression = inspect $ do
(Subroutine name1 _) <- declarations context
(Call (Reference name2) _) <- expressions expression
select (name1 == name2)
select (p name1)
-- | Inspection that tells whether an expression uses ifs
-- in its definition
usesIf :: Inspection
usesIf = containsExpression f
where f (If _ _ _) = True
f _ = False
usesYield :: Inspection
usesYield = containsExpression f
where f (Yield _) = True
f _ = False
usesFor :: Inspection
usesFor = containsExpression f
where f (For _ _) = True
f _ = False
-- | Inspection that tells whether a top level declaration exists
declares :: BoundInspection
declares = containsBoundDeclaration f
where f (TypeSignature _ _) = False
f _ = True
-- | Inspection that tells whether an expression is direct recursive
declaresRecursively :: BoundInspection
declaresRecursively = containsBoundDeclaration f
where f e | (Just name) <- (nameOf e) = uses (named name) e
| otherwise = False
nameOf :: Expression -> Maybe Identifier
nameOf = listToMaybe . declaredIdentifiers
declaresFunction :: BoundInspection
declaresFunction = containsBoundDeclaration f
where f (Function _ _) = True
f _ = False
declaresVariable :: BoundInspection
declaresVariable = containsBoundDeclaration f
where f (Variable _ _) = True
f _ = False
declaresEntryPoint :: BoundInspection
declaresEntryPoint = containsBoundDeclaration f
where f (EntryPoint _ _) = True
f _ = False
-- | Inspection that tells whether a top level computation declaration exists
declaresComputation :: BoundInspection
declaresComputation = declaresComputationWithArity' (const True)
declaresComputationWithArity :: Int -> BoundInspection
declaresComputationWithArity arity = declaresComputationWithArity' (== arity)
declaresComputationWithArity' :: (Int -> Bool) -> BoundInspection
declaresComputationWithArity' arityPredicate = containsBoundDeclaration f
where f (Subroutine _ es) = any equationArityIs es
f (Clause _ args _) = argsHaveArity args
f _ = False
equationArityIs (Equation args _) = argsHaveArity args
argsHaveArity = arityPredicate.length
raises :: BoundInspection
raises predicate = containsExpression f
where f (Raise (New (Reference n) _)) = predicate n
f (Raise (Reference n)) = predicate n
f _ = False
usesExceptions :: Inspection
usesExceptions = containsExpression f
where f (Raise _) = True
f _ = False
rescues :: BoundInspection
rescues predicate = containsExpression f
where f (Try _ rescues _) = any (matchesType predicate) . map fst $ rescues
f _ = False
usesExceptionHandling :: Inspection
usesExceptionHandling = containsExpression f
where f (Try _ _ _) = True
f _ = False
usesAnonymousVariable :: Inspection
usesAnonymousVariable = containsExpression f
where f (Subroutine _ body) = equationContainsWildcard body
--TODO f (Lambda args _) = equationContainsWildcard equations
f (Clause _ params _) = any isOrContainsWildcard params
f _ = False
equationContainsWildcard = has isOrContainsWildcard subroutineBodyPatterns
isOrContainsWildcard (InfixApplicationPattern p1 _ p2) = any isOrContainsWildcard [p1, p2]
isOrContainsWildcard (ApplicationPattern _ ps) = any isOrContainsWildcard ps
isOrContainsWildcard (TuplePattern ps) = any isOrContainsWildcard ps
isOrContainsWildcard (ListPattern ps) = any isOrContainsWildcard ps
isOrContainsWildcard (FunctorPattern _ ps) = any isOrContainsWildcard ps
isOrContainsWildcard (AsPattern _ p) = isOrContainsWildcard p
isOrContainsWildcard WildcardPattern = True
isOrContainsWildcard _ = False