cgrep-6.4: src/CGrep/Semantic/WildCard.hs
--
-- Copyright (c) 2013 Bonelli Nicola <bonelli@antifork.org>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--
module CGrep.Semantic.WildCard (WildCard(..), MultiCard,
filterTokensWithMultiCards,
wildCardMatch,
multiCardMatch) where
import qualified Data.Map as M
import CGrep.Common
import CGrep.Distance
import CGrep.Semantic.Token
import Data.Char
import Data.List
import Options
data WildCard a = TokenCard a |
AnyCard |
KeyWordCard |
NumberCard |
OctCard |
HexCard |
StringCard |
LiteralCard |
CharCard |
IdentifCard String
deriving (Show, Eq, Ord)
type MultiCard a = [WildCard a]
filterTokensWithMultiCards :: (SemanticToken a) => Options -> [MultiCard a] -> [a] -> [a]
filterTokensWithMultiCards opt ws = filterTokensWithMultiCards' opt (spanOptionalCards ws)
filterTokensWithMultiCards' :: (SemanticToken a) => Options -> [[MultiCard a]] -> [a] -> [a]
filterTokensWithMultiCards' _ [] _ = []
filterTokensWithMultiCards' opt (g:gs) ts =
concatMap (take grpLen . (`drop` ts)) (findIndices (multiCardCompare opt g) grp) ++
filterTokensWithMultiCards' opt gs ts
where grp = spanGroup grpLen ts
grpLen = length g
spanOptionalCards :: [MultiCard a] -> [[MultiCard a]]
spanOptionalCards wc = map (`filterCardIndicies` wc') idx
where wc' = zip [0..] wc
idx = subsequences $
findIndices (\w -> case w of
[IdentifCard ('$':_)] -> True
_ -> False) wc
filterCardIndicies :: [Int] -> [(Int, MultiCard a)] -> [MultiCard a]
filterCardIndicies ns ps = map snd $ filter (\(n, _) -> n `notElem` ns) ps
multiCardCompare :: (SemanticToken a) => Options -> [MultiCard a] -> [a] -> Bool
multiCardCompare opt l r =
multiCardCompareAll ts && multiCardCheckOccurences ts
where ts = multiCardGroupCompare opt l r
{-# INLINE multiCardCompareAll #-}
multiCardCompareAll :: [(Bool, (MultiCard a, [String]))] -> Bool
multiCardCompareAll = all fst
{-# INLINE multiCardCheckOccurences #-}
-- Note: pattern $ and _ match any token, whereas $1 $2 (_1 _2 etc.) match tokens
-- that must compare equal in the relative occurrences
--
multiCardCheckOccurences :: (SemanticToken a) => [(Bool, (MultiCard a, [String]))] -> Bool
multiCardCheckOccurences ts = M.foldr (\xs r -> r && all (== head xs) xs) True m
where m = M.mapWithKey (\k xs -> case k of
[IdentifCard "_0"] -> xs
[IdentifCard "_1"] -> xs
[IdentifCard "_2"] -> xs
[IdentifCard "_3"] -> xs
[IdentifCard "_4"] -> xs
[IdentifCard "_5"] -> xs
[IdentifCard "_6"] -> xs
[IdentifCard "_7"] -> xs
[IdentifCard "_8"] -> xs
[IdentifCard "_9"] -> xs
[IdentifCard "$0"] -> xs
[IdentifCard "$1"] -> xs
[IdentifCard "$2"] -> xs
[IdentifCard "$3"] -> xs
[IdentifCard "$4"] -> xs
[IdentifCard "$5"] -> xs
[IdentifCard "$6"] -> xs
[IdentifCard "$7"] -> xs
[IdentifCard "$8"] -> xs
[IdentifCard "$9"] -> xs
_ -> []
) $ M.fromListWith (++) (map snd ts)
multiCardGroupCompare :: (SemanticToken a) => Options -> [MultiCard a] -> [a] -> [(Bool, (MultiCard a, [String]))]
multiCardGroupCompare opt ls rs
| length rs >= length ls = zipWith (tokensZip opt) ls rs
| otherwise = [ (False, ([AnyCard], [])) ]
tokensZip :: (SemanticToken a) => Options -> MultiCard a -> a -> (Bool, (MultiCard a, [String]))
tokensZip opt l r
| multiCardMatch opt l r = (True, (l, [tkToString r]))
| otherwise = (False, ([AnyCard],[] ))
multiCardMatch :: (SemanticToken t) => Options -> MultiCard t -> t -> Bool
multiCardMatch opt m t = any (\w -> wildCardMatch opt w t) m
wildCardMatch :: (SemanticToken t) => Options -> WildCard t -> t -> Bool
wildCardMatch _ AnyCard _ = True
wildCardMatch _ (IdentifCard _) t = tkIsIdentifier t
wildCardMatch _ KeyWordCard t = tkIsKeyword t
wildCardMatch _ StringCard t = tkIsString t
wildCardMatch _ CharCard t = tkIsChar t
wildCardMatch _ LiteralCard t = tkIsString t || tkIsChar t
wildCardMatch _ NumberCard t = tkIsNumber t
wildCardMatch _ OctCard t = tkIsNumber t && case tkToString t of ('0':d: _) -> isDigit d; _ -> False
wildCardMatch _ HexCard t = tkIsNumber t && case tkToString t of ('0':'x':_) -> True; _ -> False
wildCardMatch opt (TokenCard l) r
| tkIsIdentifier l && tkIsIdentifier r = case () of
_ | edit_dist opt -> tkToString l ~== tkToString r
| word_match opt -> tkToString l == tkToString r
| prefix_match opt -> tkToString l `isPrefixOf` tkToString r
| suffix_match opt -> tkToString l `isSuffixOf` tkToString r
| otherwise -> tkToString l `isInfixOf` tkToString r
| tkIsString l && tkIsString r = case () of
_ | edit_dist opt -> ls ~== rs
| word_match opt -> ls == rs
| prefix_match opt -> ls `isPrefixOf` rs
| suffix_match opt -> ls `isSuffixOf` rs
| otherwise -> ls `isInfixOf` rs
where ls = unquotes $ trim (tkToString l)
rs = unquotes $ trim (tkToString r)
| otherwise = l `tkEquivalent` r