module Language.Haskell.ER.Dictionary where import Language.Haskell.TH import Language.Haskell.ER.HaskellRewrite as HaskellRewrite import Language.Haskell.ER.Syntax import Language.Haskell.ER.BaseRewrite -- to remove --import Language.Haskell.ER.Subst -- to remove import Text.Html hiding (combine) import Data.Tree import Data.List hiding (insert) import qualified Data.Map as Map data Entry = Collection String [Entry] | Basic String -- transformation label String -- full transformation name (for lookup) UniHaskellRewrite -- rewriting over something (Maybe Bool) -- if this is recommended local use only data Dictionary = Dictionary (Map.Map String UniHaskellRewrite) [Entry] dictToHtml :: Dictionary -> Html dictToHtml (Dictionary _ es) = table ! [theclass "tree"] << concatHtml [ entryToHtml [i] e | (e,i) <- zip es [0..] ] -- assumes inside ..
entryToHtml :: Path -> Entry -> Html entryToHtml path (Collection name es) = (tr << th << ((image ! [ src "downarrow.gif" , strAttr "onclick" $ "toggle(this,'" ++ pathToId path ++ "')" ]) +++ lineToHtml (" " ++ name))) +++ (tr << td << table ! [theclass "tree", identifier $ pathToId path] << concatHtml [ entryToHtml (path ++ [i]) e | (e,i) <- zip es [0..] ]) entryToHtml path (Basic name fullname _ recommend) = (tr << td ! [ identifier $ fullname , theclass $ case recommend of Just True -> "singlerewrite" _ -> "rewrite" ] << (image ! [ src $ case recommend of Just True -> "target.gif" _ -> "proof.gif" ] +++ lineToHtml (" " ++ name))) {- li ! [ theclass $ case recommend of Just True -> "singlerewrite" _ -> "rewrite" ] << leaf path name -} -- We want each leaf to have -- * name -- * what it acts on { Dec, Exp, Code, ... } -- * how it acts (prefix, postfix, once, etc) leaf :: Path -> String -> Html leaf path name = anchor ! [ href "#" , identifier $ full_name ] << name where full_name :: String full_name = foldr (\ a as -> show a ++ "," ++ as) (show $ last path) (init path) pathToId :: Path -> String pathToId [] = "root" pathToId path = foldr (\ a as -> show a ++ "," ++ as) (show $ last path) (init path) ------------------------------------------------------------------------------ performRewrite :: (Equationable eq) => [Dec] -> (Dictionary,String) -> (eq,SubstOrder) -> Q (eq,[Tree (Path,RewriteInfo)]) performRewrite decs (Dictionary fm _,dict_path) (code,code_substorder) = do case Map.lookup dict_path fm of Nothing -> do runIO $ print $ "Can not find " ++ show (dict_path,fm) error "opps" Just rr -> do runIO $ print (dict_path,code_substorder) (decs,infos,new_decs) <- HaskellRewrite.runRewrite (HaskellRewrite.substUsing' code_substorder rr) decs code return (bindDecs new_decs decs,infos) ----------------------------------------------------------------------------- generateDictionary :: [UniHaskellRewrite] -> Dictionary generateDictionary rewrites = Dictionary dict (map (fn "") trees) where fn pre (Node (name,local) []) = Basic name fullname (find fullname) local -- We rebuild the path here, needlessley where at = case local of { Just True -> "@" ; _ -> "" } fullname = at ++ pre ++ "/" ++ name fn pre (Node (name,_) others) = Collection name $ map (fn (pre ++ "/" ++ name)) others dict :: Map.Map String UniHaskellRewrite dict = Map.fromList $ map (\ a -> (show a,a)) rewrites find :: String -> UniHaskellRewrite find name = case Map.lookup name dict of Nothing -> error $ "bad lookup for : " ++ show (name,dict) Just r -> r trees = merge' [ mkNode name' rec | name <- Map.keys dict , let (rec,name') = case name of '/':rest -> (Nothing,rest) '@':'/':rest -> (Just True,rest) -- please apply at specific local _ -> error $ "bad rewrite name (needs / or @?): " ++ name ] mkNode name rec = case span (/= '/') name of (pre,'/':post) -> Node (pre,Nothing) [mkNode post rec] (pre,[]) -> Node (pre,rec) [] merge' :: (Eq a,Ord a) => [Tree a] -> [Tree a] merge' = map (\ as -> if length as == 1 then head as else Node (rootLabel $ head as) (merge' (concatMap subForest as)) ) . groupBy (\ a b -> rootLabel a == rootLabel b) . sortBy (\ a b -> rootLabel a `compare` rootLabel b) filterDictionary :: (Subst exp) => [Dec] -> Path -> exp -> Dictionary -> Q Dictionary filterDictionary decs path exp (Dictionary fm entries) = do entries' <- fnList entries return $ Dictionary fm entries' -- keep the same finite map of trans where fnList entries = do entries1 <- mapM fn entries let entries2 = [ entry | Just entry <- entries1 ] return $ entries2 fn (Collection "hacks" _) = return $ Nothing fn (Collection "Eureka" _) = return $ Nothing -- magic markers! fn (Collection str entries) = do entries' <- fnList entries if null entries' then return $ Nothing else return $ Just $ Collection str entries' fn basic@(Basic _ _ rr _) = do b <- oraclePred (substUsing' (addThePath path) rr) decs exp if b then return $ Just basic else return $ Nothing addThePath [] = Here addThePath (x:xs) = Path x $ addThePath xs ------------------------------------------------------------------------------ -- Not really dictionary stuff showInfoInHtml :: [Tree (Path,RewriteInfo)] -> Html showInfoInHtml [] = noHtml showInfoInHtml trees = ulist << concatHtml [ li << showInfoInHtml' tree | tree <- trees ] showInfoInHtml' :: Tree (Path,RewriteInfo) -> Html showInfoInHtml' (Node (path,info) trees) = show' info +++ showInfoInHtml trees where show' :: RewriteInfo -> Html show' (RewriteInfo msg) = bold << ("applied " ++ show msg) show' (RewriteMessage msg) = italics << msg ------------------------------------------------------------------------------