module Distribution.Simple.PreProcess.Unlit(unlit,plain) where
import Data.Char
data Classified = Program String | Blank | Comment
| Include Int String | Pre String
plain :: String -> String -> String
plain _ hs = hs
classify :: [String] -> [Classified]
classify [] = []
classify ("\\begin{code}":rest) = Blank : allProg rest
where allProg [] = []
allProg ("\\end{code}":xs) = Blank : classify xs
allProg (x:xs) = Program x:allProg xs
classify (('>':x):xs) = Program (' ':x) : classify xs
classify (('#':x):xs) = (case words x of
(line:rest) | all isDigit line
-> Include (read line) (unwords rest)
_ -> Pre x
) : classify xs
classify (x:xs) | all isSpace x = Blank:classify xs
classify (_:xs) = Comment:classify xs
unclassify :: Classified -> String
unclassify (Program s) = s
unclassify (Pre s) = '#':s
unclassify (Include i f) = '#':' ':show i ++ ' ':f
unclassify Blank = ""
unclassify Comment = ""
unlit :: FilePath -> String -> String
unlit file lhs = (unlines
. map unclassify
. adjacent file (0::Int) Blank
. classify) (inlines lhs)
adjacent :: FilePath -> Int -> Classified -> [Classified] -> [Classified]
adjacent file n y xs
| file `seq` n `seq` y `seq` xs `seq` False = undefined
adjacent _ _ _ (x@(Include i f):xs) = x: adjacent f i Blank xs
adjacent file n _ (x@(Pre _) :xs) = x: adjacent file (n+1) Blank xs
adjacent file n (Program _) ( Comment :_ ) = error (message file n "program" "comment")
adjacent file n Comment ( (Program _) :_ ) = error (message file n "comment" "program")
adjacent file n _ (x :xs) = x: adjacent file (n+1) x xs
adjacent _ _ _ [] = []
message :: String -> Int -> String -> String -> String
message "\"\"" n p c = "Line "++show n++": "++p++ " line before "++c++" line.\n"
message [] n p c = "Line "++show n++": "++p++ " line before "++c++" line.\n"
message file n p c = "In file " ++ file ++ " at line "++show n++": "++p++ " line before "++c++" line.\n"
inlines :: String -> [String]
inlines xs = lines' xs id
where
lines' [] acc = [acc []]
lines' ('\^M':'\n':s) acc = acc [] : lines' s id
lines' ('\^M':s) acc = acc [] : lines' s id
lines' ('\n':s) acc = acc [] : lines' s id
lines' (c:s) acc = lines' s (acc . (c:))