import System.IO import System.Exit import Data.List validTokens = ["html", "head", "body", "title", "h1", "h2", "h3", "p", "ul", "li", "a", "div", "br", "hr"] validTokens' = ["/html", "/head", "/body", "/title", "/h1", "/h2", "/h3", "/p", "/ul", "/li", "/a", "/div", "/br", "/hr"] nestables = ["h1", "h2", "h3", "p", "ul", "li", "a", "div"] nestables' = ["/h1", "/h2", "/h3", "/p", "/ul", "/li", "/a", "/div"] ignorables = ["br","hr"] main :: IO() main = do filecontent <- readFile "file.html" let fileLines = filecontent let tokenized = map cleanAttribute $ extractTokens fileLines checkTokens tokenized checkHeader tokenized let bodyTokens = isolateBody tokenized if bodyTokens == [] then errorWithoutStackTrace "Expected
..." else checkBodyStructure (head bodyTokens) (last bodyTokens) let stack = push [] (tail $ init bodyTokens) -- push tokens onto the stack one by one if stack == [] then putStrLn "No errors detected" else putStrLn "There remmain unclosed tags" extractTokens [] = [] extractTokens ('<':xs) = let (curr,rest) = extractTokens' xs in curr:extractTokens rest extractTokens (_ :xs) = extractTokens xs extractTokens' [] = ([], []) extractTokens' ('>':xs) = ([], xs) extractTokens' (x :xs) = let (curr,rest) = extractTokens' xs in (x:curr, rest) cleanAttribute:: String -> String cleanAttribute s = fst $ break (' '==) s -- take everything from insidewith: " ++x | x `elem` nestables' = if (removeSlash x) == head stack then push (tail stack) xs else errorWithoutStackTrace $ "Invalid nesting with: " ++x --i.e wrong closer found, error | otherwise = errorWithoutStackTrace $ "Invalid Tag: " ++ x removeSlash:: String -> String --well actually removes first character, but we know it must be a nestable i.e.