@alan_zimm
ParsedSource
changing names to be longer or shorter
baz = bar where x = 1
bar = 2
SrcSpan
s are no longer meaningfulpanic "blah"
entries in
the GHC ASTParsedSource
accurately reflected the state of the original sourceXRec
ping-pong landed SrcSpan
indexing, by moving the annotations into
the ParsedSource
Make the annotations properly typed
type ApiAnnKey = (SrcSpan, AnnKeywordId)
type ApiAnns = ( Map ApiAnnKey [SrcSpan]
, Map SrcSpan [Located AnnotationComment])
data AnnKeywordId
= AnnAnyclass -- 'anyclass'
| AnnAs -- 'as'
| AnnAt -- 'at'
ParsedSource
, and separate annotationsSrcSpan
order, for adding, or
moving items around.GhcPs
. There is one per AST element.So we have
data ApiAnn' ann
= ApiAnn { anchor :: RealSrcSpan
, anns :: ann
, comments :: [RealLocated AnnotationComment]
}
| ApiAnnNotUsed
data ApiAnnHsCase = ApiAnnHsCase
{ hsCaseAnnCase :: RealSrcSpan -- 'case' location
, hsCaseAnnOf :: RealSrcSpan -- 'of' location
, hsCaseAnnsRest :: [AddApiAnn]
}
data AddApiAnn = AddApiAnn AnnKeywordId RealSrcSpan
Attached as
| HsCase (XCase p) -- TTG extension point
(LHsExpr p)
(MatchGroup p (LHsExpr p))
type instance XCase GhcPs = ApiAnn' ApiAnnHsCase -- TTG usage
-- 123456789012345
043 case x of
044 1 -> True
045 ..
(HsCase
(ApiAnn
{ (43,3)-(45,14) } -- anchor
(ApiAnnHsCase { 43:3-6 } { 43:12-13 } []) -- anns
[]) -- comments
(L (SrcSpanAnn (ApiAnnNotUsed) { 43:9 })
(HsVar .. {OccName: x}))
(MG
(NoExtField)
(L (SrcSpanAnn (ApiAnn { (44,5)-(45,14) ...))))))
(DP (0,0),"case") -- (43, 3)
(DP (0,2),"x") -- (43, 9)
(DP (0,2),"of") -- (43,12)
(DP (1,2),"1") -- (44, 5) wrt (43,3) anchor
Located
annotationsRdrName
decorations:
`foo`
,
':
,
(&)
,,
, ;
, |
Located
to piggy-back annotations.XRec
Locationstype family XRec p a = r | r -> a
-- | We can strip off the XRec to access the underlying data.
class UnXRec p where
unXRec :: XRec p a -> a
type instance XRec (GhcPass p) a = Located a
type LHsExpr p = XRec p (HsExpr p)
For exactprint in GHC we adapt it as
type instance XRec (GhcPass p) a = GenLocated (Anno a) a
type family Anno a = b
(Thanks Zubin Duggal for helping me with this)
There is a regular structure for this
data SrcSpanAnn' a = SrcSpanAnn { ann :: a, locA :: SrcSpan }
Example usage
type SrcSpanAnnA = SrcSpanAnn' (ApiAnn' AnnListItem)
type SrcSpanAnnName = SrcSpanAnn' (ApiAnn' NameAnn)
data AnnListItem
= AnnListItem {
lann_trailing :: [TrailingAnn]
}
data TrailingAnn
= AddSemiAnn RealSrcSpan
| AddCommaAnn RealSrcSpan
..
In "normal" usage we can have
type LocatedA = GenLocated SrcSpanAnnA
type LocatedN = GenLocated SrcSpanAnnName
type LocatedAn an = GenLocated (SrcSpanAnn' (ApiAnn' an))
type LHsExpr p = XRec p (HsExpr p)
type instance Anno (HsExpr (GhcPass p)) = SrcSpanAnnA
foo :: LocatedA (HsExpr GhcPs)
bar :: LHsExpr GhcPs
Note: in instance declarations, you have to use the
foo
form, which matches the "after
resolution" XRec
family.
anchor
field from earlierdata Entry = Entry RealSrcSpan [RealLocated AnnotationComment]
| NoEntryVal
class ExactPrint a where
getAnnotationEntry :: a -> Entry
exact :: a -> Annotated ()
ExactPrint
is analogous to Outputable
exact
is analogous to ppr
getAnnotationEntry
pulls it out if it
exists, together with any comments in the span of the item.enterAnn
routingSimplest example
instance (ExactPrint a) => ExactPrint (Located a) where
getAnnotationEntry (L l _) = Entry (realSrcSpan l) []
exact (L _ a) = markAnnotated a
markAnnotated
manages the process of
descending into an enclosed AST item.
markAnnotated :: ExactPrint a => a -> Annotated ()
markAnnotated a = enterAnn (getAnnotationEntry a) a
The trivial version of enterAnn
, but
showing the basic interleaving flow, is
enterAnn :: (ExactPrint a) => Entry -> a -> Annotated ()
enterAnn NoEntryVal a = do
exact a
The version where there is an EntryVal
is
enterAnn (Entry anchor cs) a = do
addComments cs
printComments anchor
off <- gets epLHS
priorEndAfterComments <- getPos
let edp = adjustDeltaForOffset
off (ss2delta priorEndAfterComments anchor)
let
st = annNone { annEntryDelta = edp }
withOffset st (advance edp >> exact a)
withOffset :: Annotation -> (EPP a -> EPP a)
withOffset a =
local (\s -> s { epAnn = a })
ExactPrint
examplesinstance ExactPrint (HsTupArg GhcPs) where
getAnnotationEntry = const NoEntryVal
exact (Present _ e) = markAnnotated e
exact (Missing _) = return ()
instance ExactPrint (HsValBindsLR GhcPs GhcPs) where
getAnnotationEntry = const NoEntryVal
exact (ValBinds sortkey binds sigs) = do
applyListAnnotations
(prepareListAnnotationA (bagToList binds)
++ prepareListAnnotationA sigs
)
prepareListAnnotationA :: ExactPrint (LocatedAn an a)
=> [LocatedAn an a] -> [(RealSrcSpan,EPP ())]
prepareListAnnotationA ls
= map (\b -> (realSrcSpan $ getLocA b,markAnnotated b)) ls
applyListAnnotations :: [(RealSrcSpan, EPP ())] -> EPP ()
applyListAnnotations ls = withSortKey ls
withSortKey :: [(RealSrcSpan, EPP ())] -> EPP ()
withSortKey xs = do
Ann{annSortKey} <- asks epAnn
let ordered = case annSortKey of
NoAnnSortKey -> sortBy orderByFst xs
Annsortkey keys -> orderByKey xs keys
mapM_ snd ordered
data AnnSortKey
= NoAnnSortKey
| AnnSortKey [RealSrcSpan]
ParsedSource
.AnnSortKey
is unnecessaryRdrName
<-> Name
<-> Id
mapping
LocatedN RdrName
SrcSpan
.@alan_zimm