packages feed

hat-2.7.0.0: tools/ADT.hs

module ADT (ADT(..),displayTree,displayTrees,trustIO,trustConstant
           ,trustModule,trustApps,foldHiddens,leaves,subADTs,detectCycles
           ,trustUnevaluated,(/==),trustMatchingFunction) where

import NodeExp    (NodeExp(..),fullEval,flatEval,(===),finalResult,isomorphicIn)
import SExp       (QName(..))
import Data.Maybe (isJust,fromJust)

data ADT = Branch [Int] NodeExp (Int -> String) [ADT]
         | Cycle [Int] [ADT]

instance Show ADT where
  show = displayTree 80 (\_ s -> s)

tag (Branch t _ _ _) = t
tag (Cycle t _) = t

instance Eq ADT where
  (Branch _ n _ _) == (Branch _ n' _ _) = n == n'
  (Cycle _ xs) == (Cycle _ xs') = xs == xs'
  _ == _ = False
  
instance Ord ADT where
  compare (Branch _ n _ _) (Branch _ n' _ _) = compare n n'
  compare (Branch _ _ _ _) (Cycle _ _) = GT
  compare (Cycle _ _) (Branch _ _ _ _) = LT
  compare (Cycle _ _) (Cycle _ _) = EQ

(/==) :: ADT -> ADT -> Bool
(/==) e1 e2 = tag e1 /= tag e2

detectCycles :: [ADT] -> [ADT]
detectCycles =
  map $ detCycles []
  where
    detCycles :: [ADT] -> ADT -> ADT
    detCycles previous x@(Branch t exp q chldr) =
      let found = findExp (flatEval fullEval exp) previous
      in case found of
           [] -> Branch t exp q $ map (detCycles (x:previous)) chldr
           d  -> Cycle t d

    findExp :: NodeExp -> [ADT] -> [ADT]
    findExp x l =
      filter ((x ===) . (flatEval fullEval) . (\(Branch _ e _ _) -> e)) l

-- | Displays an EDT using a provided formatting.
displayTree :: Int -> (NodeExp -> String -> String) -> ADT -> String
displayTree w a (Branch _ exp q ts) =
  (a exp $ q w) ++ "\n" ++ (concat $ otherQuestions (w - 2) a ts)
displayTree w a (Cycle t cs) =
  if isJust q && isJust e
    then "CYCLE!\n" ++ (a (fromJust e) $ (fromJust q) (w - 2)) 
    else "CYCLE!\n"
  where
    (q,e) = findBranch cs
    findBranch [] = (Nothing,Nothing)
    findBranch (b@(Branch _ e n _):_) = (Just n,Just e)
    findBranch (_:xs) = findBranch xs

otherQuestions :: Int -> (NodeExp -> String -> String) -> [ADT] -> [String]
otherQuestions w a adts = 
     zipWith prependTree bTrees prepends
  ++ zipWith prependTree wTree wPrepends
  where
    prepends = " | " : prepends
    wPrepends = "   " : wPrepends
    trees = map (displayTree (w - 3) a) adts
    (bTrees,wTree) = splitAt (length trees - 1) trees

prependTree text prepend = 
  case theLines of
    []     -> "Error: An empty question was produced"
    (x:xs) -> unlines (  (" +-" ++ x) : (map (prepend ++) $ xs))
  where
    theLines = lines text

displayTrees :: Int -> (NodeExp -> String -> String) -> [ADT] -> String
displayTrees w a = concatMap (displayTree w a)

foldHiddens :: [ADT] -> [ADT]
foldHiddens = trustMatchingFunction False f
              where
                f (Branch _ e@(NExpHidden _ _ _) _ _) = True
                f _ = False

trustIO :: [ADT] -> [ADT]
trustIO =
  trustMatchingFunction False f
  where
    f (Branch _ e _ _) =
      (NExpIdentifier undefined
                      (Plain "{IO}")
                      undefined) `isomorphicIn` finalResult e

trustUnevaluated :: [ADT] -> [ADT]
trustUnevaluated = trustMatchingFunction False 
                                         (\(Branch _ e _ _)
                                            -> finalResult e === NExpUneval)

trustConstant :: QName -> [ADT] -> [ADT]
trustConstant name =
  trustMatchingFunction False f
  where
    f (Branch _ (NExpConstUse _ cName _) _ _) = name == cName
    f (Branch _ (NExpConstDef _ cName _) _ _) = name == cName
    f _ = False

trustModule :: String -> [ADT] -> [ADT]
trustModule mod =
  trustMatchingFunction False f
  where
    f (Branch _ (NExpApp _ (NExpIdentifier _ (Qualified mod' _) _) _ _) _ _)
      = mod == mod'
    f (Branch _ (NExpConstUse _ (Qualified mod' _) _) _ _)
      = mod == mod'
    f (Branch _ (NExpConstDef _ (Qualified mod' _) _) _ _)
      = mod == mod'
    f (Branch _ _ _ _) = False

trustApps :: [NodeExp] -> [ADT] -> [ADT]
trustApps apps trees =
  foldr trustApp trees apps
  where
    trustApp :: NodeExp -> [ADT] -> [ADT]
    trustApp exp = trustMatchingFunction False
                                         (  (compareApps exp)
                                          . (\(Branch _ e _ _) -> e))
    
    compareApps :: NodeExp -> NodeExp -> Bool
    compareApps (NExpApp _ f as _) (NExpApp _ f' as' _) =
         fullEval f === fullEval f'
      && all id (zipWith (===) (map fullEval as) (map fullEval as'))
    compareApps (NExpConstDef n _ _) (NExpConstDef n' _ _) = n == n'
    compareApps (NExpConstUse _ _ r) (NExpConstUse _ _ r') = compareApps r r'
    compareApps x y = False


trustMatchingFunction :: Bool -> (ADT -> Bool) -> [ADT] -> [ADT]
trustMatchingFunction _ _ [] = []
trustMatchingFunction tc f (b@(Branch t e q ch):os)
  | f b       = if tc 
                  then trustMatchingFunction tc f os
                  else    trustMatchingFunction tc f ch
                       ++ trustMatchingFunction tc f os
  | otherwise =   (Branch t e q (trustMatchingFunction tc f ch))
                : trustMatchingFunction tc f os 
trustMatchingFunction tc f (c@(Cycle t xs):os) =
  (Cycle t (trustMatchingFunction tc f xs)) : (trustMatchingFunction tc f os)

subADTs :: Maybe Int -> [ADT] -> [ADT]
subADTs _ []
  = []
subADTs (Just 0) _
  = []
subADTs (Just n) (e@(Branch _ _ _ []):others)
  = e:subADTs (Just n) others
subADTs (Just n) (e@(Branch _ _ _ chldrn):others)
  = e:(subADTs (Just (n-1)) chldrn ++ subADTs (Just n) others)
subADTs Nothing (e@(Branch _ _ _ []):others)
  = e:subADTs Nothing others
subADTs Nothing (e@(Branch _ _ _ chldrn):others)
  = e:(subADTs Nothing chldrn ++ subADTs Nothing others)
subADTs x ((Cycle _ e):others)
  = subADTs x others

leaves :: ADT -> [NodeExp]
leaves (Branch _ e _ []) = [e]
leaves (Branch _ e _ chldrn) = e:(concatMap leaves chldrn)
leaves (Cycle t e) = []