specialise matrices by constructors and default cases
This commit is contained in:
1 file changed
+109
@@ -0,0 +1,109 @@
|
|||||||
|
module Tessera.Analyze where
|
||||||
|
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
import Tessera.Env
|
||||||
|
import Tessera.Eval (Value (..), sourceSelect)
|
||||||
|
import Tessera.Matrix
|
||||||
|
import Tessera.Syntax
|
||||||
|
|
||||||
|
data ClauseStatus
|
||||||
|
= ClauseUseful
|
||||||
|
| ClauseRedundant
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
data ClauseReport = ClauseReport
|
||||||
|
{ reportClauseIndex :: Int
|
||||||
|
, reportClauseStatus :: ClauseStatus
|
||||||
|
, reportClauseExample :: Maybe [Value]
|
||||||
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
|
data MatchReport = MatchReport
|
||||||
|
{ reportMatchName :: String
|
||||||
|
, reportExhaustive :: Bool
|
||||||
|
, reportInconclusive :: Bool
|
||||||
|
, reportMissingCase :: Maybe [Value]
|
||||||
|
, reportClauseReports :: [ClauseReport]
|
||||||
|
, reportInhabitedTypes :: Map.Map String Bool
|
||||||
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
|
analysisBudget :: Int
|
||||||
|
analysisBudget = 500
|
||||||
|
|
||||||
|
analyzeMatch :: Env -> Declaration -> Maybe MatchReport
|
||||||
|
analyzeMatch env (MatchDeclaration name arguments _ clauses) =
|
||||||
|
let types = map snd arguments
|
||||||
|
matrixAll = map clausePatterns clauses
|
||||||
|
outcome = witness env analysisBudget types matrixAll
|
||||||
|
missing = case outcome of
|
||||||
|
NotCovered patterns -> witnessValues patterns
|
||||||
|
Covered -> Nothing
|
||||||
|
SearchExhausted -> Nothing
|
||||||
|
inconclusive = case outcome of
|
||||||
|
SearchExhausted -> True
|
||||||
|
NotCovered patterns -> witnessValues patterns == Nothing
|
||||||
|
Covered -> False
|
||||||
|
clauseReports = [ analyzeClause env types index clauses | index <- [0 .. length clauses - 1] ]
|
||||||
|
in Just MatchReport
|
||||||
|
{ reportMatchName = name
|
||||||
|
, reportExhaustive = outcome == Covered
|
||||||
|
, reportInconclusive = inconclusive
|
||||||
|
, reportMissingCase = missing
|
||||||
|
, reportClauseReports = clauseReports
|
||||||
|
, reportInhabitedTypes = finiteInhabitants env
|
||||||
|
}
|
||||||
|
analyzeMatch _ _ = Nothing
|
||||||
|
|
||||||
|
analyzeClause :: Env -> [Type] -> Int -> [Clause] -> ClauseReport
|
||||||
|
analyzeClause env types index clauses =
|
||||||
|
let previous = map clausePatterns (take index clauses)
|
||||||
|
current = clausePatterns (clauses !! index)
|
||||||
|
isUseful = useful env types previous current
|
||||||
|
example = if isUseful then exampleForClause env types index clauses else Nothing
|
||||||
|
in ClauseReport
|
||||||
|
{ reportClauseIndex = index
|
||||||
|
, reportClauseStatus = if isUseful then ClauseUseful else ClauseRedundant
|
||||||
|
, reportClauseExample = example
|
||||||
|
}
|
||||||
|
|
||||||
|
exampleForClause :: Env -> [Type] -> Int -> [Clause] -> Maybe [Value]
|
||||||
|
exampleForClause env types index clauses = case drop index clauses of
|
||||||
|
(clause : _) ->
|
||||||
|
let filled = sequence (zipWith (fillPattern env 8) types (clausePatterns clause))
|
||||||
|
candidate = filled >>= \patterns -> sequence (map patternValue patterns)
|
||||||
|
in case candidate of
|
||||||
|
Nothing -> Nothing
|
||||||
|
Just values -> case sourceSelect (map clausePatterns clauses) values of
|
||||||
|
Just selected | selected == index -> Just values
|
||||||
|
_ -> Nothing
|
||||||
|
[] -> Nothing
|
||||||
|
|
||||||
|
fillPattern :: Env -> Int -> Type -> Pattern -> Maybe Pattern
|
||||||
|
fillPattern env depth ty pattern' = case pattern' of
|
||||||
|
PVar _ -> Just (sample env depth ty)
|
||||||
|
PWild -> Just (sample env depth ty)
|
||||||
|
PInt _ -> Just pattern'
|
||||||
|
PBool _ -> Just pattern'
|
||||||
|
PTuple patterns -> case ty of
|
||||||
|
TTuple types -> PTuple <$> sequence (zipWith (fillPattern env (depth - 1)) types patterns)
|
||||||
|
_ -> Nothing
|
||||||
|
PCon name patterns -> case signature env ty of
|
||||||
|
FiniteSignature constructors -> case lookup (KeyCon name) constructors of
|
||||||
|
Just argumentTypes -> PCon name <$> sequence (zipWith (fillPattern env (depth - 1)) argumentTypes patterns)
|
||||||
|
Nothing -> Nothing
|
||||||
|
IntegerSignature -> Nothing
|
||||||
|
|
||||||
|
patternValue :: Pattern -> Maybe Value
|
||||||
|
patternValue pattern' = case pattern' of
|
||||||
|
PInt n -> Just (VInt n)
|
||||||
|
PBool b -> Just (VBool b)
|
||||||
|
PCon name arguments -> VCon name <$> mapM patternValue arguments
|
||||||
|
PTuple elements -> VTuple <$> mapM patternValue elements
|
||||||
|
PVar _ -> Nothing
|
||||||
|
PWild -> Nothing
|
||||||
|
|
||||||
|
witnessValues :: [Pattern] -> Maybe [Value]
|
||||||
|
witnessValues = sequence . map patternValue
|
||||||
|
|
||||||
|
validateWitness :: [Clause] -> [Value] -> Bool
|
||||||
|
validateWitness clauses values = sourceSelect (map clausePatterns clauses) values == Nothing
|
||||||
Reference in new issue
Block a user