module WildCard (wildcard) where import Data.List wildcard :: String -> String -> Maybe Error wildcard consumer input = go False input $ split '*' consumer where -- End of input go wildc "" cons | null cons = Nothing | wildc && all (=="*") cons = Nothing | otherwise = unexpected "" -- End of consumers go True input [] = Nothing go False input [] = unexpected input -- Set wild card to `on' go wildc input ("*":xs) = go True input xs -- Try to consume immediately go False input (x :xs) = case consume x input of Just new -> go False new xs Nothing -> unexpected input -- Wildcard is on; try to consume until the end of the string go True input (x :xs) = case walkConsume x input of Just new -> go False new xs Nothing -> unexpected input unexpected e = Just $ "unexpected \"" ++ e ++ "\"" split :: Char -> String -> [String] split c = filter (/="") . go where go [] = [] go xs = let (ys,xs') = break (==c) xs in ys : take 1 xs' : go (drop 1 xs') consume :: String -> String -> Maybe String consume cons inp | isPrefixOf cons inp = Just $ drop (length cons) inp | otherwise = Nothing walkConsume :: String -> String -> Maybe String walkConsume cons = fmap (drop (length cons)) . findLast (isPrefixOf cons) . tails findLast :: (a -> Bool) -> [a] -> Maybe a findLast p = foldl try Nothing where try last x | p x = Just x | otherwise = last type Error = String {- *WildCard> wildcard "hello" "" Just "unexpected \"\"" *WildCard> wildcard "hello" "hello" Nothing *WildCard> wildcard "hello" "hello dave" Just "unexpected \" dave\"" *WildCard> wildcard "hello*" "hello dave" Nothing *WildCard> wildcard "hello*" "oh, hello dave" Just "unexpected \"oh, hello dave\"" *WildCard> wildcard "*hello*" "oh, hello dave" Nothing *WildCard> wildcard "*hello*" "oh, hel!!lo dave" Just "unexpected \"oh, hel!!lo dave\"" *WildCard> wildcard "*hel*lo*" "oh, hel!!lo dave" Nothing -}