module Text.Razom.Uid
( uid
, generator
, escapeUid
, unescapeUid
)
where
import Data.Char (isSpace)
import Text.Razom.Char
import Text.Razom.Types
import Text.Regex.Applicative
uidcharp c = isGraphical c
&& not (isSpace c)
&& c /= '\\'
&& c /= '>'
uidfstp c = uidcharp c && c /= '%'
uidopen = sym '<'
uidclose = sym '>'
uid :: Regex String
uid = unescapeUid <$> (uidopen *> uidbody <* uidclose)
where
uidbody = snd <$> withMatched (uidfirst <* many (mkpart uidcharp))
uidfirst = Nothing <$ string "\\%" <|> Nothing <$ mkpart uidfstp
mkpart p = Nothing <$ psym p
<|> Nothing <$ string "\\\\"
<|> Nothing <$ string "\\>"
generator :: Regex String
generator = (:) <$> uidopen *> sym '%' *> many (psym uidcharp) <* uidclose
escapeUidChar :: Char -> String
escapeUidChar '\\' = "\\\\"
escapeUidChar '>' = "\\>"
escapeUidChar c = [c]
unescapeUidChar :: String -> (Char, String)
unescapeUidChar ('\\':c:cs) =
case c of
'\\' -> ('\\', cs)
'>' -> ('>', cs)
x -> error $ "invalid escape sequence: \\" ++ [x]
unescapeUidChar (c:cs) = (c, cs)
unescapeUidChar [] = error "empty string"
escapeUid :: String -> String
escapeUid s =
case s of
('%':cs) -> '\\' : '%' : f cs
cs -> f cs
where
f = foldr ((++) . escapeUidChar) ""
unescapeUid :: String -> String
unescapeUid s =
case s of
[] -> []
('\\':'%':cs) -> '%' : f cs
cs -> f cs
where
f [] = []
f s = let (c, cs) = unescapeUidChar s in c : f cs