{-+ 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 SrcLoc 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
 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 = "
"
preEnd = "
" codeStart = "
"
codeEnd = "
" 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