diff options
-rw-r--r-- | src/HaddockHtml.hs | 147 | ||||
-rw-r--r-- | src/HaddockLex.x | 2 | ||||
-rw-r--r-- | src/HaddockTypes.hs | 5 | ||||
-rw-r--r-- | src/HsLexer.lhs | 209 | ||||
-rw-r--r-- | src/HsParseMonad.lhs | 19 | ||||
-rw-r--r-- | src/HsParseUtils.lhs | 4 | ||||
-rw-r--r-- | src/HsParser.ly | 10 | ||||
-rw-r--r-- | src/HsSyn.lhs | 4 | ||||
-rw-r--r-- | src/Main.hs | 15 |
9 files changed, 238 insertions, 177 deletions
diff --git a/src/HaddockHtml.hs b/src/HaddockHtml.hs index 420eab26..b04ee3c2 100644 --- a/src/HaddockHtml.hs +++ b/src/HaddockHtml.hs @@ -148,7 +148,8 @@ spliceSrcURL :: Interface -> String -> String spliceSrcURL iface url = run url where run "" = "" run ('%':'M':rest) = modl_str ++ run rest - run ('%':'F':rest) = iface_filename iface ++ run rest + run ('%':'N':rest) = run rest + run ('%':'F':rest) = iface_orig_filename iface ++ run rest run (c:rest) = c : run rest modl_str = case iface_module iface of { Module m -> @@ -492,13 +493,13 @@ ppHtmlModule odir doctitle pageHeader mdl iface doctitle maybe_source_url maybe_wiki_url maybe_contents_url maybe_index_url </> s15 </> - ifaceToHtml mdl maybe_wiki_url iface </> s15 </> + ifaceToHtml maybe_source_url maybe_wiki_url iface </> s15 </> footer ) writeFile (pathJoin [odir, moduleHtmlFile mdl]) (renderHtml html) -ifaceToHtml :: String -> Maybe String -> Interface -> HtmlTable -ifaceToHtml _ maybe_wiki_url iface +ifaceToHtml :: Maybe String -> Maybe String -> Interface -> HtmlTable +ifaceToHtml maybe_source_url maybe_wiki_url iface = abovesSep s15 (contents: description: synopsis: maybe_doc_hdr: bdy) where exports = numberSectionHeadings (iface_exports iface) @@ -526,7 +527,7 @@ ifaceToHtml _ maybe_wiki_url iface = (tda [theclass "section1"] << toHtml "Synopsis") </> s15 </> (tda [theclass "body"] << vanillaTable << - abovesSep s8 (map (processExport True Nothing) + abovesSep s8 (map (processExport True linksInfo) (filter forSummary exports)) ) @@ -538,10 +539,8 @@ ifaceToHtml _ maybe_wiki_url iface ExportGroup _ _ _ : _ -> Html.emptyTable _ -> tda [ theclass "section1" ] << toHtml "Documentation" - bdy = map (processExport False wiki_info) exports - wiki_info = case maybe_wiki_url of - Nothing -> Nothing - Just wiki_url -> Just (wiki_url, iface_module iface) + bdy = map (processExport False linksInfo) exports + linksInfo = (maybe_source_url, maybe_wiki_url, iface) ppModuleContents :: [ExportItem] -> HtmlTable ppModuleContents exports @@ -577,14 +576,14 @@ numberSectionHeadings exports = go 1 exports go n (other:es) = other : go n es --- The base URL for wiki links, and the current module -type WikiInfo = Maybe (String, Module) +-- The URL for source and wiki links, and the current module +type LinksInfo = (Maybe String, Maybe String, Interface) -processExport :: Bool -> WikiInfo -> ExportItem -> HtmlTable +processExport :: Bool -> LinksInfo -> ExportItem -> HtmlTable processExport _ _ (ExportGroup lev id0 doc) = ppDocGroup lev (namedAnchor id0 << docToHtml doc) -processExport summary wiki (ExportDecl x decl insts) - = doDecl summary wiki x decl insts +processExport summary links (ExportDecl x decl insts) + = doDecl summary links x decl insts processExport summmary _ (ExportNoDecl _ y []) = declBox (ppHsQName y) processExport summmary _ (ExportNoDecl _ y subs) @@ -609,36 +608,36 @@ ppDocGroup lev doc -- ----------------------------------------------------------------------------- -- Converting declarations to HTML -declWithDoc :: Bool -> WikiInfo -> HsName -> Maybe Doc -> Html -> HtmlTable -declWithDoc True _ _ _ html_decl = declBox html_decl -declWithDoc False wiki nm Nothing html_decl = topDeclBox wiki nm html_decl -declWithDoc False wiki nm (Just doc) html_decl = - topDeclBox wiki nm html_decl </> docBox (docToHtml doc) +declWithDoc :: Bool -> LinksInfo -> SrcLoc -> HsName -> Maybe Doc -> Html -> HtmlTable +declWithDoc True _ _ _ _ html_decl = declBox html_decl +declWithDoc False links loc nm Nothing html_decl = topDeclBox links loc nm html_decl +declWithDoc False links loc nm (Just doc) html_decl = + topDeclBox links loc nm html_decl </> docBox (docToHtml doc) -doDecl :: Bool -> WikiInfo -> HsQName -> HsDecl -> [InstHead] -> HtmlTable -doDecl summary wiki x d instances = do_decl d +doDecl :: Bool -> LinksInfo -> HsQName -> HsDecl -> [InstHead] -> HtmlTable +doDecl summary links x d instances = do_decl d where - do_decl (HsTypeSig _ [nm] ty doc) - = ppFunSig summary wiki nm ty doc + do_decl (HsTypeSig loc [nm] ty doc) + = ppFunSig summary links loc nm ty doc - do_decl (HsForeignImport _ _ _ _ n ty doc) - = ppFunSig summary wiki n ty doc + do_decl (HsForeignImport loc _ _ _ n ty doc) + = ppFunSig summary links loc n ty doc - do_decl (HsTypeDecl _ nm args ty doc) - = declWithDoc summary wiki nm doc ( + do_decl (HsTypeDecl loc nm args ty doc) + = declWithDoc summary links loc nm doc ( hsep ([keyword "type", ppHsBinder summary nm] ++ map ppHsName args) <+> equals <+> ppHsType ty) do_decl (HsNewTypeDecl loc ctx nm args con drv doc) - = ppHsDataDecl summary wiki instances True{-is newtype-} x + = ppHsDataDecl summary links instances True{-is newtype-} x (HsDataDecl loc ctx nm args [con] drv doc) -- print it as a single-constructor datatype do_decl d0@(HsDataDecl{}) - = ppHsDataDecl summary wiki instances False{-not newtype-} x d0 + = ppHsDataDecl summary links instances False{-not newtype-} x d0 do_decl d0@(HsClassDecl{}) - = ppHsClassDecl summary wiki instances x d0 + = ppHsClassDecl summary links instances x d0 do_decl (HsDocGroup _ lev str) = if summary then Html.emptyTable @@ -653,7 +652,7 @@ ppTypeSig summary nm ty = ppHsBinder summary nm <+> dcolon <+> ppHsType ty -- ----------------------------------------------------------------------------- -- Data & newtype declarations -ppShortDataDecl :: Bool -> WikiInfo -> Bool -> HsDecl -> Html +ppShortDataDecl :: Bool -> LinksInfo -> Bool -> HsDecl -> Html ppShortDataDecl summary _ is_newty (HsDataDecl _ _ nm args [con] _ _doc) = ppHsDataHeader summary is_newty nm args @@ -661,10 +660,10 @@ ppShortDataDecl summary _ is_newty ppShortDataDecl summary _ is_newty (HsDataDecl _ _ nm args [] _ _doc) = ppHsDataHeader summary is_newty nm args -ppShortDataDecl summary wiki is_newty - (HsDataDecl _ _ nm args cons _ _doc) = +ppShortDataDecl summary links is_newty + (HsDataDecl loc _ nm args cons _ _doc) = vanillaTable << ( - (if summary then declBox else topDeclBox wiki nm) + (if summary then declBox else topDeclBox links loc nm) (ppHsDataHeader summary is_newty nm args) </> tda [theclass "body"] << vanillaTable << ( aboves (zipWith do_constr ('=':repeat '|') cons) @@ -675,10 +674,10 @@ ppShortDataDecl _ _ _ d = error $ "HaddockHtml.ppShortDataDecl: unexpected decl " ++ show d -- The rest of the cases: -ppHsDataDecl :: Ord key => Bool -> WikiInfo -> [InstHead] -> Bool -> key -> HsDecl -> HtmlTable -ppHsDataDecl summary wiki instances is_newty - x decl@(HsDataDecl _ _ nm args cons _ doc) - | summary = declWithDoc summary wiki nm doc (ppShortDataDecl summary wiki is_newty decl) +ppHsDataDecl :: Ord key => Bool -> LinksInfo -> [InstHead] -> Bool -> key -> HsDecl -> HtmlTable +ppHsDataDecl summary links instances is_newty + x decl@(HsDataDecl loc _ nm args cons _ doc) + | summary = declWithDoc summary links loc nm doc (ppShortDataDecl summary links is_newty decl) | otherwise = dataheader </> @@ -688,7 +687,7 @@ ppHsDataDecl summary wiki instances is_newty instances_bit ) where - dataheader = topDeclBox wiki nm (ppHsDataHeader False is_newty nm args) + dataheader = topDeclBox links loc nm (ppHsDataHeader False is_newty nm args) constr_table | any isRecDecl cons = spacedTable5 @@ -835,15 +834,15 @@ ppFds fds = fundep (vars1,vars2) = hsep (map ppHsName vars1) <+> toHtml "->" <+> hsep (map ppHsName vars2) -ppShortClassDecl :: Bool -> WikiInfo -> HsDecl -> HtmlTable -ppShortClassDecl summary wiki (HsClassDecl _ ctxt nm tvs fds decls _) = +ppShortClassDecl :: Bool -> LinksInfo -> HsDecl -> HtmlTable +ppShortClassDecl summary links (HsClassDecl loc ctxt nm tvs fds decls _) = if null decls - then (if summary then declBox else topDeclBox wiki nm) hdr - else (if summary then declBox else topDeclBox wiki nm) (hdr <+> keyword "where") + then (if summary then declBox else topDeclBox links loc nm) hdr + else (if summary then declBox else topDeclBox links loc nm) (hdr <+> keyword "where") </> (tda [theclass "body"] << vanillaTable << - aboves [ ppFunSig summary wiki n ty doc + aboves [ ppFunSig summary links loc n ty doc | HsTypeSig _ [n] ty doc <- decls ] ) @@ -853,10 +852,10 @@ ppShortClassDecl summary wiki (HsClassDecl _ ctxt nm tvs fds decls _) = ppShortClassDecl _ _ d = error $ "HaddockHtml.ppShortClassDecl: unexpected decl: " ++ show d -ppHsClassDecl :: Ord key => Bool -> WikiInfo -> [InstHead] -> key -> HsDecl -> HtmlTable -ppHsClassDecl summary wiki instances orig_c - decl@(HsClassDecl _ ctxt nm tvs fds decls doc) - | summary = ppShortClassDecl summary wiki decl +ppHsClassDecl :: Ord key => Bool -> LinksInfo -> [InstHead] -> key -> HsDecl -> HtmlTable +ppHsClassDecl summary links instances orig_c + decl@(HsClassDecl loc ctxt nm tvs fds decls doc) + | summary = ppShortClassDecl summary links decl | otherwise = classheader </> @@ -866,8 +865,8 @@ ppHsClassDecl summary wiki instances orig_c where classheader - | null decls = topDeclBox wiki nm hdr - | otherwise = topDeclBox wiki nm (hdr <+> keyword "where") + | null decls = topDeclBox links loc nm hdr + | otherwise = topDeclBox links loc nm (hdr <+> keyword "where") hdr = ppClassHdr summary ctxt nm tvs fds @@ -880,7 +879,7 @@ ppHsClassDecl summary wiki instances orig_c | otherwise = s8 </> meth_hdr </> tda [theclass "body"] << vanillaTable << ( - abovesSep s8 [ ppFunSig summary wiki n ty doc0 + abovesSep s8 [ ppFunSig summary links loc n ty doc0 | HsTypeSig _ [n] ty doc0 <- decls ] ) @@ -907,13 +906,13 @@ ppInstHead (ctxt,asst) = ppHsContext ctxt <+> darrow <+> ppHsAsst asst -- ---------------------------------------------------------------------------- -- Type signatures -ppFunSig :: Bool -> WikiInfo -> HsName -> HsType -> Maybe Doc -> HtmlTable -ppFunSig summary wiki nm ty0 doc +ppFunSig :: Bool -> LinksInfo -> SrcLoc -> HsName -> HsType -> Maybe Doc -> HtmlTable +ppFunSig summary links loc nm ty0 doc | summary || no_arg_docs ty0 = - declWithDoc summary wiki nm doc (ppTypeSig summary nm ty0) + declWithDoc summary links loc nm doc (ppTypeSig summary nm ty0) | otherwise = - topDeclBox wiki nm (ppHsBinder False nm) </> + topDeclBox links loc nm (ppHsBinder False nm) </> (tda [theclass "body"] << vanillaTable << ( do_args dcolon ty0 </> (if (isJust doc) @@ -1157,18 +1156,38 @@ declBox :: Html -> HtmlTable declBox html = tda [theclass "decl"] << html -- a box for top level documented names --- it adds a wiki link at the right hand side of the box -topDeclBox :: Maybe (String, Module) -> HsName -> Html -> HtmlTable -topDeclBox Nothing name html = declBox html -topDeclBox (Just (base_url, Module mod)) name html = +-- it adds a source and wiki link at the right hand side of the box +topDeclBox :: LinksInfo -> SrcLoc -> HsName -> Html -> HtmlTable +topDeclBox (Nothing, Nothing, _) srcloc name html = declBox html +topDeclBox (maybe_src_url, maybe_wiki_url, iface) (SrcLoc _ _ fname) name html = tda [theclass "topdecl"] << ( table ! [theclass "declbar"] << - ((tda [theclass "declname"] << html) <-> - (tda [theclass "declbut"] << link)) + ((tda [theclass "declname"] << html) + <-> srcLink + <-> wikiLink) ) - where link = anchor ! [href url] << toHtml "Comments" - url = pathJoin [base_url, mod] ++ nameAnchor - nameAnchor = '#' : escapeStr (hsNameStr name) + where srcLink = + case maybe_src_url of + Nothing -> Html.emptyTable + Just url -> tda [theclass "declbut"] << + (anchor ! [href (spliceURL url)] + << toHtml "Source") + wikiLink = + case maybe_wiki_url of + Nothing -> Html.emptyTable + Just url -> tda [theclass "declbut"] << + (anchor ! [href (spliceURL url)] + << toHtml "Comments") + + spliceURL url = run url + where run "" = "" + run ('%':'M':rest) = mod ++ run rest + run ('%':'N':rest) = escapeStr (hsNameStr name) ++ run rest + run ('%':'F':rest) = fname ++ run rest + run (c:rest) = c : run rest + + Module mod = iface_module iface + mod' = map (\x -> if x == '.' then '/' else x) mod -- a box for displaying an 'argument' (some code which has text to the -- right of it). Wrapping is not allowed in these boxes, whereas it is diff --git a/src/HaddockLex.x b/src/HaddockLex.x index 1044d64a..f5e40942 100644 --- a/src/HaddockLex.x +++ b/src/HaddockLex.x @@ -142,7 +142,7 @@ ident str sc cont = strToHsQNames :: String -> Maybe [HsQName] strToHsQNames str0 - = case lexer (\t -> returnP t) str0 (SrcLoc 1 1) 1 1 [] of + = case lexer (\t -> returnP t) str0 (SrcLoc 1 1 "") 1 1 "" [] of Ok _ (VarId str) -> Just [ UnQual (HsVarName (HsIdent str)) ] Ok _ (QVarId (mod0,str)) diff --git a/src/HaddockTypes.hs b/src/HaddockTypes.hs index f005332c..990d2408 100644 --- a/src/HaddockTypes.hs +++ b/src/HaddockTypes.hs @@ -25,6 +25,11 @@ data Interface iface_filename :: FilePath, -- ^ the filename that contains the source code for this module + iface_orig_filename :: FilePath, + -- ^ the original filename for this module, which may be + -- different to the 'iface_filename' (for example the original + -- file may have had a .lhs or .hs.pp extension). + iface_module :: Module, iface_package :: Maybe String, diff --git a/src/HsLexer.lhs b/src/HsLexer.lhs index d9c4635f..47ee75f5 100644 --- a/src/HsLexer.lhs +++ b/src/HsLexer.lhs @@ -218,45 +218,49 @@ tAB_LENGTH = 8 lexer :: (Token -> P a) -> P a -lexer cont input (SrcLoc _ x0) y0 col = +lexer cont input (SrcLoc _ x0 _) y0 col f = if col == 0 - then tab y0 x0 True input - else tab y0 col False input -- throw away old x + then tab y0 x0 f True input + else tab y0 col f False input -- throw away old x where -- move past whitespace and comments - tab y x _ [] = - cont EOF [] (SrcLoc y x) col y - tab y x bol ('\t':s) = - tab y (nextTab x) bol s - tab y _ _ ('\n':s) = - newLine cont s y - - tab y _ True ('#':s) + tab y x f _ [] = + cont EOF [] (SrcLoc y x f) y col f + tab y x f bol ('\t':s) = + tab y (nextTab x) f bol s + tab y _ f _ ('\n':s) = + newLine cont s y f + + tab y _ f True ('#':s) | "pragma GCC set_debug_pwd" `isPrefixOf` s - = newLine cont (tail $ dropWhile (/= '\n') s) y + = newLine cont (tail $ dropWhile (/= '\n') s) y f + + tab y x f True ('#':' ':s@(d:_)) + | isDigit d = parseLinePragma tab y f s -- single-line comments - tab y x bol s@('-':'-':' ':c:_) | doc c = - is_a_token bol s y x - tab y _ _ ('-':'-':s) | null s || not (isSymbol (head (dropWhile (== '-') s))) = - newLine cont (drop 1 (dropWhile (/= '\n') s)) y + tab y x f bol s@('-':'-':' ':c:_) | doc c = + is_a_token bol s y x f + tab y _ f _ ('-':'-':s) | null s || not (isSymbol (head (dropWhile (== '-') s))) = + newLine cont (drop 1 (dropWhile (/= '\n') s)) y f - -- multi-line nested comments - tab y x bol s@('{':'-':c:_) | doc c && c /= '#' = - is_a_token bol s y x - tab y x bol s@('{':'-':' ':c:_) | doc c = - is_a_token bol s y x - tab y x bol ('{':'-':s) = nestedComment tab y x bol s + -- multi-line nested comments and pragmas + tab y x f bol ('{':'-':'#':s) = pragma tab y (x+3) f bol s + tab y x f bol s@('{':'-':c:_) | doc c = + is_a_token bol s y x f + tab y x f bol s@('{':'-':' ':c:_) | doc c = + is_a_token bol s y x f + tab y x f bol ('{':'-':s) = nestedComment (\y x -> tab y x f) y (x+2) bol s - tab y x bol (c:s) - | isWhite c = tab y (x+1) bol s - | otherwise = is_a_token bol (c:s) y x + tab y x f bol (c:s) + | isWhite c = tab y (x+1) f bol s + | otherwise = is_a_token bol (c:s) y x f - is_a_token bol s y x - | bol = lexBOL cont s (SrcLoc y x) y x - | otherwise = lexToken cont s (SrcLoc y x) y x + is_a_token bol s y x f + | bol = lexBOL cont s (SrcLoc y x f) y x f + | otherwise = lexToken cont s (SrcLoc y x f) y x f - newLine _ s y = tab (y+1) 1 True s + newLine _ s y f = tab (y+1) 1 f True s doc '|' = True doc '/' = True @@ -273,19 +277,19 @@ nextTab x = x + (tAB_LENGTH - (x-1) `mod` tAB_LENGTH) -- insert virtual semicolons or close braces due to layout. lexBOL :: (Token -> P a) -> P a -lexBOL cont s loc y x context = +lexBOL cont s loc y x f context = if need_close_curly then -- trace "layout: inserting '}'\n" $ -- Set col to 0, indicating that we're still at the -- beginning of the line, in case we need a semi-colon too. -- Also pop the context here, so that we don't insert -- another close brace before the parser can pop it. - cont VRightCurly s loc y 0 (tail context) + cont VRightCurly s loc y 0 f (tail context) else if need_semi_colon then --trace "layout: inserting ';'\n" $ - cont SemiColon s loc y x context + cont SemiColon s loc y x f context else - lexToken cont s loc y x context + lexToken cont s loc y x f context where need_close_curly = case context of @@ -303,7 +307,7 @@ lexBOL cont s loc y x context = lexToken :: (Token -> P a) -> P a --lexToken _ [] loc _ _ = -- error $ "Internal error: empty input in lexToken at " ++ show loc -lexToken cont s0 loc y x = +lexToken cont s0 loc y x f = -- trace ("lexer: y="++show y++" x="++show x++"\n") $ case s0 of [] -> error $ "Internal error: empty input in lexToken at " @@ -330,20 +334,20 @@ lexToken cont s0 loc y x = [] -> error "Internal error: empty context in lexToken" '?':s:ss - | isIdentInitial s -> lexToken ( \ (VarId x) -> cont (IPVarId x)) (s:ss) loc y x - '\'':s -> lexChar cont s loc y (x+1) - '\"':s{-"-} -> lexString cont s loc y (x+1) + | isIdentInitial s -> lexToken ( \ (VarId x) -> cont (IPVarId x)) (s:ss) loc y x f + '\'':s -> lexChar cont s loc y (x+1) f + '\"':s{-"-} -> lexString cont s loc y (x+1) f '0':'x':c:s | isHexDigit c -> let (num, rest) = span isHexDigit (c:s) [(i,_)] = readHex num in - afterNum cont i rest loc y (x+length num) + afterNum cont i rest loc y (x+length num) f '0':'o':c:s | isOctDigit c -> let (num, rest) = span isOctDigit (c:s) [(i,_)] = readOct num in - afterNum cont i rest loc y (x+length num) + afterNum cont i rest loc y (x+length num) f c:s | isIdentInitial c -> let @@ -355,7 +359,7 @@ lexToken cont s0 loc y x = Just keyword -> forward l_id keyword rest Nothing -> forward l_id (VarId id0) rest - | isUpper c -> lexCon "" cont (c:s) loc y x + | isUpper c -> lexCon "" cont (c:s) loc y x f | isSymbol c -> let (symtail, rest) = span isSymbol s @@ -368,42 +372,42 @@ lexToken cont s0 loc y x = ':' -> forward l_sym (ConSym sym) rest _ -> forward l_sym (VarSym sym) rest - | isDigit c -> lexNum cont c s loc y x + | isDigit c -> lexNum cont c s loc y x f | otherwise -> parseError ("illegal character \'" ++ show c ++ "\'\n") - s loc y x + s loc y x f - where forward n t str = cont t str loc y (x+n) + where forward n t str = cont t str loc y (x+n) f -- this is all terribly ugly, sorry :( - do_doc ('|':s) nested = multi nested DocCommentNext cont s loc y x - do_doc ('/':s) nested = multi nested DocCommentNext cont s loc y x - do_doc ('^':s) nested = multi nested DocCommentPrev cont s loc y x - do_doc ('$':s) nested = multi nested DocCommentNamed cont s loc y x - do_doc ('#':s) nested = multi nested DocOptions cont s loc y x + do_doc ('|':s) nested = multi nested DocCommentNext cont s loc y x f + do_doc ('/':s) nested = multi nested DocCommentNext cont s loc y x f + do_doc ('^':s) nested = multi nested DocCommentPrev cont s loc y x f + do_doc ('$':s) nested = multi nested DocCommentNamed cont s loc y x f + do_doc ('#':s) nested = multi nested DocOptions cont s loc y x f do_doc ('*':s) nested = section 1 s where section n ('*':s1) = section (n+1) s1 section n s1 - | nested = nestedDocComment (DocSection n) cont s1 loc y x - | otherwise = oneLineDocComment (DocSection n) cont s1 loc y x + | nested = nestedDocComment (DocSection n) cont s1 loc y x f + | otherwise = oneLineDocComment (DocSection n) cont s1 loc y x f do_doc _ _ = error "Internal error: HsLexer.do_doc" -multi :: Num a => Bool -> ([Char] -> b) - -> (b -> [Char] -> c -> a -> Int -> d) - -> [Char] -> c -> a -> Int -> d +multi :: Bool -> ([Char] -> b) + -> (b -> [Char] -> c -> Int -> Int -> d) + -> [Char] -> c -> Int -> Int -> d multi True = nestedDocComment multi False = multiLineDocComment -afterNum :: Num a => (Token -> [Char] -> b -> c -> a -> d) - -> Integer -> [Char] -> b -> c -> a -> d -afterNum cont i ('#':s) loc y x = cont (PrimInt i) s loc y (x+1) -afterNum cont i s loc y x = cont (IntTok i) s loc y x +afterNum :: Num a => (Token -> [Char] -> b -> c -> a -> d -> e) + -> Integer -> [Char] -> b -> c -> a -> d -> e +afterNum cont i ('#':s) loc y x f = cont (PrimInt i) s loc y (x+1) f +afterNum cont i s loc y x f = cont (IntTok i) s loc y x f -lexNum :: (Token -> [Char] -> a -> b -> Int -> c) - -> Char -> [Char] -> a -> b -> Int -> c -lexNum cont c0 s0 loc y x = +lexNum :: (Token -> [Char] -> a -> b -> Int -> c -> d) + -> Char -> [Char] -> a -> b -> Int -> c -> d +lexNum cont c0 s0 loc y x fname = let (num, after_num) = span isDigit (c0:s0) in case after_num of @@ -433,11 +437,11 @@ lexNum cont c0 s0 loc y x = x' = x + length f in case after_exp of -- glasgow exts only - '#':'#':s -> cont (PrimDouble f) s loc y x' - '#':s -> cont (PrimFloat f) s loc y x' - s -> cont (FloatTok f) s loc y x' + '#':'#':s -> cont (PrimDouble f) s loc y x' fname + '#':s -> cont (PrimFloat f) s loc y x' fname + s -> cont (FloatTok f) s loc y x' fname - _ -> afterNum cont (parseInteger 10 num) after_num loc y (x + length num) + _ -> afterNum cont (parseInteger 10 num) after_num loc y (x + length num) fname -- GHC extension: allow trailing '#'s in an identifier. @@ -455,11 +459,11 @@ slurphashes [] i = (reverse i, []) slurphashes ('#':cs) i = slurphashes cs ('#':i) slurphashes s i = (reverse i, s) -lexCon :: [Char] -> (Token -> String -> a -> b -> Int -> c) - -> String -> a -> b -> Int -> c -lexCon qual cont s0 loc y x = +lexCon :: [Char] -> (Token -> String -> a -> b -> Int -> c -> d) + -> String -> a -> b -> Int -> c -> d +lexCon qual cont s0 loc y x f = let - forward n t s = cont t s loc y (x+n) + forward n t s = cont t s loc y (x+n) f (con, rest) = slurpIdent s0 l_con = length con @@ -485,7 +489,7 @@ lexCon qual cont s0 loc y x = _ -> forward (l_con+1+l_id) (QVarId (qual', id0)) rest1 | isUpper c1 -> -- qualified conid? - lexCon qual' cont (c1:s1) loc y (x+l_con+1) + lexCon qual' cont (c1:s1) loc y (x+l_con+1) f | isSymbol c1 -> -- qualified symbol? let @@ -505,28 +509,28 @@ lexCon qual cont s0 loc y x = lexChar :: (Token -> P a) -> P a -lexChar cont s0 loc0 y x = case s0 of - '\\':s1 -> (escapeChar s1 `thenP` \(e,s,i) _ _ _ _ -> - charEnd e s loc0 y (x+i)) s1 loc0 y x - c:s -> charEnd c s loc0 y (x+1) +lexChar cont s0 loc0 y x f = case s0 of + '\\':s1 -> (escapeChar s1 `thenP` \(e,s,i) _ _ _ _ _ -> + charEnd e s loc0 y (x+i) f) s1 loc0 y x f + c:s -> charEnd c s loc0 y (x+1) f [] -> error "Internal error: lexChar" - where charEnd c ('\'':'#':s) = \loc y0 x0 -> cont (PrimChar c) s loc y0 (x0+2) - charEnd c ('\'':s) = \loc y0 x0 -> cont (Character c) s loc y0 (x0+1) + where charEnd c ('\'':'#':s) = \loc y0 x0 f0 -> cont (PrimChar c) s loc y0 (x0+2) f0 + charEnd c ('\'':s) = \loc y0 x0 f0 -> cont (Character c) s loc y0 (x0+1) f0 charEnd _ s = parseError "Improperly terminated character constant" s lexString :: (Token -> P a) -> P a -lexString cont s0 loc y0 x0 = loop "" s0 x0 y0 +lexString cont s0 loc y0 x0 f0 = loop "" s0 x0 y0 f0 where - loop e s1 x y = case s1 of - '\\':'&':s -> loop e s (x+2) y - '\\':c:s | isSpace c -> stringGap e s (x+2) y + loop e s1 x y f = case s1 of + '\\':'&':s -> loop e s (x+2) y f + '\\':c:s | isSpace c -> stringGap e s (x+2) y f | otherwise -> (escapeChar (c:s) `thenP` \(e',s2,i) _ _ _ _ -> - loop (e':e) s2 (x+i) y) s loc y x - '\"':'#':s -> cont (PrimString (reverse e)) s loc y (x+2) - '\"':s{-"-} -> cont (StringTok (reverse e)) s loc y (x+1) - c:s -> loop (c:e) s (x+1) y - [] -> parseError "Improperly terminated string" s1 loc y x + loop (e':e) s2 (x+i) y) s loc y x f + '\"':'#':s -> cont (PrimString (reverse e)) s loc y (x+2) f + '\"':s{-"-} -> cont (StringTok (reverse e)) s loc y (x+1) f + c:s -> loop (c:e) s (x+1) y f + [] -> parseError "Improperly terminated string" s1 loc y x f stringGap e s1 x y = case s1 of '\n':s -> stringGap e s 1 (y+1) @@ -617,8 +621,35 @@ cntrl :: String -> P (Char,String,Int) cntrl (c:s) | c >= '@' && c <= '_' = returnP (chr (ord c - ord '@'), s,2) cntrl _ = parseError "Illegal control character" -nestedComment :: Num a => (a -> Int -> Bool -> [Char] -> b) - -> a -> Int -> Bool -> [Char] -> b + +pragma :: (Int -> Int -> FilePath -> Bool -> [Char] -> b) + -> Int -> Int -> FilePath -> Bool -> [Char] -> b +pragma cont y x f bol s0 = + case span (==' ') s0 of + (_, 'L':'I':'N':'E':' ':s) -> parseLinePragma cont y f s + (_, 'l':'i':'n':'e':' ':s) -> parseLinePragma cont y f s + (sp,s) -> nestedComment (\y x -> cont y x f) y (x+length sp) bol s + +parseLinePragma :: (Int -> Int -> FilePath -> Bool -> [Char] -> b) + -> Int -> FilePath -> [Char] -> b +parseLinePragma cont y fname s0 = + cont y' 1 fname' True (drop 1 (dropWhile (/= '\n') s0)) + + where s1 = dropWhite s0 + (lineStr, s2) = span isDigit s1 + y' = case reads lineStr of + ((y',_):_) -> y' + _ -> y + s3 = dropWhite s2 + fnameStr = takeWhile (\c -> c /= '"') (tail s3) + fname' | null s3 || head s3 /= '"' = fname + -- try and get more sharing of file name strings + | fnameStr == fname = fname + | otherwise = fnameStr + dropWhite = dropWhile (\c -> c == ' ' || c == '\t') + +nestedComment :: (Int -> Int -> Bool -> [Char] -> b) + -> Int -> Int -> Bool -> [Char] -> b nestedComment cont y x bol s0 = case s0 of '-':'}':s -> cont y (x+2) bol s @@ -628,9 +659,9 @@ nestedComment cont y x bol s0 = _:s -> nestedComment cont y (x+1) bol s [] -> error "Internal error: nestedComment" -nestedDocComment :: Num a => ([Char] -> b) - -> (b -> [Char] -> c -> a -> Int -> d) - -> [Char] -> c -> a -> Int -> d +nestedDocComment :: ([Char] -> b) + -> (b -> [Char] -> c -> Int -> Int -> d) + -> [Char] -> c -> Int -> Int -> d nestedDocComment f0 cont0 s0 loc y0 x0 = go f0 cont0 "" y0 x0 s0 where go f cont acc y1 x1 s1 = diff --git a/src/HsParseMonad.lhs b/src/HsParseMonad.lhs index 748fbad1..f1423f6f 100644 --- a/src/HsParseMonad.lhs +++ b/src/HsParseMonad.lhs @@ -27,14 +27,15 @@ type P a -> SrcLoc -- location of last token read -> Int -- current line -> Int -- current column + -> FilePath -- current original filename -> ParseState -- layout info. -> ParseResult a thenP :: P a -> (a -> P b) -> P b -m `thenP` k = \i l n c s0 -> - case m i l n c s0 of +m `thenP` k = \i l n c f s0 -> + case m i l n c f s0 of Failed s -> Failed s - Ok s' a -> case k a of k' -> k' i l n c s' + Ok s' a -> case k a of k' -> k' i l n c f s' thenP_ :: P a -> P b -> P b m `thenP_` k = m `thenP` \_ -> k @@ -47,24 +48,24 @@ mapP f (a:as) = returnP (b:bs) returnP :: a -> P a -returnP a = \_ _ _ _ s -> Ok s a +returnP a = \_ _ _ _ _ s -> Ok s a failP :: String -> P a -failP err = \_ _ _ _ _ -> Failed err +failP err = \_ _ _ _ _ _ -> Failed err getSrcLoc :: P SrcLoc -getSrcLoc = \_ l _ _ s -> Ok s l +getSrcLoc = \_ l _ _ _ s -> Ok s l getContext :: P [LexContext] -getContext = \_ _ _ _ s -> Ok s s +getContext = \_ _ _ _ _ s -> Ok s s pushContext :: LexContext -> P () pushContext ctxt = --trace ("pushing lexical scope: " ++ show ctxt ++"\n") $ - \_ _ _ _ s -> Ok (ctxt:s) () + \_ _ _ _ _ s -> Ok (ctxt:s) () popContext :: P () -popContext = \_ _ _ _ stk -> +popContext = \_ _ _ _ _ stk -> case stk of (_:s) -> --trace ("popping lexical scope, context now "++show s ++ "\n") $ Ok s () diff --git a/src/HsParseUtils.lhs b/src/HsParseUtils.lhs index 5498cfd3..58f7f763 100644 --- a/src/HsParseUtils.lhs +++ b/src/HsParseUtils.lhs @@ -43,8 +43,8 @@ import Ratio \begin{code} parseError :: String -> P a -parseError s = \r (SrcLoc y x) -> - failP (show y ++ ":" ++ show x ++ ": " ++ s) r (SrcLoc y x) +parseError s = \r (SrcLoc y x f) -> + failP (show f ++ ": " ++ show y ++ ":" ++ show x ++ ": " ++ s) r (SrcLoc y x f) splitTyConApp :: HsType -> P (HsName,[HsType]) splitTyConApp t0 = split t0 [] diff --git a/src/HsParser.ly b/src/HsParser.ly index 21561e0a..b62f1cae 100644 --- a/src/HsParser.ly +++ b/src/HsParser.ly @@ -149,12 +149,12 @@ Reserved Ids Module Header > module :: { HsModule } -> : optdoc 'module' modid maybeexports 'where' body +> : optdoc 'module' srcloc modid maybeexports 'where' body > { case $1 of { (opts,info,doc) -> -> HsModule $3 $4 (reverse (fst $6)) (snd $6) +> HsModule $3 $4 $5 (reverse (fst $7)) (snd $7) > opts info doc } } -> | body -> { HsModule main_mod Nothing (reverse (fst $1)) (snd $1) +> | body srcloc +> { HsModule $2 main_mod Nothing (reverse (fst $1)) (snd $1) > Nothing emptyModuleInfo Nothing } > optdoc :: { (Maybe String,ModuleInfo,Maybe Doc) } @@ -951,7 +951,7 @@ Layout > : vccurly { () } -- context popped in lexer. > | error {% popContext } -> layout_on :: { () } : {% getSrcLoc `thenP` \(SrcLoc r c) -> +> layout_on :: { () } : {% getSrcLoc `thenP` \(SrcLoc r c f) -> > pushContext (Layout c) } ----------------------------------------------------------------------------- diff --git a/src/HsSyn.lhs b/src/HsSyn.lhs index 82f89da9..cb5ec11e 100644 --- a/src/HsSyn.lhs +++ b/src/HsSyn.lhs @@ -41,7 +41,7 @@ module HsSyn ( import Char (isSpace) -data SrcLoc = SrcLoc Int Int -- (Line, Indentation) +data SrcLoc = SrcLoc !Int !Int FilePath -- (Line, Indentation, FileName) deriving (Eq,Ord,Show) newtype Module = Module String @@ -80,7 +80,7 @@ instance Show HsIdentifier where showsPrec _ (HsSymbol s) = showString s showsPrec _ (HsSpecial s) = showString s -data HsModule = HsModule Module (Maybe [HsExportSpec]) +data HsModule = HsModule SrcLoc Module (Maybe [HsExportSpec]) [HsImportDecl] [HsDecl] (Maybe String) -- the doc options ModuleInfo -- the info (portability etc.) diff --git a/src/Main.hs b/src/Main.hs index 70c2dd58..1f76fe47 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -334,7 +334,7 @@ parse_file file = do (openFile file ReadMode) (\h -> hClose h) (\h -> do stuff <- hGetContents h - case parse stuff (SrcLoc 1 1) 1 0 [] of + case parse stuff (SrcLoc 1 1 file) 1 0 file [] of Ok _ e -> return e Failed err -> die (file ++ ':':err ++ "\n") ) @@ -425,7 +425,8 @@ mkInterfacePhase1 -> ErrMsgM Interface -- the "interface" of the module mkInterfacePhase1 flags verbose mod_map filename package - (HsModule mdl exps imps decls maybe_opts maybe_info maybe_doc) = do + (HsModule (SrcLoc _ _ orig_filename) mdl exps imps decls + maybe_opts maybe_info maybe_doc) = do let no_implicit_prelude = Flag_NoImplicitPrelude `elem` flags @@ -466,7 +467,7 @@ mkInterfacePhase1 flags verbose mod_map filename package | no_implicit_prelude || any is_prel_import imps = imps | otherwise = HsImportDecl loc prelude_mod False Nothing Nothing : imps where - loc = SrcLoc 0 0 + loc = SrcLoc 0 0 "" is_prel_import (HsImportDecl _ mdl0 _ _ _ ) = mdl0 == prelude_mod -- in @@ -542,6 +543,7 @@ mkInterfacePhase1 flags verbose mod_map filename package return (Interface { iface_filename = filename, + iface_orig_filename= orig_filename, iface_module = mdl, iface_package = package, iface_env = name_env, @@ -1182,12 +1184,12 @@ sortModules mdls = mapM for_each_scc sccs edges :: [((HsModule,FilePath), Module, [Module])] edges = [ ((hsmod,file), mdl, get_imps impdecls) - | (hsmod@(HsModule mdl _ impdecls _ _ _ _), file) <- mdls + | (hsmod@(HsModule _ mdl _ impdecls _ _ _ _), file) <- mdls ] get_imps impdecls = [ imp | HsImportDecl _ imp _ _ _ <- impdecls ] - get_mods hsmodules = [ mdl | HsModule mdl _ _ _ _ _ _ <- hsmodules ] + get_mods hsmodules = [ mdl | HsModule _ mdl _ _ _ _ _ _ <- hsmodules ] for_each_scc (AcyclicSCC hsmodule) = return hsmodule for_each_scc (CyclicSCC hsmodules) = @@ -1351,6 +1353,7 @@ to_interface1 (mdl,descriptionOpt,package, hide, env, _, sub) = Interface { iface_module = mdl, iface_filename = "", + iface_orig_filename= "", iface_package = package, iface_env = Map.fromList env, iface_sub = Map.fromList sub, @@ -1369,6 +1372,7 @@ to_interface2 (mdl,descriptionOpt,package, hide, env, sub) = Interface { iface_module = mdl, iface_filename = "", + iface_orig_filename= "", iface_package = package, iface_env = Map.fromList [(n,Qual mdl n) | (n,mdl) <- env], @@ -1388,6 +1392,7 @@ nullVersion_to_interface (mdl, package, hide, env, reexported, sub) = Interface { iface_module = mdl, iface_filename = "", + iface_orig_filename= "", iface_package = package, iface_env = Map.fromList env, iface_sub = Map.fromList sub, |