{-# LANGUAGE CPP, OverloadedStrings, PatternGuards #-}
{-# OPTIONS_HADDOCK hide #-}
module Data.GraphViz.Internal.Util where
import Data.Char (isAsciiLower, isAsciiUpper, isDigit, ord)
import Control.Monad (liftM2)
import Data.Function (on)
import Data.List (groupBy, sortBy)
import Data.Maybe (isJust)
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.Read as T
#if MIN_VERSION_base(4,8,0)
import Data.Version (Version, makeVersion)
#else
import Data.Version (Version(..))
#endif
isIDString :: Text -> Bool
isIDString :: Text -> Bool
isIDString = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\(Char
f,Text
os) -> Char -> Bool
frstIDString Char
f Bool -> Bool -> Bool
&& (Char -> Bool) -> Text -> Bool
T.all Char -> Bool
restIDString Text
os)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe (Char, Text)
T.uncons
frstIDString :: Char -> Bool
frstIDString :: Char -> Bool
frstIDString Char
c = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (forall a b. (a -> b) -> a -> b
$Char
c) [ Char -> Bool
isAsciiUpper
, Char -> Bool
isAsciiLower
, forall a. Eq a => a -> a -> Bool
(==) Char
'_'
, (\ Char
x -> Char -> Int
ord Char
x forall a. Ord a => a -> a -> Bool
>= Int
128)
]
restIDString :: Char -> Bool
restIDString :: Char -> Bool
restIDString Char
c = Char -> Bool
frstIDString Char
c Bool -> Bool -> Bool
|| Char -> Bool
isDigit Char
c
isNumString :: Bool -> Text -> Bool
isNumString :: Bool -> Text -> Bool
isNumString Bool
_ Text
"" = Bool
False
isNumString Bool
_ Text
"-" = Bool
False
isNumString Bool
allowE Text
str = case Text -> Maybe (Char, Text)
T.uncons forall a b. (a -> b) -> a -> b
$ Text -> Text
T.toLower Text
str of
Just (Char
'-',Text
str') -> Text -> Bool
go Text
str'
Maybe (Char, Text)
_ -> Text -> Bool
go Text
str
where
go :: Text -> Bool
go Text
s = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Text -> Text -> Bool
go' forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> (Text, Text)
T.span Char -> Bool
isDigit Text
s
go' :: Text -> Text -> Bool
go' Text
ds Text
nds
| Text -> Bool
T.null Text
nds = Bool
True
| Text -> Bool
T.null Text
ds Bool -> Bool -> Bool
&& Text
nds forall a. Eq a => a -> a -> Bool
== Text
"." = Bool
False
| Text -> Bool
T.null Text
ds
, Just (Char
'.',Text
nds') <- Text -> Maybe (Char, Text)
T.uncons Text
nds
, Just (Char
d,Text
nds'') <- Text -> Maybe (Char, Text)
T.uncons Text
nds' = Char -> Bool
isDigit Char
d Bool -> Bool -> Bool
&& Text -> Bool
checkEs' Text
nds''
| Just (Char
'.',Text
nds') <- Text -> Maybe (Char, Text)
T.uncons Text
nds = Text -> Bool
checkEs forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> Text
T.dropWhile Char -> Bool
isDigit Text
nds'
| Text -> Bool
T.null Text
ds = Bool
False
| Bool
otherwise = Text -> Bool
checkEs Text
nds
checkEs' :: Text -> Bool
checkEs' Text
s = case (Char -> Bool) -> Text -> (Text, Text)
T.break (Char
'e' forall a. Eq a => a -> a -> Bool
==) Text
s of
(Text
"", Text
_) -> Bool
False
(Text
ds,Text
es) -> (Char -> Bool) -> Text -> Bool
T.all Char -> Bool
isDigit Text
ds Bool -> Bool -> Bool
&& Text -> Bool
checkEs Text
es
checkEs :: Text -> Bool
checkEs Text
str' = case Text -> Maybe (Char, Text)
T.uncons Text
str' of
Maybe (Char, Text)
Nothing -> Bool
True
Just (Char
'e',Text
ds) -> Bool
allowE Bool -> Bool -> Bool
&& Text -> Bool
isIntString Text
ds
Maybe (Char, Text)
_ -> Bool
False
toDouble :: Text -> Double
toDouble :: Text -> Double
toDouble Text
str = case Text -> Maybe (Char, Text)
T.uncons forall a b. (a -> b) -> a -> b
$ Text -> Text
T.toLower Text
str of
Just (Char
'-', Text
str') -> Text -> Double
toD forall a b. (a -> b) -> a -> b
$ Char
'-' Char -> Text -> Text
`T.cons` Text -> Text
adj Text
str'
Maybe (Char, Text)
_ -> Text -> Double
toD forall a b. (a -> b) -> a -> b
$ Text -> Text
adj Text
str
where
adj :: Text -> Text
adj Text
s = Char -> Text -> Text
T.cons Char
'0'
forall a b. (a -> b) -> a -> b
$ case (Char -> Bool) -> Text -> (Text, Text)
T.span (Char
'.' forall a. Eq a => a -> a -> Bool
==) Text
s of
(Text
ds, Text
".") | Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ Text -> Bool
T.null Text
ds -> Text
s Text -> Char -> Text
`T.snoc` Char
'0'
(Text
ds, Text
ds') | Just (Char
'.',Text
es) <- Text -> Maybe (Char, Text)
T.uncons Text
ds'
, Just (Char
'e',Text
_) <- Text -> Maybe (Char, Text)
T.uncons Text
es
-> Text
ds Text -> Char -> Text
`T.snoc` Char
'.' Text -> Char -> Text
`T.snoc` Char
'0' Text -> Text -> Text
`T.append` Text
es
(Text, Text)
_ -> Text
s
toD :: Text -> Double
toD = forall a. Read a => String -> a
read forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack
isIntString :: Text -> Bool
isIntString :: Text -> Bool
isIntString = forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Int
stringToInt
stringToInt :: Text -> Maybe Int
stringToInt :: Text -> Maybe Int
stringToInt Text
str = case forall a. Num a => Reader a -> Reader a
T.signed forall a. Integral a => Reader a
T.decimal Text
str of
Right (Int
n, Text
"") -> forall a. a -> Maybe a
Just Int
n
Either String (Int, Text)
_ -> forall a. Maybe a
Nothing
escapeQuotes :: String -> String
escapeQuotes :: String -> String
escapeQuotes [] = []
escapeQuotes (Char
'"':String
str) = Char
'\\'forall a. a -> [a] -> [a]
:Char
'"'forall a. a -> [a] -> [a]
: String -> String
escapeQuotes String
str
escapeQuotes (Char
c:String
str) = Char
c forall a. a -> [a] -> [a]
: String -> String
escapeQuotes String
str
descapeQuotes :: String -> String
descapeQuotes :: String -> String
descapeQuotes [] = []
descapeQuotes (Char
'\\':Char
'"':String
str) = Char
'"' forall a. a -> [a] -> [a]
: String -> String
descapeQuotes String
str
descapeQuotes (Char
c:String
str) = Char
c forall a. a -> [a] -> [a]
: String -> String
descapeQuotes String
str
isKeyword :: Text -> Bool
isKeyword :: Text -> Bool
isKeyword = (forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Text
keywords) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.toLower
keywords :: Set Text
keywords :: Set Text
keywords = forall a. Ord a => [a] -> Set a
Set.fromList [ Text
"node"
, Text
"edge"
, Text
"graph"
, Text
"digraph"
, Text
"subgraph"
, Text
"strict"
]
createVersion :: [Int] -> Version
#if MIN_VERSION_base(4,8,0)
createVersion :: [Int] -> Version
createVersion = [Int] -> Version
makeVersion
#else
createVersion bs = Version { versionBranch = bs, versionTags = []}
#endif
uniq :: (Ord a) => [a] -> [a]
uniq :: forall a. Ord a => [a] -> [a]
uniq = forall b a. Ord b => (a -> b) -> [a] -> [a]
uniqBy forall a. a -> a
id
uniqBy :: (Ord b) => (a -> b) -> [a] -> [a]
uniqBy :: forall b a. Ord b => (a -> b) -> [a] -> [a]
uniqBy a -> b
f = forall a b. (a -> b) -> [a] -> [b]
map forall a. [a] -> a
head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. Ord b => (a -> b) -> [a] -> [[a]]
groupSortBy a -> b
f
groupSortBy :: (Ord b) => (a -> b) -> [a] -> [[a]]
groupSortBy :: forall b a. Ord b => (a -> b) -> [a] -> [[a]]
groupSortBy a -> b
f = forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` a -> b
f) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (forall a. Ord a => a -> a -> Ordering
compare forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` a -> b
f)
groupSortCollectBy :: (Ord b) => (a -> b) -> (a -> c) -> [a] -> [(b,[c])]
groupSortCollectBy :: forall b a c. Ord b => (a -> b) -> (a -> c) -> [a] -> [(b, [c])]
groupSortCollectBy a -> b
f a -> c
g = forall a b. (a -> b) -> [a] -> [b]
map (forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 (,) (a -> b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> a
head) (forall a b. (a -> b) -> [a] -> [b]
map a -> c
g)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. Ord b => (a -> b) -> [a] -> [[a]]
groupSortBy a -> b
f
bool :: a -> a -> Bool -> a
bool :: forall a. a -> a -> Bool -> a
bool a
f a
t Bool
b = if Bool
b
then a
t
else a
f
isSingle :: [a] -> Bool
isSingle :: forall a. [a] -> Bool
isSingle [a
_] = Bool
True
isSingle [a]
_ = Bool
False