44 lines
1.3 KiB
Haskell
44 lines
1.3 KiB
Haskell
import qualified Text.Parsec as P
|
|
|
|
showExpansion :: String -> String
|
|
showExpansion =
|
|
(<>) . (<> "\n-->\n") <*> (either show unlines . P.parse parser [])
|
|
|
|
parser :: P.Parsec String u [String]
|
|
parser = expansion P.anyChar
|
|
|
|
expansion :: P.Parsec String u Char -> P.Parsec String u [String]
|
|
expansion =
|
|
fmap expand .
|
|
P.many .
|
|
((P.try alts P.<|> P.try alt1 P.<|> escape) P.<|>) . fmap (pure . pure)
|
|
|
|
expand :: [[String]] -> [String]
|
|
expand = foldr ((<*>) . fmap (<>)) [[]]
|
|
|
|
alts :: P.Parsec String u [String]
|
|
alts = concat <$> P.between (P.char '{') (P.char '}') (alt `sepBy2` P.char ',')
|
|
|
|
alt :: P.Parsec String u [String]
|
|
alt = expansion (P.noneOf ",}")
|
|
|
|
alt1 :: P.Parsec String u [String]
|
|
alt1 =
|
|
(\x -> ['{' : (x <> "}")]) <$>
|
|
P.between (P.char '{') (P.char '}') (P.many $ P.noneOf ",{}")
|
|
|
|
sepBy2 :: P.Parsec String u a -> P.Parsec String u b -> P.Parsec String u [a]
|
|
p `sepBy2` sep = (:) <$> p <*> P.many1 (sep >> p)
|
|
|
|
escape :: P.Parsec String u [String]
|
|
escape = pure <$> sequence [P.char '\\', P.anyChar]
|
|
|
|
main :: IO ()
|
|
main =
|
|
mapM_
|
|
(putStrLn . showExpansion)
|
|
[ "~/{Downloads,Pictures}/*.{jpg,gif,png}"
|
|
, "It{{em,alic}iz,erat}e{d,}, please."
|
|
, "{,{,gotta have{ ,\\, again\\, }}more }cowbell!"
|
|
, "{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}"
|
|
]
|