addfile ./Check.hs hunk ./Check.hs 1 + +module Check where + +import Fragment +import System +import Data.List + + +data Result = Pass | Fail String | Missing String + deriving (Eq,Show) + + +checkFragments :: String -> [Frag] -> IO () +checkFragments prefix xs = mapM_ f xs + where + f (Frag i has s) | i < 262= do + putStr $ "Checking line " ++ show i ++ "... " + res <- check (prefix ++ "\n" ++ s) + case res of + Pass -> putStrLn "success" + Fail msg -> do + putStrLn "FAILURE" + putStr $ unlines $ map (" "++) $ lines msg + error "Fix your code, or we'll reject you!" + + f _ = return () + + check s = do + res <- checkCode s + case res of + Missing x -> g (Fail $ "Can't find: " ++ show x) s [t | Frag _ has t <- xs, x `elem` has] + _ -> return res + + g err s [] = return err + g err s (x:xs) = do + r <- check (s ++ "\n" ++ x) + if r == Pass then return Pass else g r s xs + + +checkCode :: String -> IO Result +checkCode s = do + writeFile "temp.hs" s + res <- system "ffihugs temp.hs 2> temp.txt" + if res == ExitSuccess then return Pass else do + x <- readFile "temp.txt" + let s = unlines $ filter (not . null) $ drop 1 $ lines x + return $ if any ("- Undefined" `isPrefixOf`) (tails s) + then Missing $ takeWhile (/= '\"') $ drop 1 $ dropWhile (/= '\"') $ dropWhile (/= '-') s + else Fail s + + addfile ./Fragment.hs hunk ./Fragment.hs 1 + +module Fragment where + +import Data.List +import Data.Char +import Data.Maybe + + +type Line = Int + +data Frag = Frag Line [String] String + deriving Show + + + +parseFragments :: String -> [Frag] +parseFragments x = f $ zip [1..] (lines x) + where + f ((i,x):xs) | beginCode x = let (a,b) = break (endCode . snd) xs + code = (unlines $ map snd a) + in Frag i (provides code) (tweak code) : f b + | ignoreCode x = f $ drop 1 $ dropWhile (not . endCode . snd) xs + | otherwise = concat (zipWith (g i) [1..] (parseLine x)) ++ f xs + f [] = [] + + g line col s | length ws <= 1 = [] + | "=" `elem` ws = [Frag line [head ws] s] + | ws !! 1 == "::" = [Frag line [head ws] (s ++ "\n" ++ head ws ++ " = undefined")] + | otherwise = [Frag line [] (name ++ " _ = " ++ s)] + where + ws = words s + name = "expr_" ++ show line ++ "_" ++ show col + +ignoreCode = isPrefixOf "\\ignore\\begin{code}" +beginCode = isPrefixOf "\\begin{code}" +endCode = isPrefixOf "\\end{code}" + + +parseLine :: String -> [String] +parseLine ('|':'|':xs) = parseLine xs +parseLine ('|':xs) = a : parseLine b + where (a,b) = parseBar xs +parseLine xs | "\\ignore|" `isPrefixOf` xs = parseLine $ snd $ parseBar $ drop 8 xs +parseLine (x:xs) = parseLine xs +parseLine [] = [] + +parseBar ('|':'|':xs) = ('|':a,b) + where (a,b) = parseBar xs +parseBar ('|':xs) = ("",xs) +parseBar (x:xs) = (x:a,b) + where (a,b) = parseBar xs +parseBar [] = ("","") + + +provides :: String -> [String] +provides = f . lines + where + f (x:(y:ys):xs) | isSpace y = f ((x ++ y:ys):xs) + f (x:xs) | "data " `isPrefixOf` x || "type " `isPrefixOf` x = providesData x ++ f xs + f (x:xs) = [head $ words x | not $ null x] ++ f xs + f _ = [] + + +providesData :: String -> [String] +providesData x = (ws!!1) : [a2 | a1:a2:as <- tails ws, a1 `elem` ["|","="]] + where ws = words x + + +tweak :: String -> String +tweak = unlines . f . lines + where + f (x:xs) | isJust typ && typ /= fun = x : def : f xs + where + def = fromJust typ ++ " = undefined" + typ = isType x + fun = isFunc xs + + f (x:xs) = x : f xs + f [] = [] + + +isType :: String -> Maybe String +isType x = if length xs > 1 && (xs !! 1) == "::" then Just (head xs) else Nothing + where xs = words x + +isFunc :: [String] -> Maybe String +isFunc (x:xs) = if length xs > 0 then Just (head xs) else Nothing + where xs = words x +isFunc _ = Nothing addfile ./Main.hs hunk ./Main.hs 1 + +module Main where + +import System.Environment +import Fragment +import Check + + +main = do + [x] <- getArgs + src <- readFile x + pre <- readFile "Include.hs" + checkFragments pre $ parseFragments src addfile ./push.bat hunk ./push.bat 1 +darcs push --no-set-default ndm@venice.cs.york.ac.uk:/n/www/cs/fp/darcs/tex2hs hunk ./Check.hs 7 +import Data.Char +import Control.Monad +import Debug.Trace hunk ./Check.hs 12 -data Result = Pass | Fail String | Missing String +data Result = Pass | Fail String | Missing String | Instances [String] hunk ./Check.hs 15 +builtin = ["Int","Bool","Float","Integer","String","Char"] hunk ./Check.hs 17 -checkFragments :: String -> [Frag] -> IO () -checkFragments prefix xs = mapM_ f xs + +checkFragments :: Bool -> (Int -> Bool) -> String -> [Frag] -> IO () +checkFragments debug test prefix xs = mapM_ f xs hunk ./Check.hs 21 - f (Frag i has s) | i < 262= do + names = [drop 5 x | x <- lines prefix, "-- # " `isPrefixOf` x] + insts = [drop 12 x | x <- lines prefix, "-- instance " `isPrefixOf` x] + + f (Expr i s) + | test i && s `elem` (names ++ builtin ++ concat [has | Stmt _ has _ <- xs]) + = putStrLn $ "Checking line " ++ show i ++ "... success" + + f (Expr i s) = f $ Stmt i [] ("tex2hs _ = (" ++ s ++ ")") + f (Stmt i has s) | test i = do hunk ./Check.hs 42 - res <- checkCode s + res <- checkCode debug s hunk ./Check.hs 44 - Missing x -> g (Fail $ "Can't find: " ++ show x) s [t | Frag _ has t <- xs, x `elem` has] + Missing x -> g (Fail $ "Can't find: " ++ show x) s [t | Stmt _ has t <- xs, x `elem` has] + Instances x -> + let add = unlines ["instance " ++ i | i <- x, i `elem` insts] + in g (Fail $ "No instance: " ++ show x) s [add | not $ null add] hunk ./Check.hs 55 - -checkCode :: String -> IO Result -checkCode s = do - writeFile "temp.hs" s - res <- system "ffihugs temp.hs 2> temp.txt" +checkCode :: Bool -> String -> IO Result +checkCode debug orig = do + writeFile "temp.hs" orig + res <- system "ffihugs -98 temp.hs 2> temp.txt" hunk ./Check.hs 62 - return $ if any ("- Undefined" `isPrefixOf`) (tails s) - then Missing $ takeWhile (/= '\"') $ drop 1 $ dropWhile (/= '\"') $ dropWhile (/= '-') s - else Fail s + err = parseError s + + when debug $ do + putStrLn orig + putStrLn s + print err + getChar + return () + + return err + +parseError s = + if any ("- Undefined" `isPrefixOf`) (tails s) then + Missing $ takeWhile (/= '\"') $ drop 1 $ dropWhile (/= '\"') $ dropWhile (/= '-') s + else if any ("- Instance" `isPrefixOf`) (tails s) then + Instances $ insts s + else if any ("requires extra context" `isPrefixOf`) (tails s) then + Instances $ nub $ insts2 s + else + Fail s hunk ./Check.hs 85 +insts = map (unwords . words) . lines . map rep . sel + where + rep x = if x == ',' then '\n' + else if x `elem` "()" then ' ' + else x + + sel (' ':'o':'f':' ':xs) = g xs + sel (x:xs) = sel xs + + g (' ':'r':xs) = [] + g (x:xs) = x : g xs + + +insts2 = map (unwords . words) . lines . map rep . reverse . takeWhile (/= ':') . reverse + where + rep x = if x == ',' then '\n' + else if x `elem` "()" then ' ' + else x + hunk ./Fragment.hs 11 -data Frag = Frag Line [String] String +data Frag = Stmt Line [String] String + | Expr Line String hunk ./Fragment.hs 22 - in Frag i (provides code) (tweak code) : f b + in Stmt i (provides code) (tweak code) : f b hunk ./Fragment.hs 27 - g line col s | length ws <= 1 = [] - | "=" `elem` ws = [Frag line [head ws] s] - | ws !! 1 == "::" = [Frag line [head ws] (s ++ "\n" ++ head ws ++ " = undefined")] - | otherwise = [Frag line [] (name ++ " _ = " ++ s)] + g line col s | null ws = [] + | "=" `elem` ws = [Stmt line [head ws] s] + | length ws > 1 && ws !! 1 == "::" = [Stmt line [head ws] (s ++ "\n" ++ head ws ++ " = undefined")] + | otherwise = [Expr line s] hunk ./Fragment.hs 33 - name = "expr_" ++ show line ++ "_" ++ show col hunk ./Fragment.hs 58 - f (x:(y:ys):xs) | isSpace y = f ((x ++ y:ys):xs) + f (x:(y:ys):xs) | not ("class " `isPrefixOf` x) && not (" " `isPrefixOf` x) && isSpace y = f ((x ++ y:ys):xs) hunk ./Fragment.hs 60 - f (x:xs) = [head $ words x | not $ null x] ++ f xs + f (x:xs) | "class " `isPrefixOf` x = providesClass x ++ f xs + f (x:xs) = [unbracket $ head $ words x | not $ null x] ++ f xs hunk ./Fragment.hs 64 +unbracket ('(':xs) = init xs +unbracket x = x + +providesClass :: String -> [String] +providesClass x = [pre !! 1] + where + pre = if "=>" `elem` ws then dropWhile (/= "=>") ws else ws + ws = words x + hunk ./Fragment.hs 82 + f (x:xs) + | "module " `isPrefixOf` x = f xs + | "import " `isPrefixOf` x = f xs + hunk ./Fragment.hs 97 -isType x = if length xs > 1 && (xs !! 1) == "::" then Just (head xs) else Nothing +isType x = if length xs > 1 && (xs !! 1) == "::" && not (isSpace $ head x) then Just (head xs) else Nothing hunk ./Fragment.hs 101 +isFunc ((' ':_):xs) = isFunc xs hunk ./Main.hs 10 - [x] <- getArgs + (x:xs) <- getArgs hunk ./Main.hs 13 - checkFragments pre $ parseFragments src + checkFragments ("-d" `elem` xs) + (parseRanges $ filter (/= "-d") xs) + pre (parseFragments src) + +parseRanges [] i = True +parseRanges xs i = f xs + where + f [] = False + f (x:xs) = parseRange x i || f xs + +parseRange ('.':'.':xs) i = i <= read xs +parseRange xs i = case b of + [] -> i == a2 + ('.':'.':x) | null x -> i >= a2 + | otherwise -> i >= a2 && i <= read x + where + (a,b) = break (== '.') xs + a2 = read a hunk ./Main.hs 5 +import System.Directory hunk ./Main.hs 13 - pre <- readFile "Include.hs" + b <- doesFileExist "Include.hs" + pre <- if b then readFile "Include.hs" else return "" addfile ./sample.tex hunk ./sample.tex 1 +We have developed a method for short-cut fusion using |foldr|/|build|. By introducing the definition: + +\begin{code} +build :: ((a -> [a] -> [a]) -> [b] -> c) -> c +build g = g (:) [] +\end{code} + +The standard definition of |map| is: + +\begin{code} +map :: (a -> b) -> [a] -> [b] +map f [] = [] +map f (x:xs) = f x : map f xs +\end{code} + +But we redefine it as: + +\begin{code} +map :: (a -> b) -> [a] -> [b] +map f = foldr ((:) . f) [] +\end{code} + +Which now allows us to have the property: + +\begin{code} +propEq g k z = foldr k z (build g) == g k z +\end{code} hunk ./Check.hs 5 -import System +import System.Cmd +import System.Exit +import System.IO hunk ./Check.hs 62 - x <- readFile "temp.txt" + x <- readFileStrict "temp.txt" hunk ./Check.hs 75 + +readFileStrict s = do + h <- openFile s ReadMode + s <- hGetContents h + length s `seq` hClose h + return s + + addfile ./tex2hs.cabal hunk ./tex2hs.cabal 1 +Name: tex2hs +Version: 0.1 +Copyright: 2006-7, Neil Mitchell +Maintainer: ndmitchell@gmail.com +Homepage: http://www-users.cs.york.ac.uk/~ndm/tex2hs/ +Build-Depends: base +License: BSD3 +Author: Neil Mitchell +Synopsis: A program to check for type errors in a Latex document/ +Category: Academic + +Executable: tex2hs +Main-Is: Main.hs addfile ./Setup.hs hunk ./Setup.hs 1 - +import Distribution.Simple +main = defaultMain hunk ./Fragment.hs 75 -providesData x = (ws!!1) : [a2 | a1:a2:as <- tails ws, a1 `elem` ["|","="]] - where ws = words x +providesData x = (ws!!1) : concat [f (a2:as) | a1:a2:as <- tails ws, a1 `elem` ["|","="]] + where + ws = words x + f ((x:xs):_) | isUpper x = [x:xs] + f xs = take 1 $ filter (":" `isPrefixOf`) xs hunk ./Main.hs 6 +import System.IO hunk ./Main.hs 12 + hSetBuffering stdin NoBuffering + hSetBuffering stdout NoBuffering hunk ./Fragment.hs 89 - f (x:xs) | isJust typ && typ /= fun = x : def : f xs + f (x:xs) | isJust typ && not (isFunc (fromJust typ) xs) = x : def : f xs hunk ./Fragment.hs 91 - def = fromJust typ ++ " = undefined" + def = "(" ++ fromJust typ ++ ") = undefined" hunk ./Fragment.hs 93 - fun = isFunc xs hunk ./Fragment.hs 99 -isType x = if length xs > 1 && (xs !! 1) == "::" && not (isSpace $ head x) then Just (head xs) else Nothing - where xs = words x +isType x | all isSpace (take 1 x) = Nothing + | otherwise = case lexemes x of + (a:"::":_) -> Just a + ("(":a:")":"::":_) -> Just a + _ -> Nothing hunk ./Fragment.hs 105 -isFunc :: [String] -> Maybe String -isFunc ((' ':_):xs) = isFunc xs -isFunc (x:xs) = if length xs > 0 then Just (head xs) else Nothing - where xs = words x -isFunc _ = Nothing + +isFunc :: String -> [String] -> Bool +isFunc name xs = name `elem` ws + where ws = takeWhile (/= "=") $ lexemes $ concat $ take 1 xs + + +lexemes :: String -> [String] +lexemes x = case lex x of + [("",_)] -> [] + [(x,y)] -> x : lexemes y hunk ./Fragment.hs 75 -providesData x = (ws!!1) : concat [f (a2:as) | a1:a2:as <- tails ws, a1 `elem` ["|","="]] +providesData x = (ws!!1) : concat [f $ takeWhile (/= "|") (a2:as) | a1:a2:as <- tails ws, a1 `elem` ["|","="]] hunk ./Fragment.hs 78 + f xs | not $ null res = res + where res = take 1 $ filter (":" `isPrefixOf`) xs hunk ./Fragment.hs 81 - f xs = take 1 $ filter (":" `isPrefixOf`) xs + f _ = [] hunk ./Fragment.hs 110 - where ws = takeWhile (/= "=") $ lexemes $ concat $ take 1 xs + where ws = takeWhile (/= "=") $ lexemes $ concat $ take 1 $ dropWhile (" " `isPrefixOf`) xs hunk ./Check.hs 17 -builtin = ["Int","Bool","Float","Integer","String","Char"] +builtin = ["where"] ++ + ["Int","Bool","Float","Integer","String","Char"] adddir ./Haskell adddir ./Latex hunk ./Fragment.hs 4 -import Data.List -import Data.Char -import Data.Maybe +import Haskell.Provides +import Haskell.Tweak +import Latex.Parser hunk ./Fragment.hs 9 -type Line = Int - hunk ./Fragment.hs 14 - hunk ./Fragment.hs 15 -parseFragments x = f $ zip [1..] (lines x) - where - f ((i,x):xs) | beginCode x = let (a,b) = break (endCode . snd) xs - code = (unlines $ map snd a) - in Stmt i (provides code) (tweak code) : f b - | ignoreCode x = f $ drop 1 $ dropWhile (not . endCode . snd) xs - | otherwise = concat (zipWith (g i) [1..] (parseLine x)) ++ f xs - f [] = [] - - g line col s | null ws = [] - | "=" `elem` ws = [Stmt line [head ws] s] - | length ws > 1 && ws !! 1 == "::" = [Stmt line [head ws] (s ++ "\n" ++ head ws ++ " = undefined")] - | otherwise = [Expr line s] - where - ws = words s - -ignoreCode = isPrefixOf "\\ignore\\begin{code}" -beginCode = isPrefixOf "\\begin{code}" -endCode = isPrefixOf "\\end{code}" - - -parseLine :: String -> [String] -parseLine ('|':'|':xs) = parseLine xs -parseLine ('|':xs) = a : parseLine b - where (a,b) = parseBar xs -parseLine xs | "\\ignore|" `isPrefixOf` xs = parseLine $ snd $ parseBar $ drop 8 xs -parseLine (x:xs) = parseLine xs -parseLine [] = [] - -parseBar ('|':'|':xs) = ('|':a,b) - where (a,b) = parseBar xs -parseBar ('|':xs) = ("",xs) -parseBar (x:xs) = (x:a,b) - where (a,b) = parseBar xs -parseBar [] = ("","") - - -provides :: String -> [String] -provides = f . lines - where - f (x:(y:ys):xs) | not ("class " `isPrefixOf` x) && not (" " `isPrefixOf` x) && isSpace y = f ((x ++ y:ys):xs) - f (x:xs) | "data " `isPrefixOf` x || "type " `isPrefixOf` x = providesData x ++ f xs - f (x:xs) | "class " `isPrefixOf` x = providesClass x ++ f xs - f (x:xs) = [unbracket $ head $ words x | not $ null x] ++ f xs - f _ = [] - -unbracket ('(':xs) = init xs -unbracket x = x - -providesClass :: String -> [String] -providesClass x = [pre !! 1] +parseFragments = map f . parseLatex hunk ./Fragment.hs 57 - where ws = takeWhile (/= "=") $ lexemes $ concat $ take 1 $ dropWhile (" " `isPrefixOf`) xs + where ws = takeWhile (/= "=") $ lexemes $ concat $ take 1 xs hunk ./Fragment.hs 60 -lexemes :: String -> [String] -lexemes x = case lex x of - [("",_)] -> [] - [(x,y)] -> x : lexemes y addfile ./Haskell/Provides.hs hunk ./Haskell/Provides.hs 1 + +module Haskell.Provides(Provides(..), provides, fromProvides, isStmt) where + +import Data.List +import Data.Char + + +data Provides = ProvidesBody String + | ProvidesSig String + | ProvidesName String + deriving (Eq,Show) + + +fromProvides (ProvidesBody x) = x +fromProvides (ProvidesSig x) = x +fromProvides (ProvidesName x) = x + + +provides :: String -> [Provides] +provides x = nub $ concatMap (provider . lexemes) $ indents $ lines x + + +indents (x:(y:ys):zs) | isSpace y = indents $ (x++" ; "++y:ys) : zs +indents (x:xs) = x : indents xs +indents [] = [] + + +isStmt x = "=" `elem` xs || "::" `elem` xs + where xs = lexemes x + + +split on xs = a : if null b then [] else split on (tail b) + where (a,b) = break (== on) xs + + +provider :: [String] -> [Provides] +provider xs = case xs of + "type":xs -> [ProvidesName $ headNote 1 con] + "data":xs -> ProvidesName (headNote 2 con) : providerCtors (map (rep "=" "|") (tail con)) + "class":xs -> ProvidesName (headNote 3 con) : concatMap provider (tail $ split ";" con) + _ | "::" `elem` xs -> providesSig xs + _ -> providesBody xs + where + con = dropContext $ tail xs + + dropContext xs = if null b then a else tail b + where (a,b) = break (== "=>") xs + + + +providerCtors = map f . tail . split "|" + where + f xs = ProvidesName $ headNote 4 $ y ++ xs + where y = filter (\x -> ":" `isPrefixOf` x && x /= "::") xs + + +providesSig = map ProvidesSig . filter (`notElem` [",","(",")"]) . takeWhile (/= "::") + + +-- approximation: +-- (symbol) +-- (...) symbol +-- ... symbol +-- name +providesBody [] = [] +providesBody xs = [ProvidesBody $ f xs] + where + f (x:ys:xs) | isSymbol ys = getSymbol (ys:xs) + f ("(":xs) = dropWhile (/= ")") xs !! 1 + f (x:xs) = x + + isSymbol (y:ys) = not (isAlpha y) && y `notElem` "([" && (y:ys) /= "=" + + getSymbol ("`":x:xs) = x + getSymbol (x:xs) = x + + +lexemes :: String -> [String] +lexemes x = case lex x of + [("",_)] -> [] + [(x,y)] -> x : lexemes y + + +rep from to x = if x == from then to else x + + +headNote i [] = error $ show i +headNote i (x:xs) = x addfile ./Haskell/Tweak.hs hunk ./Haskell/Tweak.hs 1 + +module Haskell.Tweak(tweak) where + +import Haskell.Provides +import Data.List + + +tweak :: String -> String +tweak = dummy . unlines . filter (not . isModule) . lines + where isModule x = "module " `isPrefixOf` x || "import " `isPrefixOf` x + + +dummy x = unlines (x : map f undef) + where + p = provides x + undef = [x | ProvidesSig x <- p] \\ [x | ProvidesBody x <- p] + f x = "(" ++ x ++ ") = undefined" addfile ./Latex/Parser.hs hunk ./Latex/Parser.hs 1 + +module Latex.Parser(Line, HsCode(..), parseLatex) where + +import Data.List +import Data.Char + +type Line = Int + +data HsCode = HsCode Line String + | HsExpr Line String + deriving (Eq,Show) + + + +parseLatex :: String -> [HsCode] +parseLatex x = f $ zip [1..] (lines x) + where + f ((i,x):xs) | beginCode x = let (a,b) = break (endCode . snd) xs + code = (unlines $ map snd a) + in HsCode i code : f b + | ignoreCode x = f $ drop 1 $ dropWhile (not . endCode . snd) xs + | otherwise = concat (zipWith (g i) [1..] (parseLine x)) ++ f xs + f [] = [] + + g line col s = [HsExpr line s] + + +ignoreCode = isPrefixOf "\\ignore\\begin{code}" +beginCode = isPrefixOf "\\begin{code}" +endCode = isPrefixOf "\\end{code}" + + +parseLine :: String -> [String] +parseLine ('|':'|':xs) = parseLine xs +parseLine ('|':xs) = a : parseLine b + where (a,b) = parseBar xs +parseLine xs | "\\ignore|" `isPrefixOf` xs = parseLine $ snd $ parseBar $ drop 8 xs +parseLine (x:xs) = parseLine xs +parseLine [] = [] + +parseBar ('|':'|':xs) = ('|':a,b) + where (a,b) = parseBar xs +parseBar ('|':xs) = ("",xs) +parseBar (x:xs) = (x:a,b) + where (a,b) = parseBar xs +parseBar [] = ("","") hunk ./Fragment.hs 17 - pre = if "=>" `elem` ws then dropWhile (/= "=>") ws else ws - ws = words x - - -providesData :: String -> [String] -providesData x = (ws!!1) : concat [f $ takeWhile (/= "|") (a2:as) | a1:a2:as <- tails ws, a1 `elem` ["|","="]] - where - ws = words x - f xs | not $ null res = res - where res = take 1 $ filter (":" `isPrefixOf`) xs - f ((x:xs):_) | isUpper x = [x:xs] - f _ = [] - - -tweak :: String -> String -tweak = unlines . f . lines - where - f (x:xs) - | "module " `isPrefixOf` x = f xs - | "import " `isPrefixOf` x = f xs - - f (x:xs) | isJust typ && not (isFunc (fromJust typ) xs) = x : def : f xs - where - def = "(" ++ fromJust typ ++ ") = undefined" - typ = isType x - - f (x:xs) = x : f xs - f [] = [] - - -isType :: String -> Maybe String -isType x | all isSpace (take 1 x) = Nothing - | otherwise = case lexemes x of - (a:"::":_) -> Just a - ("(":a:")":"::":_) -> Just a - _ -> Nothing - - -isFunc :: String -> [String] -> Bool -isFunc name xs = name `elem` ws - where ws = takeWhile (/= "=") $ lexemes $ concat $ take 1 xs - - + f (HsExpr line x) | isStmt x = f $ HsCode line x + f (HsCode line x) = Stmt line (map fromProvides $ provides x) (tweak x) + f (HsExpr line x) = Expr line x hunk ./Haskell/Provides.hs 40 - "class":xs -> ProvidesName (headNote 3 con) : concatMap provider (tail $ split ";" con) - _ | "::" `elem` xs -> providesSig xs + "class":xs -> ProvidesName (headNote 3 con) : map asClass (concatMap provider (tail $ split ";" con)) + _ | "::" `elem` (takeWhile (/= "where") xs) -> providesSig xs hunk ./Haskell/Provides.hs 45 + asClass = ProvidesName . fromProvides