module WildCard (wildcard) where
import Data.List
wildcard :: String -> String -> Maybe Error
wildcard consumer input = go False input $ split '*' consumer where
go wildc "" cons | null cons = Nothing
| wildc && all (=="*") cons = Nothing
| otherwise = unexpected ""
go True input [] = Nothing
go False input [] = unexpected input
go wildc input ("*":xs) = go True input xs
go False input (x :xs) = case consume x input of
Just new -> go False new xs
Nothing -> unexpected input
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