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 <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