module Yhc.Core.Html(coreHtml) where import Yhc.Core.Type import Yhc.Core.Show(isCoreOperator) import Yhc.Core.Internal.HughesPJ import Data.List import Data.Maybe import Data.Char prefix modu = "" ++ "" ++ "" ++ "" ++ "" ++ modu ++ " - Yhc.Core" ++ "" ++ "\n" suffix = "\n" script = "var done = '';\n" ++ "\n" ++ "function none()\n" ++ "{\n" ++ " if (done == '') return;\n" ++ " done = '';\n" ++ " document.styleSheets[0].deleteRule(0);\n" ++ " document.styleSheets[0].deleteRule(0);\n" ++ "}\n" ++ "\n" ++ "function use(node)\n" ++ "{\n" ++ " if (done == node)\n" ++ " {\n" ++ " none();\n" ++ " return false;\n" ++ " }\n" ++ "\n" ++ " var n = document.getElementById(node);\n" ++ " var offsetBottom = n.offsetTop + n.offsetHeight;\n" ++ " var scrollBottom = document.body.scrollTop + window.innerHeight;\n" ++ "\n" ++ " def(node);\n" ++ "\n" ++ " return (n.offsetTop < document.body.scrollTop || offsetBottom > scrollBottom)\n" ++ "}\n" ++ "\n" ++ "function def(node)\n" ++ "{\n" ++ " if (done == node)\n" ++ " {\n" ++ " none();\n" ++ " return;\n" ++ " }\n" ++ "\n" ++ " none();\n" ++ " var rule1 = '#' + node + '{border-color: #ff4;}'\n" ++ " var rule2 = '.' + node + '{background-color: #ff4;}'\n" ++ "\n" ++ " document.styleSheets[0].insertRule(rule1,0);\n" ++ " document.styleSheets[0].insertRule(rule2,0);\n" ++ " done = node;\n" ++ "}\n" ++ "\n" coreHtml :: Core -> String coreHtml core = prefix (coreName core) ++ show (docCore core) ++ suffix listLines = vcat -- . intersperse (text "\n") blankLine = text "" wrap prepend doc append = zeroText prepend <> doc <> zeroText append tag s x = wrap ("") (text x) "" enc = concatMap f where f x | isAlphaNum x = [x] | otherwise = show (ord x) key = tag "key" op = tag "op" str = tag "str" opchars = hcat . map f where f x | x `elem` "[]()," = op [x] | otherwise = char x docCore :: Core -> Doc docCore core@(Core modName depends datas funcs) = listLines $ [key "module" <+> text modName <+> key "where", blankLine] ++ map ((key "import" <+>) . text) depends ++ [blankLine] ++ intersperse (blankLine <> blankLine) (map docData datas ++ map (docFunc core) funcs) docData :: CoreData -> Doc docData (CoreData name free []) = key "data" <+> hsep (map text (name:free)) docData (CoreData name free (x:xs)) = docData (CoreData name free []) <+> op "=" <+> text "\n" <+> text " " <> docCtor x <+> hsep (map (\x -> text "\n " <> op "|" <> text " " <> docCtor x) xs) docCtor :: CoreCtor -> Doc docCtor (CoreCtor name args) = text name <+> text ( ['{' | useRecords] ++ (concat $ intersperse sep $ map f args) ++ ['}' | useRecords]) where useRecords = any (isJust . snd) args sep = ([','|useRecords]++" ") f (typ, Nothing) = typ f (typ, Just x) = "_" ++ x ++ " :: " ++ typ inner :: Doc -> Doc inner = nest 4 (<>>) :: Doc -> Doc -> Doc a <>> b = sep [a, inner b] docFunc :: Core -> CoreFunc -> Doc docFunc core x = wrap ("
") res "
" where res = body initial ename = enc name name = coreFuncName x body = if isCoreFunc x then (<>> docExpr core (coreFuncBody x)) else id args = if isCoreFunc x then hsep (map text (coreFuncArgs x)) <+> op "=" else text $ "arity=" ++ show (corePrimArity x) prefix = if isCoreFunc x then text name else key "primitive" <+> text name pre = "" initial = wrap pre prefix "" <+> args -- True is bracket, False is don't docExpr :: Core -> CoreExpr -> Doc docExpr core x = f False x where -- True is do bracketing -- False is don't f b (CoreCon x) = f b (CoreVar x) f b (CoreFun x) | not link = f b (CoreVar x) | otherwise = wrap pre (f b (CoreVar x)) "" where pre = "" link = isJust $ coreFuncMaybe core x ename = enc x f b (CoreVar x) = brack (isCoreOperator x) (opchars x) f b (CoreLam xs x) = brack b $ char '\\' <> text (unwords xs) <+> text "->" <+> f False x f b (CoreLit x) = g x f b (CorePos x y) = f b y f b (CoreApp x []) = f b x f b (CoreApp x xs) = brack b $ call (f True x) (map (f True) xs) f b (CoreCase on alts) = brack b (key "case" <+> f True on <+> key "of" $$ inner (vcat $ map g alts)) where g (a,b) = (f False (patToExpr a) <+> op "->") <>> f False b f b (CoreLet binds x) = brack b $ key "let" <+> vcat (map g binds) $$ key "in" <+> f False x where g (lhs,rhs) = text lhs <+> op "=" <>> f False rhs call x xs = sep $ x : map (nest 2) xs brack b x = if b then op "(" <> x <> op ")" else x g (CoreInt x) = text $ show x g (CoreChr x) = str $ show x g (CoreStr x) = str $ show x g (CoreInteger x) = text $ show x g (CoreFloat x) = text $ show x g (CoreDouble x) = text $ show x