/src/Scion/PersistentHoogle/Parser.hs

https://github.com/serras/scion-class-browser · Haskell · 168 lines · 153 code · 12 blank · 3 comment · 11 complexity · 0c0dc18704e767d664615f2e589703ca MD5 · raw file

  1. {-# LANGUAGE RankNTypes, ImpredicativeTypes, ScopedTypeVariables #-}
  2. module Scion.PersistentHoogle.Parser where
  3. import Data.List (intercalate)
  4. import qualified Data.Text as T
  5. import Database.Persist
  6. -- import Database.Persist.Base
  7. import Database.Persist.Sqlite
  8. import Database.Persist.Store
  9. import Language.Haskell.Exts.Annotated.Syntax
  10. import Scion.PersistentBrowser.DbTypes
  11. import Scion.PersistentBrowser.Parser.Internal
  12. import Scion.PersistentBrowser.Query
  13. import Scion.PersistentBrowser.Types
  14. import Scion.PersistentHoogle.Types
  15. import Text.Parsec.Char
  16. import Text.Parsec.Combinator
  17. import Text.Parsec.Prim
  18. data HalfResult = HalfPackage String
  19. | HalfModule String (Documented Module)
  20. | HalfDecl String (Documented Decl)
  21. | HalfGadtDecl String (Documented GadtDecl)
  22. | HalfKeyword String
  23. hoogleElements :: BSParser (SqlPersist IO [Result])
  24. hoogleElements = do elts <- hoogleElements'
  25. let results = catMaybesM $ map convertHalfToResult elts
  26. return results
  27. catMaybesM :: Monad m => [m (Maybe a)] -> m [a]
  28. catMaybesM [] = return []
  29. catMaybesM (x:xs) = do y <- x
  30. zs <- catMaybesM xs
  31. case y of
  32. Nothing -> return zs
  33. Just z -> return (z:zs)
  34. hoogleElements' :: BSParser [HalfResult]
  35. hoogleElements' = try (do spaces0
  36. optional $ try (do
  37. string "No results found"
  38. spacesOrEol0)
  39. eof
  40. return [])
  41. <|> (do first <- hoogleElement
  42. rest <- many $ try (try eol >> try hoogleElement)
  43. spaces
  44. eof
  45. return $ first:rest)
  46. hoogleElement :: BSParser HalfResult
  47. hoogleElement = try (do pname <- hooglePackageName
  48. return $ HalfPackage pname)
  49. <|> try (do pname <- hoogleKeyword
  50. return $ HalfKeyword pname)
  51. <|> try (do (mname, m) <- moduled (module_ NoDoc)
  52. return $ HalfModule mname m)
  53. <|> try (do (mname, d) <- moduled (function NoDoc)
  54. return $ HalfDecl mname d)
  55. <|> try (do (mname, d) <- moduled (dataHead NoDoc)
  56. return $ HalfDecl mname d)
  57. <|> try (do (mname, d) <- moduled (newtypeHead NoDoc)
  58. return $ HalfDecl mname d)
  59. <|> try (do (mname, d) <- moduled (type_ NoDoc)
  60. return $ HalfDecl mname d)
  61. <|> try (do (mname, d) <- moduled (class_ NoDoc)
  62. return $ HalfDecl mname d)
  63. <|> try (do (mname, d) <- moduled (constructor NoDoc)
  64. return $ HalfGadtDecl mname d)
  65. moduled :: BSParser a -> BSParser (String, a)
  66. moduled p = try (do mname <- try conid `sepBy` char '.'
  67. let name = intercalate "." (map getid mname)
  68. try spaces1
  69. rest <- p
  70. return (name, rest))
  71. hooglePackageName :: BSParser String
  72. hooglePackageName = do string "package"
  73. spaces1
  74. name <- restOfLine
  75. spaces0
  76. return name
  77. -- | handle a keyword. For example searching for 'id' gives 'keyword hiding' in the results
  78. hoogleKeyword :: BSParser String
  79. hoogleKeyword = do string "keyword"
  80. spaces1
  81. name <- restOfLine
  82. spaces0
  83. return name
  84. convertHalfToResult :: HalfResult -> SqlPersist IO (Maybe Result)
  85. convertHalfToResult (HalfKeyword kw) =
  86. return $ Just (RKeyword kw)
  87. convertHalfToResult (HalfPackage pname) =
  88. do pkgs <- packagesByName pname Nothing
  89. case pkgs of
  90. [] -> return Nothing
  91. p -> return $ Just (RPackage p)
  92. convertHalfToResult (HalfModule mname _) =
  93. do let sql = "SELECT DbModule.name, DbModule.doc, DbModule.packageId, DbPackage.name, DbPackage.version"
  94. ++ " FROM DbModule, DbPackage"
  95. ++ " WHERE DbModule.packageId = DbPackage.id"
  96. ++ " AND DbModule.name = ?"
  97. mods <- queryDb sql [mname] action
  98. return $ if null mods then Nothing else Just (RModule mods)
  99. where action [PersistText modName, modDoc, pkgId@(PersistInt64 _), PersistText pkgName, PersistText pkgVersion] =
  100. ( DbPackageIdentifier (T.unpack pkgName) (T.unpack pkgVersion)
  101. , DbModule (T.unpack modName) (fromDbText modDoc) (Key pkgId) )
  102. action _ = error "This should not happen"
  103. convertHalfToResult (HalfDecl mname dcl) =
  104. do let sql = "SELECT DbDecl.id, DbDecl.declType, DbDecl.name, DbDecl.doc, DbDecl.kind, DbDecl.signature, DbDecl.equals, DbDecl.moduleId"
  105. ++ ", DbPackage.name, DbPackage.version"
  106. ++ " FROM DbDecl, DbModule, DbPackage"
  107. ++ " WHERE DbDecl.moduleId = DbModule.id"
  108. ++ " AND DbModule.packageId = DbPackage.id"
  109. ++ " AND DbDecl.name = ?"
  110. ++ " AND DbModule.name = ?"
  111. decls <- queryDb sql [getName dcl, mname] action
  112. completeDecls <- mapM (\(pkgId, modName, dclKey, dclInfo) -> do complete <- getAllDeclInfo (dclKey, dclInfo)
  113. return (pkgId, modName, complete) ) decls
  114. return $ if null completeDecls then Nothing else Just (RDeclaration completeDecls)
  115. where action [ declId@(PersistInt64 _), PersistText declType, PersistText declName
  116. , declDoc, declKind, declSignature, declEquals, modId@(PersistInt64 _)
  117. , PersistText pkgName, PersistText pkgVersion ] =
  118. let (innerDclKey :: DbDeclId) = Key declId
  119. innerDcl = DbDecl (read (T.unpack declType)) (T.unpack declName) (fromDbText declDoc)
  120. (fromDbText declKind) (fromDbText declSignature) (fromDbText declEquals)
  121. (Key modId)
  122. in ( DbPackageIdentifier (T.unpack pkgName) (T.unpack pkgVersion)
  123. , mname
  124. , innerDclKey
  125. , innerDcl
  126. )
  127. action _ = error "This should not happen"
  128. convertHalfToResult (HalfGadtDecl mname dcl) =
  129. do let sql = "SELECT DbConstructor.name, DbConstructor.signature"
  130. ++ ", DbDecl.id, DbDecl.declType, DbDecl.name, DbDecl.doc, DbDecl.kind, DbDecl.signature, DbDecl.equals, DbDecl.moduleId"
  131. ++ ", DbPackage.name, DbPackage.version"
  132. ++ " FROM DbConstructor, DbDecl, DbModule, DbPackage"
  133. ++ " WHERE DbConstructor.declId = DbDecl.id"
  134. ++ " AND DbDecl.moduleId = DbModule.id"
  135. ++ " AND DbModule.packageId = DbPackage.id"
  136. ++ " AND DbDecl.name = ?"
  137. ++ " AND DbModule.name = ?"
  138. decls <- queryDb sql [getName dcl, mname] action
  139. completeDecls <- mapM (\(pkgId, modName, dclKey, dclInfo, cst) -> do complete <- getAllDeclInfo (dclKey, dclInfo)
  140. return (pkgId, modName, complete, cst) ) decls
  141. return $ if null completeDecls then Nothing else Just (RConstructor completeDecls)
  142. where action [ PersistText constName, PersistText constSignature
  143. , declId@(PersistInt64 _), PersistText declType, PersistText declName
  144. , declDoc, declKind, declSignature, declEquals, modId@(PersistInt64 _)
  145. , PersistText pkgName, PersistText pkgVersion ] =
  146. let (innerDclKey :: DbDeclId) = Key declId
  147. innerDcl = DbDecl (read (T.unpack declType)) (T.unpack declName) (fromDbText declDoc)
  148. (fromDbText declKind) (fromDbText declSignature) (fromDbText declEquals)
  149. (Key modId)
  150. in ( DbPackageIdentifier (T.unpack pkgName) (T.unpack pkgVersion)
  151. , mname
  152. , innerDclKey
  153. , innerDcl
  154. , DbConstructor (T.unpack constName) (T.unpack constSignature) (Key declId)
  155. )
  156. action _ = error "This should not happen"