module General.Makefile(parseMakefile) where

import qualified Data.ByteString.Char8 as BS
import Data.Char


endsSlash :: BS.ByteString -> Bool
endsSlash :: ByteString -> Bool
endsSlash = ByteString -> ByteString -> Bool
BS.isSuffixOf (Char -> ByteString
BS.singleton Char
'\\')

wordsMakefile :: BS.ByteString -> [BS.ByteString]
wordsMakefile :: ByteString -> [ByteString]
wordsMakefile = [ByteString] -> [ByteString]
f ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> [ByteString]
BS.splitWith Char -> Bool
isSpace
    where
        f :: [ByteString] -> [ByteString]
f (ByteString
x:[ByteString]
xs) | ByteString -> Bool
BS.null ByteString
x = [ByteString] -> [ByteString]
f [ByteString]
xs
        f (ByteString
x:ByteString
y:[ByteString]
xs) | ByteString -> Bool
endsSlash ByteString
x = [ByteString] -> [ByteString]
f ([ByteString] -> [ByteString]) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BS.concat [ByteString -> ByteString
BS.init ByteString
x, Char -> ByteString
BS.singleton Char
' ', ByteString
y] ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
xs
        f (ByteString
x:[ByteString]
xs) = ByteString
x ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString] -> [ByteString]
f [ByteString]
xs
        f [] = []

parseMakefile :: BS.ByteString -> [(BS.ByteString, [BS.ByteString])]
parseMakefile :: ByteString -> [(ByteString, [ByteString])]
parseMakefile = (ByteString -> [(ByteString, [ByteString])])
-> [ByteString] -> [(ByteString, [ByteString])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ByteString -> [(ByteString, [ByteString])]
f ([ByteString] -> [(ByteString, [ByteString])])
-> (ByteString -> [ByteString])
-> ByteString
-> [(ByteString, [ByteString])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [ByteString]
join ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
linesCR
    where
        join :: [ByteString] -> [ByteString]
join [ByteString]
xs = case (ByteString -> Bool)
-> [ByteString] -> ([ByteString], [ByteString])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span ByteString -> Bool
endsSlash [ByteString]
xs of
            ([], []) -> []
            ([ByteString]
xs, []) -> [[ByteString] -> ByteString
BS.unwords ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ByteString
BS.init [ByteString]
xs]
            ([], ByteString
y:[ByteString]
ys) -> ByteString
y ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString] -> [ByteString]
join [ByteString]
ys
            ([ByteString]
xs, ByteString
y:[ByteString]
ys) -> [ByteString] -> ByteString
BS.unwords ((ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ByteString
BS.init [ByteString]
xs [ByteString] -> [ByteString] -> [ByteString]
forall a. [a] -> [a] -> [a]
++ [ByteString
y]) ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString] -> [ByteString]
join [ByteString]
ys

        f :: ByteString -> [(ByteString, [ByteString])]
f ByteString
x = [(ByteString
a, ByteString -> [ByteString]
wordsMakefile (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
b) | ByteString
a <- ByteString -> [ByteString]
wordsMakefile ByteString
a]
            where (ByteString
a,ByteString
b) = (Char -> Bool) -> ByteString -> (ByteString, ByteString)
BS.break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
':') (ByteString -> (ByteString, ByteString))
-> ByteString -> (ByteString, ByteString)
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ByteString -> ByteString
BS.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'#') ByteString
x


-- | This is a hot-spot, so optimised
linesCR :: BS.ByteString -> [BS.ByteString]
linesCR :: ByteString -> [ByteString]
linesCR ByteString
x = case Char -> ByteString -> [ByteString]
BS.split Char
'\n' ByteString
x of
    ByteString
x:[ByteString]
xs | Just (Char
'\r',ByteString
x) <- ByteString -> Maybe (Char, ByteString)
unsnoc ByteString
x -> ByteString
x ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (\ByteString
x -> case ByteString -> Maybe (Char, ByteString)
unsnoc ByteString
x of Just (Char
'\r',ByteString
x) -> ByteString
x; Maybe (Char, ByteString)
_ -> ByteString
x) [ByteString]
xs
    [ByteString]
xs -> [ByteString]
xs
    where
        -- the ByteString unsnoc was introduced in a newer version
        unsnoc :: ByteString -> Maybe (Char, ByteString)
unsnoc ByteString
x | ByteString -> Bool
BS.null ByteString
x = Maybe (Char, ByteString)
forall a. Maybe a
Nothing
                 | Bool
otherwise = (Char, ByteString) -> Maybe (Char, ByteString)
forall a. a -> Maybe a
Just (ByteString -> Char
BS.last ByteString
x, ByteString -> ByteString
BS.init ByteString
x)