language-ocaml-0.1.31: lib/Language/OCaml/Definitions/Parsing/Docstrings.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
module Language.OCaml.Definitions.Parsing.Docstrings
( Docs
, Docstring(..)
, Info
, Text
, addDocsAttrs
, addInfoAttrs
, addTextAttrs
, docsAttr
, docstringBody
, docstringLoc
, emptyDocs
, emptyInfo
, rhsInfo
, rhsPostText
, rhsPreText
, rhsPostExtraText
, rhsPreExtraText
, rhsText
, symbolInfo
, symbolText
, symbolTextLazy
, textAttr
) where
import GHC.Generics
import qualified Data.Map.Strict as M
import Prelude hiding (exp)
import Language.OCaml.Definitions.StdLib.Lexing
import Language.OCaml.Definitions.StdLib.Parsing as Parsing
import Language.OCaml.Definitions.Parsing.ASTTypes
import Language.OCaml.Definitions.Parsing.Location
import Language.OCaml.Definitions.Parsing.ParseTree
data DsAttached
= Unattached {- Not yet attached anything. -}
| Info {- Attached to a field or constructor. -}
| Docs {- Attached to an item or as floating text. -}
deriving (Eq, Generic, Show)
{- A docstring is "associated" with an item if there are no blank lines between
them. This is used for generating docstring ambiguity warnings. -}
data DsAssociated
= Zero {- Not associated with an item -}
| One {- Associated with one item -}
| Many
deriving (Eq, Generic, Show)
data Docstring = Docstring
{ dsBody :: String
, dsLoc :: Location
, dsAttached :: DsAttached
, dsAssociated :: DsAssociated
}
deriving (Eq, Generic, Show)
type Text = [Docstring]
textLoc :: Loc String
textLoc = Loc
{ txt = "ocaml.text"
, loc = none
}
textAttr :: Docstring -> Attribute
textAttr ds =
let exp =
Expression
{ pexpDesc = PexpConstant (PconstString (dsBody ds) Nothing)
, pexpLoc = dsLoc ds
, pexpAttributes = []
}
in
let item =
StructureItem
{ pstrDesc = PstrEval exp []
, pstrLoc = pexpLoc exp
}
in
(textLoc, PStr [item])
addTextAttrs :: [Docstring] -> [Attribute] -> [Attribute]
addTextAttrs dsl attrs = (map textAttr dsl) ++ attrs
rhsText :: a -> [b]
rhsText pos = getText (rhsStartPos pos)
getText :: a -> [b]
getText _pos = [] -- FIXME
data Docs = Docs'
{ docsPre :: Maybe Docstring
, docsPost :: Maybe Docstring
}
deriving (Eq, Generic, Show)
addDocsAttrs :: Docs -> [(Loc String, Payload)] -> [(Loc String, Payload)]
addDocsAttrs docs attrs =
let attrs1 = case docsPre docs of
Nothing -> attrs
Just ds -> docsAttr ds : attrs
in
let attrs2 = case docsPost docs of
Nothing -> attrs1
Just ds -> attrs1 ++ [docsAttr ds]
in
attrs2
addInfoAttrs :: a -> b -> b
addInfoAttrs _info attrs = attrs -- FIXME
emptyDocs :: Docs
emptyDocs =
Docs'
{ docsPre = Nothing
, docsPost = Nothing
}
docLoc :: Loc String
docLoc =
Loc
{ txt = "ocaml.doc"
, loc = none
}
docsAttr :: Docstring -> (Loc String, Payload)
docsAttr ds =
let exp = Expression
{ pexpDesc = PexpConstant $ PconstString (dsBody ds) Nothing
, pexpLoc = dsLoc ds
, pexpAttributes = []
}
in
let item = StructureItem
{ pstrDesc = PstrEval exp []
, pstrLoc = pexpLoc exp
}
in
(docLoc, PStr [item])
type Info = Maybe Docstring
emptyInfo :: Info
emptyInfo = Nothing
docstringBody :: Docstring -> String
docstringBody = dsBody
docstringLoc :: Docstring -> Location
docstringLoc = dsLoc
symbolInfo :: () -> Info
symbolInfo () = Nothing -- FIXME
symbolText :: () -> Text
symbolText () = [] -- FIXM
symbolTextLazy :: () -> Text
symbolTextLazy () = [] -- FIXMEE
preTable :: M.Map Position Text
preTable = M.empty
postTable :: M.Map Position Text
postTable = M.empty
preExtraTable :: M.Map Position Text
preExtraTable = M.empty
postExtraTable :: M.Map Position Text
postExtraTable = M.empty
getDocstrings :: [Docstring] -> [Docstring]
getDocstrings dsl = loop [] dsl
where
loop acc = \case
[] -> reverse acc
(Docstring {..}) : rest | dsAttached == Info -> loop acc rest
ds : rest -> loop (ds { dsAttached = Docs } : acc) rest
getPreText :: Position -> Text
getPreText pos = getDocstrings $ M.findWithDefault [] pos preTable
rhsPreText :: a -> Text
rhsPreText pos = getPreText (Parsing.rhsStartPos pos)
getPostText :: Position -> Text
getPostText pos = getDocstrings $ M.findWithDefault [] pos postTable
rhsPostText :: a -> Text
rhsPostText pos = getPostText (Parsing.rhsEndPos pos)
getPreExtraText :: Position -> Text
getPreExtraText pos = getDocstrings $ M.findWithDefault [] pos preExtraTable
rhsPreExtraText :: a -> Text
rhsPreExtraText pos = getPreExtraText (Parsing.rhsStartPos pos)
getPostExtraText :: Position -> Text
getPostExtraText pos = getDocstrings $ M.findWithDefault [] pos postExtraTable
rhsPostExtraText :: a -> Text
rhsPostExtraText pos = getPostExtraText (Parsing.rhsEndPos pos)
rhsInfo :: Int -> Info
rhsInfo pos = getInfo (Parsing.rhsEndPos pos)
getInfo :: Position -> Maybe Docstring
getInfo pos = M.lookup pos postTable >>= getDocstring True
getDocstring :: Bool -> [Docstring] -> Maybe Docstring
getDocstring info dsl = loop dsl
where
loop = \case
[] -> Nothing
(Docstring { dsAttached = Info }) : rest -> loop rest
ds : _ -> Just $ ds { dsAttached = if info then Info else Docs }