module Language.Mulang.Inspector.Generic.Duplication (hasCodeDuplication) where
import Language.Mulang.Ast
import Language.Mulang.Inspector.Primitive
import Language.Mulang.Generator (expressions)
import qualified Data.Hashable as H (hash)
import Data.List (nub, subsequences)
hasCodeDuplication :: Inspection
hasCodeDuplication e = hasDuplicates $ map hash $ filter (not . isLightweight) $ concat $ stripesOf 2 e
isLightweight :: Inspection
isLightweight (MuNumber _) = True
isLightweight (MuString _) = True
isLightweight (MuChar _) = True
isLightweight (MuBool _) = True
isLightweight (Reference _) = True
isLightweight Self = True
isLightweight None = True
isLightweight MuNil = True
isLightweight Equal = True
isLightweight (Application _ es) = not $ any isApplication es
isLightweight (Return e) = isLightweight e
isLightweight (Assignment _ e) = isLightweight e
isLightweight (Variable _ e) = isLightweight e
isLightweight _ = False
isApplication (Application _ _) = True
isApplication _ = False
hasDuplicates ::Eq a => [a] -> Bool
hasDuplicates xs = nub xs /= xs
hash :: Expression -> Int
hash (Return e) = 1 * (37 + hash e)
hash (MuNumber e) = 2 * H.hash e
hash (MuString e) = 3 * H.hash e
hash (Reference i) = 5 * H.hash i
hash (MuBool e) = 7 * H.hash e
hash (Application i es) = 11 * (37 + hash i) * (positionalHash es)
hash (SimpleFunction _ _ body) = 13 * (37 + hash body)
hash Self = 15
hash (SimpleProcedure _ _ body) = 17 * (37 + hash body)
hash (Sequence es) = 19 * (37 + positionalHash es)
hash (MuChar e) = 23 * H.hash e
hash _ = 1
positionalHash :: [Expression] -> Int
positionalHash = sum . zipWith hashElement [1..] . reverse
where
hashElement :: Int -> Expression -> Int
hashElement index expression = (31^index) * hash expression
stripesOf :: Int -> Expression -> [[Expression]]
stripesOf n = concatMap (makeStripes n) . expressions
makeStripes :: Int -> Expression -> [[Expression]]
makeStripes n (Sequence xs) = stripes n xs
makeStripes _ e = [[e]]
stripes :: Int -> [a] -> [[a]]
stripes n = filter ( (>n) . length) . subsequences