HaRe-0.6: tools/hs2html/HLex2html.hs
{-+
This module defines the function #hlex2html#, which translates the output from
an early pass of the lexical analyzer to HTML. It can also make use of cross
reference information to link identifiers to their definitions.
The generated HTML is intended to be part of the body of a web page,
thus it does not include the #head# or #body# tags.
-}
module HLex2html({-hlex2html,-}hlex2html',simpleHlex2html) where
import RefsTypes --hiding (isDef)
import MUtils(apSnd)
import Char(isSpace{-,isAlpha-},isAlphaNum)
import HsTokens
import SrcLoc1
import LitTxt(toHTMLblock)
import PathUtils(normf)
import HLexTagModuleNames
import PrettyPrint(pp)
--------------------------------------------------------------------------------
type ModuleContext = (FilePath,[(FilePath,Module)]) -- (this,other) modules
type LexTokens = [(Token,(Pos,String))]
type URL = String
type HTML = String
simpleHlex2html :: LexTokens -> HTML
--hlex2html :: ModuleContext -> (Refs,LexTokens) -> HTML
hlex2html' :: (Module->URL) -> ModuleContext -> (Refs,LexTokens) -> HTML
--------------------------------------------------------------------------------
simpleHlex2html = hlex2html' undefined dummy . (,) []
where dummy = ("",[("",noModule)])
hlex2html' srcURL (thisf,fm) =
normal . tokens2html srcURL (thisf,thism,fm) . uncurry merge .
apSnd convModuleNames
where Just thism = lookup thisf fm
{-+
The functions #normal#, #pre#, and #code# implement a state machine that
handles the insertion of properly nested #pre# and #div# tags.
-}
-- Normal text mode, in which literate comments can be output:
normal [] = []
normal ((LiterateComment,(_,s)):ts) = toHTMLblock s++normal ts
normal ((Whitespace,(p,s)):ts) | noCodeOnLine (line p) ts = s++normal ts -- indented code??
normal ((Commentstart,(Pos{column=1},s1)):(Comment,(_,s2)):ts) =
preStart++cmntesc (s1++s2)++pre ts
normal ((Comment,ps1):(Whitespace,ps2):ts) | isBlockComment ps1 ps2 =
preStart++cmntesc (snd ps1++snd ps2)++pre ts
normal ts = codeStart++code ts
-- Inside a <pre> block, where blank lines and block comments can be output:
pre [] = preEnd
pre ((LiterateComment,(_,s)):ts) = preEnd++toHTMLblock s++normal ts
pre ((Whitespace,(_,s)):ts) = s++pre ts
pre ((Commentstart,(Pos{column=1},s1)):(Comment,(_,s2)):ts) =
cmntesc (s1++s2)++pre ts
pre ((Comment,ps1):(Whitespace,ps2):ts) | isBlockComment ps1 ps2 =
cmntesc (snd ps1++snd ps2)++pre ts
pre ts = preEnd++codeStart++code ts
-- Inside a code, where code and ordinary comments can be output:
code [] = codeEnd
code ((LiterateComment,(_,s)):ts) = codeEnd++toHTMLblock s++normal ts
code ((Commentstart,(_,s1)):(Comment,(_,s2)):ts) = cmntesc (s1++s2)++code ts
code ((Comment,ps1):(Whitespace,ps2):ts) | isBlockComment ps1 ps2 =
codeEnd++preStart++cmntesc (snd ps1++snd ps2)++pre ts
code ((Comment,(_,s)) :ts) = cmntesc s++code ts
code ((Whitespace,(_,s)) :ts) = s++code ts
code ((_,(_,s)):ts) = s++code ts
preStart = "<pre>"
preEnd = "</pre>"
codeStart = "<div class=code><pre>"
codeEnd = "</pre></div>"
isBlockComment (Pos{column=1},'{':'-':_) (_,s) | '\n' `elem` s = True
isBlockComment _ _ = False
noCodeOnLine l ts =
all ((`elem` notCode).fst) (takeWhile ((==l).line.fst.snd) ts)
where notCode = [LiterateComment,Whitespace{-,Commentstart,Comment-}]
cmntesc = cmnt . esc
--------------------------------------------------------------------------------
tokens2html srcURL rs = map (token2html srcURL rs)
token2html :: (Module->URL)->(FilePath,Module,[(FilePath,Module)])->
((Token,(Pos,String)),Maybe Orig)->
(Token,(Pos,String))
token2html _ _ ((LiterateComment,ps@(_,"> ")),_) = (Whitespace,ps)
token2html _ _ ((NestedComment,s),_) = nestedcomment s
token2html srcURL (thisf,thism,fm) ((t,(p,s)),r) = (t,(p,f (esc s)))
where
moduleLink s =
case [m|(f,m)<-fm,sameModuleName s m] of
[m] -> link (srcURL m)
_ -> modname
f = case t of
ModuleName -> if sameModuleName s thism || thism==noModule
then modname
else moduleLink s
ModuleAlias -> modname
Reservedid -> b
Reservedop -> b
Conid -> conp
Consym -> consymp
Qconid -> conp
Qconsym -> consymp
Varid -> varp
Specialid -> b
Varsym -> varsymp
Qvarid -> varp
Qvarsym -> varsymp
-- Literal -> lit -- obsolete
IntLit -> lit
FloatLit -> lit
CharLit -> lit
StringLit -> lit
{-
Whitespace ->
Special
-}
_ -> id
varp = var (info "var" "" p)
conp = con (info "con" "" p)
varsymp = var (info "var" "op" p)
consymp = con (info "con" "op" p)
modname = con (Nothing,[("class","mod")])
info cl op p =
case r of
Just (n,role,sp,rs) | n==s ->
(link,
(if isDef role
then (("id",rstarget sp rs):)
else id) $
[("class",ty++cl++op),("title",n++": "++title)])
where
ty = if isType sp then "t" else ""
ttag t = if isType t then "t" else "v"
link = case links of
[Just link] -> Just link
_ -> Nothing
title = case titles of
[] -> "not in scope"
_ -> unwords titles
(links,titles) = unzip (map shr rs)
sht T = "type"
sht V = "value"
sht Cl = "class"
sht (Co n) = "constructor of "++n
sht (Me n) = "method of class "++n
sht (Fi n) = "field of type "++n
shr (t,p) =
apSnd (("a "++sht t)++) $
if role==DP
then (Nothing," bound here")
else if isDef role
then (Nothing," defined here")
else shrp t p
shrp t (Left (m,n)) =
if m==thism
then (Just ("#"++tmangle t n)," defined in this module")
else (Just (srcURL m++"#"++tmangle t n)," defined in module "++pp m)
shrp _ (Right p'@(f,rc)) =
if p'==(thisf,p)
then (Nothing," defined here")
else if f==thisf
then (Just ("#"++shPos' rc),
" defined in this module at "++shPos rc)
else (Just (srcURL m++"#"++shPos' rc),
" defined in module "++pp m++" at "++show p')
where Just m = lookup (normf f) fm
--shpos (f,(y,x)) = show (SrcLoc f 0 y x) -- hmm
--shrc (y,x) = show y++":"++show x
--shrc' (y,x) = show y++"."++show x
rstarget t = rtarget t . head
rtarget t = either (gtarget t) ptarget . snd
gtarget t = tmangle t . snd
ptarget = shPos' . snd
tmangle t p = ttag t++mangle p
_ -> (Nothing,attrs)
where
attrs = if thism==noModule
then [("class",cl++op)]
else [("title","Hmm. Info missing")]
--isDef r = r `elem` [DT,DL,DP,DC]
b = ctx "b"
var (optl,as) = optlink optl . ctx' "var" as
con (optl,as) = optlink optl . ctx' "b" as
lit = ctx' "span" [("class","lit")]
optlink = maybe id link
link url = ctx' "a" [("href",url)]
cmnt = ctx' "span" [("class","cmnt")]
-- Some nested comments, {-+ ... -}, are treated like literate comments...
nestedcomment ps@(p,s) =
case s of
'{':'-':'+':c:s' | isSpace c ->
case reverse s' of
'}':'-':s -> (LiterateComment,(p,reverse s))
_ -> (NestedComment,ps) -- Can't happen
_ -> (NestedComment,ps)
ctx t s = tag t++s++endtag t
ctx' t as s = tag (t++shas as)++s++endtag t
where
shas = concatMap sha
sha (n,v) = ' ':n++"="++quote v
tag t = "<"++t++">"
endtag t = tag ('/':t)
esc = concatMap esc1
where esc1 '<' = "<"
esc1 '&' = "&"
esc1 c = [c]
quote s =
if all isAlphaNum s
then s
else '"':s++"\""
mangle = concatMap mangle1
where
mangle1 c = if isAlphaNum c
then [c]
else '.':show (fromEnum c) -- hmm