packages feed

hoogle-3.1: src/Hoogle/Parser.hs

{-
    This file is part of Hoogle, (c) Neil Mitchell 2004-2005
    http://www.cs.york.ac.uk/~ndm/hoogle/
    
    This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License.
    To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/
    or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
-}

module Hoogle.Parser (
    parser,
    parseConType,
    validLine
    ) where

import Hoogle.Lexer
import Hoogle.TypeSig



-- | Is this line a content based line
validLine :: String -> Bool
validLine "" = False
validLine ('-':'-':_) = False
validLine _ = True


-- | Parse one line of Lexemes at a time and convert it to an item, or raise a parse error
parser :: String -> Either Item String
parser x = case lexer x of
               Left x -> parse x
               Right x -> Right x

parse :: [Lexeme] -> Either Item String
parse (VarName "module":TypeName x:[]) = Left $ Module (splitOn '.' x)

parse (VarName "class":x) = Left $ Class (readConType x)

parse (VarName "instance":x) = Left $ Instance (readConType x)

parse (VarName "keyword":xs) = Left $ Keyword $ concatMap show xs

parse (VarName "newtype":x) = Left $ Data True  (readConType x)
parse (VarName "data"   :x) = Left $ Data False (readConType x)

parse (VarName "type":x) = Left $ TypeAlias name (map (\(VarName a) -> a) args) (readConType b)
    where (TypeName name:args,_:b) = break (== EqSymbol) x

parse (TypeName x:TypeColon:typ) = Left $ Func x (readConType typ)
parse (VarName  x:TypeColon:typ) = Left $ Func x (readConType typ)

-- a data value produced by Haddock being foolish
parse [VarName  x] = Right ""
parse [TypeName x] = Right ""


parse [] = Right "Parse error: unexpected empty line"
parse (x:xs) = Right $ "Parse error: doesn't start with a keyword, or have a type annotation, " ++ show x


parseConType :: String -> Either ConType String
parseConType xs = case lexer xs of
                      Left x -> Left (readConType x)
                      Right x -> Right x


splitOn :: Eq a => a -> [a] -> [[a]]
splitOn e xs = if null b then [a] else a : splitOn e (tail b)
    where (a,b) = break (== e) xs


readConType :: [Lexeme] -> (Constraint, Type)
readConType xs = (con, readType res)
    where (con, res) = readConstraint xs


readConstraint :: [Lexeme] -> (Constraint, [Lexeme])
readConstraint (TypeColon:x) = readConstraint x
readConstraint x = if not (EqArrow `elem` x) then ([],x)
                   else (f (readType a) ++ con, lexe)
    where
        (a,b) = break (== EqArrow) x
        (con,lexe) = readConstraint (tail b)
        
        f (TList (TLit ",":xs)) = xs
        f x = [x]



readType :: [Lexeme] -> Type
readType x = f $ bracket $ filter (/= ExSymbol) x
    where
        f :: [Bracket Lexeme] -> Type
        f xs = if not (singleton tups) then TList (TLit ",":map f tups)
               else if not (singleton func) then TList (TLit "->":map f func)
               else if singleton xs then g (head xs)
               else if null xs then TVar "_"
               else TList (map g xs)
            where
                tups = splitOn (BItem Comma    ) xs
                func = splitOn (BItem LineArrow) xs
        
        g (Bracket OpenRound  x) = f x
        g (Bracket OpenSquare []) = TLit "[]"
        g (Bracket OpenSquare x) = TList [TLit "[]", f x]
        g (BItem (TypeName x)) = TLit x
        g (BItem (VarName  x)) = TVar x
        g y = error $ "Hoogle.Parser.readType: " ++ show (x,y)
    

singleton [x] = True
singleton _ = False


data Bracket x = Bracket x [Bracket x]
               | BItem x
               deriving (Eq, Show)


isOpen x = x `elem` [OpenRound, OpenSquare]
isShut x = x `elem` [ShutRound, ShutSquare]

bracket :: [Lexeme] -> [Bracket Lexeme]
bracket xs = let (a,[]) = g xs in a
    where
        f :: [Lexeme] -> (Bracket Lexeme, [Lexeme])
        f (x:xs) | isOpen x = let (a,b) = g xs in (Bracket x a, b)
        f (x:xs) = (BItem x, xs)
        
        
        g :: [Lexeme] -> ([Bracket Lexeme], [Lexeme])
        g (x:xs) | isShut x = ([], xs)
        g [] = ([], [])
        g xs = let (a,b) = f xs ; (c,d) = g b in (a:c,d)