summaryrefslogtreecommitdiff
path: root/testsuite/tests
diff options
context:
space:
mode:
authorAlan Zimmerman <alan.zimm@gmail.com>2014-11-21 11:20:13 -0600
committerAustin Seipp <austin@well-typed.com>2014-11-21 11:26:28 -0600
commit803fc5db31f084b73713342cdceaed5a9c664267 (patch)
tree176024676eb95211b2aadb43297f474983b7df75 /testsuite/tests
parent7927658ed1dcf557c7dd78e4b9844100521391c8 (diff)
downloadhaskell-803fc5db31f084b73713342cdceaed5a9c664267.tar.gz
Add API Annotations
Summary: The final design and discussion is captured at https://ghc.haskell.org/trac/ghc/wiki/GhcAstAnnotations This is a proof of concept implementation of a completely separate annotation structure, populated in the parser,and tied to the AST by means of a virtual "node-key" comprising the surrounding SrcSpan and a value derived from the specific constructor used for the node. The key parts of the design are the following. == The Annotations == In `hsSyn/ApiAnnotation.hs` ```lang=haskell type ApiAnns = (Map.Map ApiAnnKey SrcSpan, Map.Map SrcSpan [Located Token]) type ApiAnnKey = (SrcSpan,AnnKeywordId) -- --------------------------------------------------------------------- -- | Retrieve an annotation based on the @SrcSpan@ of the annotated AST -- element, and the known type of the annotation. getAnnotation :: ApiAnns -> SrcSpan -> AnnKeywordId -> Maybe SrcSpan getAnnotation (anns,_) span ann = Map.lookup (span,ann) anns -- |Retrieve the comments allocated to the current @SrcSpan@ getAnnotationComments :: ApiAnns -> SrcSpan -> [Located Token] getAnnotationComments (_,anns) span = case Map.lookup span anns of Just cs -> cs Nothing -> [] -- | Note: in general the names of these are taken from the -- corresponding token, unless otherwise noted data AnnKeywordId = AnnAs | AnnBang | AnnClass | AnnClose -- ^ } or ] or ) or #) etc | AnnComma | AnnDarrow | AnnData | AnnDcolon .... ``` == Capturing in the lexer/parser == The annotations are captured in the lexer / parser by extending PState to include a field In `parser/Lexer.x` ```lang=haskell data PState = PState { .... annotations :: [(ApiAnnKey,SrcSpan)] -- Annotations giving the locations of 'noise' tokens in the -- source, so that users of the GHC API can do source to -- source conversions. } ``` The lexer exposes a helper function to add an annotation ```lang=haskell addAnnotation :: SrcSpan -> Ann -> SrcSpan -> P () addAnnotation l a v = P $ \s -> POk s { annotations = ((AK l a), v) : annotations s } () ``` The parser also has some helper functions of the form ```lang=haskell type MaybeAnn = Maybe (SrcSpan -> P ()) gl = getLoc gj x = Just (gl x) ams :: Located a -> [MaybeAnn] -> P (Located a) ams a@(L l _) bs = (mapM_ (\a -> a l) $ catMaybes bs) >> return a ``` This allows annotations to be captured in the parser by means of ``` ctypedoc :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctypedoc {% hintExplicitForall (getLoc $1) >> ams (LL $ mkExplicitHsForAllTy $2 (noLoc []) $4) [mj AnnForall $1,mj AnnDot $3] } | context '=>' ctypedoc {% ams (LL $ mkQualifiedHsForAllTy $1 $3) [mj AnnDarrow $2] } | ipvar '::' type {% ams (LL (HsIParamTy (unLoc $1) $3)) [mj AnnDcolon $2] } | typedoc { $1 } ``` == Parse result == ```lang-haskell data HsParsedModule = HsParsedModule { hpm_module :: Located (HsModule RdrName), hpm_src_files :: [FilePath], -- ^ extra source files (e.g. from #includes). The lexer collects -- these from '# <file> <line>' pragmas, which the C preprocessor -- leaves behind. These files and their timestamps are stored in -- the .hi file, so that we can force recompilation if any of -- them change (#3589) hpm_annotations :: ApiAnns } -- | The result of successful parsing. data ParsedModule = ParsedModule { pm_mod_summary :: ModSummary , pm_parsed_source :: ParsedSource , pm_extra_src_files :: [FilePath] , pm_annotations :: ApiAnns } ``` This diff depends on D426 Test Plan: sh ./validate Reviewers: austin, simonpj, Mikolaj Reviewed By: simonpj, Mikolaj Subscribers: Mikolaj, goldfire, thomie, carter Differential Revision: https://phabricator.haskell.org/D438 GHC Trac Issues: #9628
Diffstat (limited to 'testsuite/tests')
-rw-r--r--testsuite/tests/ghc-api/annotations/.gitignore7
-rw-r--r--testsuite/tests/ghc-api/annotations/AnnotationLet.hs12
-rw-r--r--testsuite/tests/ghc-api/annotations/AnnotationTuple.hs20
-rw-r--r--testsuite/tests/ghc-api/annotations/CommentsTest.hs13
-rw-r--r--testsuite/tests/ghc-api/annotations/Makefile21
-rw-r--r--testsuite/tests/ghc-api/annotations/all.T4
-rw-r--r--testsuite/tests/ghc-api/annotations/annotations.hs58
-rw-r--r--testsuite/tests/ghc-api/annotations/annotations.stdout51
-rw-r--r--testsuite/tests/ghc-api/annotations/comments.hs64
-rw-r--r--testsuite/tests/ghc-api/annotations/comments.stdout24
-rw-r--r--testsuite/tests/ghc-api/annotations/parseTree.hs102
-rw-r--r--testsuite/tests/ghc-api/annotations/parseTree.stdout122
12 files changed, 498 insertions, 0 deletions
diff --git a/testsuite/tests/ghc-api/annotations/.gitignore b/testsuite/tests/ghc-api/annotations/.gitignore
new file mode 100644
index 0000000000..61d9b24b9e
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/.gitignore
@@ -0,0 +1,7 @@
+annotations
+parseTree
+comments
+*.hi
+*.o
+*.run.*
+*.normalised
diff --git a/testsuite/tests/ghc-api/annotations/AnnotationLet.hs b/testsuite/tests/ghc-api/annotations/AnnotationLet.hs
new file mode 100644
index 0000000000..de30f8baaf
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/AnnotationLet.hs
@@ -0,0 +1,12 @@
+module AnnotationLet (foo) where
+
+{
+import qualified Data.List as DL
+;
+foo = let
+ a 0 = 1
+ a _ = 2
+ b = 2
+ in a b
+
+}
diff --git a/testsuite/tests/ghc-api/annotations/AnnotationTuple.hs b/testsuite/tests/ghc-api/annotations/AnnotationTuple.hs
new file mode 100644
index 0000000000..1eced4d2cb
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/AnnotationTuple.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE TupleSections #-}
+module AnnotationTuple (foo) where
+
+{
+import qualified Data.List as DL
+;
+foo = let
+ a = 1
+ b = 2
+ in a + b
+
+;
+bar = print $ map (1, "hello" , 6.5,, [5, 5, 6, 7]) [Just (), Nothing]
+;
+baz = (1, "hello", 6.5,,,,) 'a' (Just ())
+}
+-- Note: the trailing whitespace in this file is used to check that we
+-- have an annotation for it.
+
+
diff --git a/testsuite/tests/ghc-api/annotations/CommentsTest.hs b/testsuite/tests/ghc-api/annotations/CommentsTest.hs
new file mode 100644
index 0000000000..ce0f336d39
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/CommentsTest.hs
@@ -0,0 +1,13 @@
+{-# LANGUAGE DeriveFoldable #-}
+module CommentsTest (foo) where
+{-
+An opening comment
+-}
+
+import qualified Data.List as DL
+
+-- | The function @foo@ does blah
+foo = let
+ a = 1
+ b = 2 -- value 2
+ in a + b
diff --git a/testsuite/tests/ghc-api/annotations/Makefile b/testsuite/tests/ghc-api/annotations/Makefile
new file mode 100644
index 0000000000..d5c7bd4973
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/Makefile
@@ -0,0 +1,21 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+clean:
+ rm -f *.o *.hi
+
+annotations: clean
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make -v0 -package ghc annotations
+ ./annotations "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`"
+
+parseTree: clean
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make -v0 -package ghc parseTree
+ ./parseTree "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`"
+
+comments: clean
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make -v0 -package ghc comments
+ ./comments "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`"
+
+
+.PHONY: clean
diff --git a/testsuite/tests/ghc-api/annotations/all.T b/testsuite/tests/ghc-api/annotations/all.T
new file mode 100644
index 0000000000..54da2efda4
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/all.T
@@ -0,0 +1,4 @@
+test('annotations', normal, run_command, ['$MAKE -s --no-print-directory annotations'])
+test('parseTree', normal, run_command, ['$MAKE -s --no-print-directory parseTree'])
+test('comments', normal, run_command, ['$MAKE -s --no-print-directory comments'])
+
diff --git a/testsuite/tests/ghc-api/annotations/annotations.hs b/testsuite/tests/ghc-api/annotations/annotations.hs
new file mode 100644
index 0000000000..fe952601d2
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/annotations.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE RankNTypes #-}
+
+-- This program must be called with GHC's libdir as the single command line
+-- argument.
+module Main where
+
+-- import Data.Generics
+import Data.Data
+import Data.List
+import System.IO
+import GHC
+import DynFlags
+import MonadUtils
+import Outputable
+import Bag (filterBag,isEmptyBag)
+import System.Directory (removeFile)
+import System.Environment( getArgs )
+import qualified Data.Map as Map
+import Data.Dynamic ( fromDynamic,Dynamic )
+
+main::IO()
+main = do
+ [libdir] <- getArgs
+ testOneFile libdir "AnnotationLet"
+
+testOneFile libdir fileName = do
+ p <- runGhc (Just libdir) $ do
+ dflags <- getSessionDynFlags
+ setSessionDynFlags dflags
+ let mn =mkModuleName fileName
+ addTarget Target { targetId = TargetModule mn
+ , targetAllowObjCode = True
+ , targetContents = Nothing }
+ load LoadAllTargets
+ modSum <- getModSummary mn
+ p <- parseModule modSum
+ t <- typecheckModule p
+ d <- desugarModule t
+ l <- loadModule d
+ let ts=typecheckedSource l
+ r =renamedSource l
+ -- liftIO (putStr (showSDocDebug (ppr ts)))
+ return (pm_annotations p)
+
+ let anns = p
+ (l,_) = fst $ head $ Map.toList (fst anns)
+ annModule = (getAnnotation anns l AnnModule)
+ annLet = (getAnnotation anns l AnnLet)
+
+ putStrLn (intercalate "\n" [showAnns anns,pp annModule,pp annLet,pp l])
+
+showAnns (anns,_) = "[\n" ++ (intercalate "\n"
+ $ map (\((s,k),v)
+ -> ("(AK " ++ pp s ++ " " ++ show k ++" = " ++ pp v ++ ")\n"))
+ $ Map.toList anns)
+ ++ "]\n"
+
+pp a = showPpr unsafeGlobalDynFlags a
diff --git a/testsuite/tests/ghc-api/annotations/annotations.stdout b/testsuite/tests/ghc-api/annotations/annotations.stdout
new file mode 100644
index 0000000000..e0c311eb18
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/annotations.stdout
@@ -0,0 +1,51 @@
+[
+(AK AnnotationLet.hs:1:1 AnnClose = [AnnotationLet.hs:12:1])
+
+(AK AnnotationLet.hs:1:1 AnnModule = [AnnotationLet.hs:1:1-6])
+
+(AK AnnotationLet.hs:1:1 AnnOpen = [AnnotationLet.hs:3:1])
+
+(AK AnnotationLet.hs:1:1 AnnSemi = [AnnotationLet.hs:5:1])
+
+(AK AnnotationLet.hs:1:1 AnnWhere = [AnnotationLet.hs:1:28-32])
+
+(AK AnnotationLet.hs:1:22-26 AnnClose = [AnnotationLet.hs:1:26])
+
+(AK AnnotationLet.hs:1:22-26 AnnOpen = [AnnotationLet.hs:1:22])
+
+(AK AnnotationLet.hs:4:1-32 AnnAs = [AnnotationLet.hs:4:28-29])
+
+(AK AnnotationLet.hs:4:1-32 AnnImport = [AnnotationLet.hs:4:1-6])
+
+(AK AnnotationLet.hs:4:1-32 AnnQualified = [AnnotationLet.hs:4:8-16])
+
+(AK AnnotationLet.hs:(6,1)-(10,12) AnnEqual = [AnnotationLet.hs:6:5])
+
+(AK AnnotationLet.hs:(6,1)-(10,12) AnnFunId = [AnnotationLet.hs:6:1-3])
+
+(AK AnnotationLet.hs:(6,7)-(10,12) AnnIn = [AnnotationLet.hs:10:7-8])
+
+(AK AnnotationLet.hs:(6,7)-(10,12) AnnLet = [AnnotationLet.hs:6:7-9])
+
+(AK AnnotationLet.hs:7:9-15 AnnEqual = [AnnotationLet.hs:7:13])
+
+(AK AnnotationLet.hs:7:9-15 AnnFunId = [AnnotationLet.hs:7:9])
+
+(AK AnnotationLet.hs:8:9-15 AnnEqual = [AnnotationLet.hs:8:13])
+
+(AK AnnotationLet.hs:8:9-15 AnnFunId = [AnnotationLet.hs:8:9])
+
+(AK AnnotationLet.hs:8:9-15 AnnSemi = [AnnotationLet.hs:8:9])
+
+(AK AnnotationLet.hs:9:9-13 AnnEqual = [AnnotationLet.hs:9:11])
+
+(AK AnnotationLet.hs:9:9-13 AnnFunId = [AnnotationLet.hs:9:9])
+
+(AK AnnotationLet.hs:9:9-13 AnnSemi = [AnnotationLet.hs:9:9])
+
+(AK <no location info> AnnEofPos = [AnnotationLet.hs:13:1])
+]
+
+[AnnotationLet.hs:1:1-6]
+[]
+AnnotationLet.hs:1:1
diff --git a/testsuite/tests/ghc-api/annotations/comments.hs b/testsuite/tests/ghc-api/annotations/comments.hs
new file mode 100644
index 0000000000..1fb1d41903
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/comments.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE RankNTypes #-}
+
+-- This program must be called with GHC's libdir as the single command line
+-- argument.
+module Main where
+
+-- import Data.Generics
+import Data.Data
+import Data.List
+import System.IO
+import GHC
+import DynFlags
+import MonadUtils
+import Outputable
+import Bag (filterBag,isEmptyBag)
+import System.Directory (removeFile)
+import System.Environment( getArgs )
+import qualified Data.Map as Map
+import Data.Dynamic ( fromDynamic,Dynamic )
+
+main::IO()
+main = do
+ [libdir] <- getArgs
+ testOneFile libdir "CommentsTest" True
+ testOneFile libdir "CommentsTest" False
+
+testOneFile libdir fileName useHaddock = do
+ p <- runGhc (Just libdir) $ do
+ dflags <- getSessionDynFlags
+ let dflags' = if useHaddock
+ then gopt_set (gopt_set dflags Opt_Haddock)
+ Opt_KeepRawTokenStream
+ else gopt_set (gopt_unset dflags Opt_Haddock)
+ Opt_KeepRawTokenStream
+ setSessionDynFlags dflags'
+ let mn =mkModuleName fileName
+ addTarget Target { targetId = TargetModule mn
+ , targetAllowObjCode = True
+ , targetContents = Nothing }
+ load LoadAllTargets
+ modSum <- getModSummary mn
+ p <- parseModule modSum
+ t <- typecheckModule p
+ d <- desugarModule t
+ l <- loadModule d
+ let ts=typecheckedSource l
+ r =renamedSource l
+ -- liftIO (putStr (showSDocDebug (ppr ts)))
+ return (pm_annotations p)
+
+ let anns = p
+
+ putStrLn (intercalate "\n" [showAnns anns])
+
+showAnns (_,anns) = "[\n" ++ (intercalate "\n"
+ $ map (\(s,v)
+ -> ("( " ++ pp s ++" =\n[" ++ showToks v ++ "])\n"))
+ $ Map.toList anns)
+ ++ "]\n"
+
+showToks ts = intercalate ",\n\n"
+ $ map (\(L p t) -> "(" ++ pp p ++ "," ++ show t ++ ")") ts
+
+pp a = showPpr unsafeGlobalDynFlags a
diff --git a/testsuite/tests/ghc-api/annotations/comments.stdout b/testsuite/tests/ghc-api/annotations/comments.stdout
new file mode 100644
index 0000000000..82ae6e1f50
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/comments.stdout
@@ -0,0 +1,24 @@
+[
+( CommentsTest.hs:(10,7)-(13,14) =
+[(CommentsTest.hs:12:15-24,AnnLineComment "-- value 2")])
+
+( <no location info> =
+[(CommentsTest.hs:9:1-33,AnnDocCommentNext " The function @foo@ does blah"),
+
+(CommentsTest.hs:(3,1)-(5,2),AnnBlockComment "\nAn opening comment\n"),
+
+(CommentsTest.hs:1:1-31,AnnBlockComment "# LANGUAGE DeriveFoldable #")])
+]
+
+[
+( CommentsTest.hs:(10,7)-(13,14) =
+[(CommentsTest.hs:12:15-24,AnnLineComment "-- value 2")])
+
+( <no location info> =
+[(CommentsTest.hs:9:1-33,AnnLineComment "-- | The function @foo@ does blah"),
+
+(CommentsTest.hs:(3,1)-(5,2),AnnBlockComment "\nAn opening comment\n"),
+
+(CommentsTest.hs:1:1-31,AnnBlockComment "# LANGUAGE DeriveFoldable #")])
+]
+
diff --git a/testsuite/tests/ghc-api/annotations/parseTree.hs b/testsuite/tests/ghc-api/annotations/parseTree.hs
new file mode 100644
index 0000000000..2794f22607
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/parseTree.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE RankNTypes #-}
+
+-- This program must be called with GHC's libdir as the single command line
+-- argument.
+module Main where
+
+-- import Data.Generics
+import Data.Data
+import Data.List
+import System.IO
+import GHC
+import BasicTypes
+import DynFlags
+import MonadUtils
+import Outputable
+import Bag (filterBag,isEmptyBag)
+import System.Directory (removeFile)
+import System.Environment( getArgs )
+import qualified Data.Map as Map
+import Data.Dynamic ( fromDynamic,Dynamic )
+
+main::IO()
+main = do
+ [libdir] <- getArgs
+ testOneFile libdir "AnnotationTuple"
+
+testOneFile libdir fileName = do
+ ((anns,cs),p) <- runGhc (Just libdir) $ do
+ dflags <- getSessionDynFlags
+ setSessionDynFlags dflags
+ let mn =mkModuleName fileName
+ addTarget Target { targetId = TargetModule mn
+ , targetAllowObjCode = True
+ , targetContents = Nothing }
+ load LoadAllTargets
+ modSum <- getModSummary mn
+ p <- parseModule modSum
+ t <- typecheckModule p
+ d <- desugarModule t
+ l <- loadModule d
+ let ts=typecheckedSource l
+ r =renamedSource l
+ return (pm_annotations p,p)
+
+ let tupArgs = gq (pm_parsed_source p)
+
+ putStrLn (pp tupArgs)
+ putStrLn (intercalate "\n" [showAnns anns])
+
+ where
+ gq ast = everything (++) ([] `mkQ` doLHsTupArg) ast
+
+ doLHsTupArg :: LHsTupArg RdrName -> [(SrcSpan,String,HsExpr RdrName)]
+ doLHsTupArg (L l arg@(Present _)) = [(l,"p",ExplicitTuple [L l arg] Boxed)]
+ doLHsTupArg (L l arg@(Missing _)) = [(l,"m",ExplicitTuple [L l arg] Boxed)]
+
+
+showAnns anns = "[\n" ++ (intercalate "\n"
+ $ map (\((s,k),v)
+ -> ("(AK " ++ pp s ++ " " ++ show k ++" = " ++ pp v ++ ")\n"))
+ $ Map.toList anns)
+ ++ "]\n"
+
+pp a = showPpr unsafeGlobalDynFlags a
+
+
+-- ---------------------------------------------------------------------
+
+-- Copied from syb for the test
+
+
+-- | Generic queries of type \"r\",
+-- i.e., take any \"a\" and return an \"r\"
+--
+type GenericQ r = forall a. Data a => a -> r
+
+
+-- | Make a generic query;
+-- start from a type-specific case;
+-- return a constant otherwise
+--
+mkQ :: ( Typeable a
+ , Typeable b
+ )
+ => r
+ -> (b -> r)
+ -> a
+ -> r
+(r `mkQ` br) a = case cast a of
+ Just b -> br b
+ Nothing -> r
+
+
+
+-- | Summarise all nodes in top-down, left-to-right order
+everything :: (r -> r -> r) -> GenericQ r -> GenericQ r
+
+-- Apply f to x to summarise top-level node;
+-- use gmapQ to recurse into immediate subterms;
+-- use ordinary foldl to reduce list of intermediate results
+
+everything k f x = foldl k (f x) (gmapQ (everything k f) x)
diff --git a/testsuite/tests/ghc-api/annotations/parseTree.stdout b/testsuite/tests/ghc-api/annotations/parseTree.stdout
new file mode 100644
index 0000000000..b8b9aa69b7
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/parseTree.stdout
@@ -0,0 +1,122 @@
+[(AnnotationTuple.hs:13:20, [p], (1)),
+ (AnnotationTuple.hs:13:23-29, [p], ("hello")),
+ (AnnotationTuple.hs:13:35-37, [p], (6.5)),
+ (AnnotationTuple.hs:13:38, [m], ()),
+ (AnnotationTuple.hs:13:41-52, [p], ([5, 5, 6, 7])),
+ (AnnotationTuple.hs:15:8, [p], (1)),
+ (AnnotationTuple.hs:15:11-17, [p], ("hello")),
+ (AnnotationTuple.hs:15:20-22, [p], (6.5)),
+ (AnnotationTuple.hs:15:23, [m], ()),
+ (AnnotationTuple.hs:15:24, [m], ()),
+ (AnnotationTuple.hs:15:25, [m], ()),
+ (AnnotationTuple.hs:15:26, [m], ())]
+[
+(AK AnnotationTuple.hs:1:1 AnnClose = [AnnotationTuple.hs:16:1])
+
+(AK AnnotationTuple.hs:1:1 AnnModule = [AnnotationTuple.hs:2:1-6])
+
+(AK AnnotationTuple.hs:1:1 AnnOpen = [AnnotationTuple.hs:4:1])
+
+(AK AnnotationTuple.hs:1:1 AnnSemi = [AnnotationTuple.hs:6:1])
+
+(AK AnnotationTuple.hs:1:1 AnnWhere = [AnnotationTuple.hs:2:30-34])
+
+(AK AnnotationTuple.hs:2:24-28 AnnClose = [AnnotationTuple.hs:2:28])
+
+(AK AnnotationTuple.hs:2:24-28 AnnOpen = [AnnotationTuple.hs:2:24])
+
+(AK AnnotationTuple.hs:5:1-32 AnnAs = [AnnotationTuple.hs:5:28-29])
+
+(AK AnnotationTuple.hs:5:1-32 AnnImport = [AnnotationTuple.hs:5:1-6])
+
+(AK AnnotationTuple.hs:5:1-32 AnnQualified = [AnnotationTuple.hs:5:8-16])
+
+(AK AnnotationTuple.hs:(7,1)-(10,14) AnnEqual = [AnnotationTuple.hs:7:5])
+
+(AK AnnotationTuple.hs:(7,1)-(10,14) AnnFunId = [AnnotationTuple.hs:7:1-3])
+
+(AK AnnotationTuple.hs:(7,7)-(10,14) AnnIn = [AnnotationTuple.hs:10:7-8])
+
+(AK AnnotationTuple.hs:(7,7)-(10,14) AnnLet = [AnnotationTuple.hs:7:7-9])
+
+(AK AnnotationTuple.hs:8:9-13 AnnEqual = [AnnotationTuple.hs:8:11])
+
+(AK AnnotationTuple.hs:8:9-13 AnnFunId = [AnnotationTuple.hs:8:9])
+
+(AK AnnotationTuple.hs:9:9-13 AnnEqual = [AnnotationTuple.hs:9:11])
+
+(AK AnnotationTuple.hs:9:9-13 AnnFunId = [AnnotationTuple.hs:9:9])
+
+(AK AnnotationTuple.hs:9:9-13 AnnSemi = [AnnotationTuple.hs:9:9])
+
+(AK AnnotationTuple.hs:13:1-72 AnnEqual = [AnnotationTuple.hs:13:5])
+
+(AK AnnotationTuple.hs:13:1-72 AnnFunId = [AnnotationTuple.hs:13:1-3])
+
+(AK AnnotationTuple.hs:13:1-72 AnnSemi = [AnnotationTuple.hs:12:1])
+
+(AK AnnotationTuple.hs:13:19-53 AnnClose = [AnnotationTuple.hs:13:53])
+
+(AK AnnotationTuple.hs:13:19-53 AnnOpen = [AnnotationTuple.hs:13:19])
+
+(AK AnnotationTuple.hs:13:20 AnnComma = [AnnotationTuple.hs:13:21])
+
+(AK AnnotationTuple.hs:13:23-29 AnnComma = [AnnotationTuple.hs:13:33])
+
+(AK AnnotationTuple.hs:13:35-37 AnnComma = [AnnotationTuple.hs:13:38])
+
+(AK AnnotationTuple.hs:13:39 AnnComma = [AnnotationTuple.hs:13:39])
+
+(AK AnnotationTuple.hs:13:41-52 AnnClose = [AnnotationTuple.hs:13:52])
+
+(AK AnnotationTuple.hs:13:41-52 AnnOpen = [AnnotationTuple.hs:13:41])
+
+(AK AnnotationTuple.hs:13:42 AnnComma = [AnnotationTuple.hs:13:43])
+
+(AK AnnotationTuple.hs:13:45 AnnComma = [AnnotationTuple.hs:13:46])
+
+(AK AnnotationTuple.hs:13:48 AnnComma = [AnnotationTuple.hs:13:49])
+
+(AK AnnotationTuple.hs:13:55-72 AnnClose = [AnnotationTuple.hs:13:72])
+
+(AK AnnotationTuple.hs:13:55-72 AnnOpen = [AnnotationTuple.hs:13:55])
+
+(AK AnnotationTuple.hs:13:56-62 AnnComma = [AnnotationTuple.hs:13:63])
+
+(AK AnnotationTuple.hs:13:61-62 AnnClose = [AnnotationTuple.hs:13:62])
+
+(AK AnnotationTuple.hs:13:61-62 AnnOpen = [AnnotationTuple.hs:13:61])
+
+(AK AnnotationTuple.hs:15:1-41 AnnEqual = [AnnotationTuple.hs:15:5])
+
+(AK AnnotationTuple.hs:15:1-41 AnnFunId = [AnnotationTuple.hs:15:1-3])
+
+(AK AnnotationTuple.hs:15:1-41 AnnSemi = [AnnotationTuple.hs:14:1])
+
+(AK AnnotationTuple.hs:15:7-27 AnnClose = [AnnotationTuple.hs:15:27])
+
+(AK AnnotationTuple.hs:15:7-27 AnnOpen = [AnnotationTuple.hs:15:7])
+
+(AK AnnotationTuple.hs:15:8 AnnComma = [AnnotationTuple.hs:15:9])
+
+(AK AnnotationTuple.hs:15:11-17 AnnComma = [AnnotationTuple.hs:15:18])
+
+(AK AnnotationTuple.hs:15:20-22 AnnComma = [AnnotationTuple.hs:15:23])
+
+(AK AnnotationTuple.hs:15:24 AnnComma = [AnnotationTuple.hs:15:24])
+
+(AK AnnotationTuple.hs:15:25 AnnComma = [AnnotationTuple.hs:15:25])
+
+(AK AnnotationTuple.hs:15:26 AnnComma = [AnnotationTuple.hs:15:26])
+
+(AK AnnotationTuple.hs:15:33-41 AnnClose = [AnnotationTuple.hs:15:41])
+
+(AK AnnotationTuple.hs:15:33-41 AnnOpen = [AnnotationTuple.hs:15:33])
+
+(AK AnnotationTuple.hs:15:39-40 AnnClose = [AnnotationTuple.hs:15:40])
+
+(AK AnnotationTuple.hs:15:39-40 AnnOpen = [AnnotationTuple.hs:15:39])
+
+(AK <no location info> AnnEofPos = [AnnotationTuple.hs:21:1])
+]
+