neil-0.0: src/Paper/Haskell2/Haskell.hs
module Paper.Haskell2.Haskell(
isHaskellSym, haskellKeywords, lexer,
defines, rename, fakeImplement
) where
import Data.Char
import Data.List
import Data.Maybe
import Paper.Util.String
haskellKeywords = ["class","instance","where","data","type","import","in","let","do","module","newtype"]
haskellKeySymbols = ["--","="]
isHaskellSym xs = all (`elem` "|+-*<>.=?&") xs && xs `notElem` haskellKeySymbols
isHaskellVar xs = isAlpha (head xs) && xs `notElem` haskellKeywords
validName xs = isHaskellSym xs || isHaskellVar xs
defines :: String -> [String]
defines = nub . filter validName . concatMap f . map lexer . classLeft . lines
where
f ("(":name:")":_) | isHaskellSym name = [name]
f ("(":xs) | isHaskellSym name = [name]
where name:_ = drop 1 $ dropWhile (/= ")") xs
f (_:name:_) | isHaskellSym name = [name]
f ("type":name:_) = [name]
f (name:_) = [name]
f _ = []
flushLeft (x:xs) = not $ isSpace x
flushLeft [] = False
classLeft (x:xs) | "class" `isPrefixOf` x = x : a ++ classLeft xs
where (a,_) = span (\x -> null x || isSpace (head x)) xs
classLeft ((x:_):xs) | isSpace x = classLeft xs
classLeft (x:xs) = x : classLeft xs
classLeft [] = []
rename :: [(String, String)] -> String -> String
rename [] = id
rename ren = concatMap f . lexerSpace
where f x = fromMaybe x $ lookup x ren
-- figure out which definitions have a type signature
-- but no associated body, and make one up
fakeImplement :: String -> String
fakeImplement xs = unlines $
["-- !typesigFunction " ++ show typ, "-- !implementsFunction " ++ show imp, xs] ++
[operator x ++ " = undefined -- stub" | x <- typ \\ imp]
where (typ,imp) = (typesigFunction xs, implementsFunction xs)
-- more a "this function is definately defined"
-- as conservative
typesigFunction :: String -> [String]
typesigFunction = nub . concatMap (typesigs . lexer) . filter flushLeft . lines
typesigs :: [String] -> [String]
typesigs = f []
where
f seen ("(":x:")":xs) = f seen (x:xs)
f seen (x:"::":xs) = x:seen
f seen (x:",":xs) = f (x:seen) xs
f _ _ = []
-- more a "this function is possibly implemented"
-- as conservative
implementsFunction :: String -> [String]
implementsFunction = nub . concatMap (f . lexer) . lines
where
f xs | not $ null $ typesigs xs = []
f (_:"`":x:"`":_) = [x]
f (_:x:_) | isHaskellSym x = [x]
f ("(":xs) | bs /= [] && isHaskellSym (head bs) = [head bs]
where bs = drop 1 $ dropWhile (/= ")") xs
f (x:xs) = [x]
f [] = []
operator (x:xs) | isAlpha x = x:xs
operator x = "(" ++ x ++ ")"
-- concat . lexerSpace == id (nearly, just comments)
lexerSpace :: String -> [String]
lexerSpace [] = []
lexerSpace xs@(x:_) | isSpace x = a : lexerSpace b
where (a,b) = span isSpace xs
lexerSpace ('{':'-':'\"':xs) = (" {-\"" ++ a ++ c) : lexerSpace d
where (a,b) = breakStr "\"-}" xs
(c,d) = splitAt 3 b
lexerSpace ('-':'-':x:xs) | isAlphaNum x || isSpace x = (" --" ++ a) : lexerSpace b
where (a,b) = break (== '\n') (x:xs)
lexerSpace xs = case lex xs of
[(a,'.':x:xs)] | isUpper x -> (a++'.':b) : c
where b:c = lexerSpace (x:xs)
[(a,b)] -> a : lexerSpace b
other -> error $ "lexerSpace, unexpected: " ++ show (xs, other)
lexer = filter (not . isSpace . head) . lexerSpace