module Argon.Visitor (funcsCC) where import Data.Data (Data) import Data.Generics.Uniplate.Data (childrenBi, universeBi) import Language.Haskell.Exts.Syntax import Argon.Types (ComplexityBlock(..)) -- | Compute cyclomatic complexity of every function binding in the given AST. funcsCC :: Data from => from -> [ComplexityBlock] funcsCC ast = map funCC [matches | FunBind matches <- universeBi ast] funCC :: [Match] -> ComplexityBlock funCC [] = CC (0, 0, "", 0) funCC ms@(Match (SrcLoc _ l c) n _ _ _ _:_) = CC (l, c, name n, complexity ms) where name (Ident s) = s name (Symbol s) = s sumWith :: (a -> Int) -> [a] -> Int sumWith f = sum . map f complexity :: Data from => from -> Int complexity node = 1 + visitMatches node + visitExps node visitMatches :: Data from => from -> Int visitMatches = sumWith descend . childrenBi where descend :: [Match] -> Int descend x = length x - 1 + sumWith visitMatches x visitExps :: Data from => from -> Int visitExps = sumWith inspect . universeBi where inspect e = visitExp e + visitOp e visitExp :: Exp -> Int visitExp (If {}) = 1 visitExp (MultiIf alts) = length alts - 1 visitExp (Case _ alts) = length alts - 1 visitExp (LCase alts) = length alts - 1 visitExp _ = 0 visitOp :: Exp -> Int visitOp (InfixApp _ (QVarOp (UnQual (Symbol op))) _) = case op of "||" -> 1 "&&" -> 1 _ -> 0 visitOp _ = 0